diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 72b3d43..3ef92ea 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,16 +5,36 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -40,23 +60,23 @@
- {
- "keyToString": {
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "WebServerToolWindowFactoryState": "false",
- "git-widget-placeholder": "ammon/wallet-static-call",
- "last_opened_file_path": "/Users/ammonwerner/supa/supa-foundry",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "yarn",
- "settings.editor.selected.configurable": "preferences.lookFeel",
- "ts.external.directory.path": "/Users/ammonwerner/Applications/WebStorm.app/Contents/plugins/javascript-impl/jsLanguageServicesImpl/external",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
diff --git a/flat/gelato/TaskCreatorProxy.flat.sol b/flat/gelato/TaskCreatorProxy.flat.sol
new file mode 100644
index 0000000..c15f3ce
--- /dev/null
+++ b/flat/gelato/TaskCreatorProxy.flat.sol
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
+
+/**
+ * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
+ * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
+ * be specified by overriding the virtual {_implementation} function.
+ *
+ * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
+ * different contract through the {_delegate} function.
+ *
+ * The success and return data of the delegated call will be returned back to the caller of the proxy.
+ */
+abstract contract Proxy {
+ /**
+ * @dev Delegates the current call to `implementation`.
+ *
+ * This function does not return to its internal call site, it will return directly to the external caller.
+ */
+ function _delegate(address implementation) internal virtual {
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+ calldatacopy(0, 0, calldatasize())
+
+ // Call the implementation.
+ // out and outsize are 0 because we don't know the size yet.
+ let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
+
+ // Copy the returned data.
+ returndatacopy(0, 0, returndatasize())
+
+ switch result
+ // delegatecall returns 0 on error.
+ case 0 {
+ revert(0, returndatasize())
+ }
+ default {
+ return(0, returndatasize())
+ }
+ }
+ }
+
+ /**
+ * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
+ * and {_fallback} should delegate.
+ */
+ function _implementation() internal view virtual returns (address);
+
+ /**
+ * @dev Delegates the current call to the address returned by `_implementation()`.
+ *
+ * This function does not return to its internal call site, it will return directly to the external caller.
+ */
+ function _fallback() internal virtual {
+ _beforeFallback();
+ _delegate(_implementation());
+ }
+
+ /**
+ * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
+ * function in the contract matches the call data.
+ */
+ fallback() external payable virtual {
+ _fallback();
+ }
+
+ /**
+ * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
+ * is empty.
+ */
+ receive() external payable virtual {
+ _fallback();
+ }
+
+ /**
+ * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
+ * call, or as part of the Solidity `fallback` or `receive` functions.
+ *
+ * If overridden should call `super._beforeFallback()`.
+ */
+ function _beforeFallback() internal virtual {}
+}
+
+// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
+
+/**
+ * @dev Library for reading and writing primitive types to specific storage slots.
+ *
+ * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
+ * This library helps with reading and writing to such slots without the need for inline assembly.
+ *
+ * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
+ *
+ * Example usage to set ERC1967 implementation slot:
+ * ```
+ * contract ERC1967 {
+ * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
+ *
+ * function _getImplementation() internal view returns (address) {
+ * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
+ * }
+ *
+ * function _setImplementation(address newImplementation) internal {
+ * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
+ * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
+ * }
+ * }
+ * ```
+ *
+ * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
+ */
+library StorageSlot {
+ struct AddressSlot {
+ address value;
+ }
+
+ struct BooleanSlot {
+ bool value;
+ }
+
+ struct Bytes32Slot {
+ bytes32 value;
+ }
+
+ struct Uint256Slot {
+ uint256 value;
+ }
+
+ /**
+ * @dev Returns an `AddressSlot` with member `value` located at `slot`.
+ */
+ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
+ */
+ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
+ */
+ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
+ */
+ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+ function _msgSender() internal view virtual returns (address) {
+ return msg.sender;
+ }
+
+ function _msgData() internal view virtual returns (bytes calldata) {
+ return msg.data;
+ }
+}
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+ address private _owner;
+
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+ /**
+ * @dev Initializes the contract setting the deployer as the initial owner.
+ */
+ constructor() {
+ _transferOwnership(_msgSender());
+ }
+
+ /**
+ * @dev Throws if called by any account other than the owner.
+ */
+ modifier onlyOwner() {
+ _checkOwner();
+ _;
+ }
+
+ /**
+ * @dev Returns the address of the current owner.
+ */
+ function owner() public view virtual returns (address) {
+ return _owner;
+ }
+
+ /**
+ * @dev Throws if the sender is not the owner.
+ */
+ function _checkOwner() internal view virtual {
+ require(owner() == _msgSender(), "Ownable: caller is not the owner");
+ }
+
+ /**
+ * @dev Leaves the contract without owner. It will not be possible to call
+ * `onlyOwner` functions anymore. Can only be called by the current owner.
+ *
+ * NOTE: Renouncing ownership will leave the contract without an owner,
+ * thereby removing any functionality that is only available to the owner.
+ */
+ function renounceOwnership() public virtual onlyOwner {
+ _transferOwnership(address(0));
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Can only be called by the current owner.
+ */
+ function transferOwnership(address newOwner) public virtual onlyOwner {
+ require(newOwner != address(0), "Ownable: new owner is the zero address");
+ _transferOwnership(newOwner);
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Internal function without access restriction.
+ */
+ function _transferOwnership(address newOwner) internal virtual {
+ address oldOwner = _owner;
+ _owner = newOwner;
+ emit OwnershipTransferred(oldOwner, newOwner);
+ }
+}
+
+/// @title Task Creator for Supa Automations
+contract TaskCreatorProxy is Proxy, Ownable {
+
+ /**
+ * @dev Storage slot with the address of the current implementation.
+ * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
+ * validated in the constructor.
+ */
+ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
+
+ constructor() {
+ _transferOwnership(tx.origin);
+ }
+
+ function upgrade(address implementation_) external onlyOwner {
+ StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = implementation_;
+ }
+
+ function implementation() external view returns (address) {
+ return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
+ }
+
+ function _setImplementation(address newImplementation) private {
+ StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
+ }
+
+ function _implementation() internal view override returns (address) {
+ return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
+ }
+}
+
diff --git a/flat/governance/GovernanceProxy.flat.sol b/flat/governance/GovernanceProxy.flat.sol
new file mode 100644
index 0000000..adbade8
--- /dev/null
+++ b/flat/governance/GovernanceProxy.flat.sol
@@ -0,0 +1,2091 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
+
+// BEGIN STRIP
+// Used in `FsUtils.log` which is a debugging tool.
+
+library console {
+ address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
+
+ function _sendLogPayload(bytes memory payload) private view {
+ uint256 payloadLength = payload.length;
+ address consoleAddress = CONSOLE_ADDRESS;
+ /// @solidity memory-safe-assembly
+ assembly {
+ let payloadStart := add(payload, 32)
+ let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
+ }
+ }
+
+ function log() internal view {
+ _sendLogPayload(abi.encodeWithSignature("log()"));
+ }
+
+ function logInt(int p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
+ }
+
+ function logUint(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function logString(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function logBool(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function logAddress(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function logBytes(bytes memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
+ }
+
+ function logBytes1(bytes1 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
+ }
+
+ function logBytes2(bytes2 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
+ }
+
+ function logBytes3(bytes3 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
+ }
+
+ function logBytes4(bytes4 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
+ }
+
+ function logBytes5(bytes5 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
+ }
+
+ function logBytes6(bytes6 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
+ }
+
+ function logBytes7(bytes7 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
+ }
+
+ function logBytes8(bytes8 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
+ }
+
+ function logBytes9(bytes9 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
+ }
+
+ function logBytes10(bytes10 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
+ }
+
+ function logBytes11(bytes11 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
+ }
+
+ function logBytes12(bytes12 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
+ }
+
+ function logBytes13(bytes13 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
+ }
+
+ function logBytes14(bytes14 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
+ }
+
+ function logBytes15(bytes15 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
+ }
+
+ function logBytes16(bytes16 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
+ }
+
+ function logBytes17(bytes17 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
+ }
+
+ function logBytes18(bytes18 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
+ }
+
+ function logBytes19(bytes19 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
+ }
+
+ function logBytes20(bytes20 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
+ }
+
+ function logBytes21(bytes21 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
+ }
+
+ function logBytes22(bytes22 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
+ }
+
+ function logBytes23(bytes23 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
+ }
+
+ function logBytes24(bytes24 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
+ }
+
+ function logBytes25(bytes25 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
+ }
+
+ function logBytes26(bytes26 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
+ }
+
+ function logBytes27(bytes27 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
+ }
+
+ function logBytes28(bytes28 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
+ }
+
+ function logBytes29(bytes29 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
+ }
+
+ function logBytes30(bytes30 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
+ }
+
+ function logBytes31(bytes31 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
+ }
+
+ function logBytes32(bytes32 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
+ }
+
+ function log(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function log(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function log(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function log(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function log(uint p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
+ }
+
+ function log(uint p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
+ }
+
+ function log(uint p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
+ }
+
+ function log(uint p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
+ }
+
+ function log(string memory p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
+ }
+
+ function log(string memory p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
+ }
+
+ function log(string memory p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
+ }
+
+ function log(string memory p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
+ }
+
+ function log(bool p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
+ }
+
+ function log(bool p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
+ }
+
+ function log(bool p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
+ }
+
+ function log(bool p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
+ }
+
+ function log(address p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
+ }
+
+ function log(address p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
+ }
+
+ function log(address p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
+ }
+
+ function log(address p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
+ }
+
+ function log(uint p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
+ }
+
+}
+
+// END STRIP
+
+library FsUtils {
+ // BEGIN STRIP
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s) internal view {
+ console.log(s);
+ }
+
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s, int256 x) internal view {
+ console.log(s);
+ console.logInt(x);
+ }
+
+ function log(string memory s, address x) internal view {
+ console.log(s, x);
+ }
+
+ // END STRIP
+
+ function encodeToBytes32(bytes memory b) internal pure returns (bytes32) {
+ require(b.length < 32, "Byte array to long");
+ bytes32 out = bytes32(b);
+ out = (out & (~(bytes32(type(uint256).max) >> (8 * b.length)))) | bytes32(b.length);
+ return out;
+ }
+
+ function decodeFromBytes32(bytes32 b) internal pure returns (bytes memory) {
+ uint256 len = uint256(b) & 0xff;
+ bytes memory out = new bytes(len);
+ for (uint256 i = 0; i < len; i++) {
+ out[i] = b[i];
+ }
+ return out;
+ }
+
+ function nonNull(address _address) internal pure returns (address) {
+ require(_address != address(0), "Zero address");
+ return _address;
+ }
+
+ function revertBytes(bytes memory b) internal pure {
+ assembly ("memory-safe") {
+ revert(add(b, 0x20), mload(b))
+ }
+ }
+
+ // assert a condition. Assert should be used to assert an invariant that should be true
+ // logically.
+ // This is useful for readability and debugability. A failing assert is always a bug.
+ //
+ // In production builds (non-hardhat, and non-localhost deployments) this method is a noop.
+ //
+ // Use "require" to enforce requirements on data coming from outside of a contract. Ie.,
+ //
+ // ```solidity
+ // function nonNegativeX(int x) external { require(x >= 0, "non-negative"); }
+ // ```
+ //
+ // But
+ // ```solidity
+ // function nonNegativeX(int x) private { assert(x >= 0); }
+ // ```
+ //
+ // If a private function has a pre-condition that it should only be called with non-negative
+ // values it's a bug in the contract if it's called with a negative value.
+ // solhint-disable-next-line func-name-mixedcase
+ function Assert(bool cond) internal pure {
+ // BEGIN STRIP
+ assert(cond);
+ // END STRIP
+ }
+}
+
+/// @title ImmutableGovernance
+/// @dev This contract is meant to be inherited by other contracts, to make them ownable.
+contract ImmutableGovernance {
+ address public immutable immutableGovernance;
+
+ /// @notice Only governance can call this function
+ error OnlyGovernance();
+
+ modifier onlyGovernance() {
+ if (msg.sender != immutableGovernance) revert OnlyGovernance();
+ _;
+ }
+
+ constructor(address governance) {
+ // slither-disable-next-line missing-zero-check
+ immutableGovernance = FsUtils.nonNull(governance);
+ }
+}
+
+/**
+ * @title A serialized contract method call.
+ *
+ * @notice A call to a contract with no native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct CallWithoutValue {
+ address to;
+ bytes callData;
+ }
+
+/**
+ * @title A serialized contract method call, with value.
+ *
+ * @notice A call to a contract that may also have native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct Call {
+ address to;
+ bytes callData;
+ uint256 value;
+ }
+
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
+/// @notice Metadata to splice a return value into a call.
+ struct ReturnDataLink {
+ // index of the call with the return value
+ uint32 callIndex;
+ // offset of the return value in the return data
+ uint32 returnValueOffset;
+ // indicates whether the return value is static or dynamic
+ bool isStatic;
+ // offset in the callData where the return value should be spliced in
+ uint128 offset;
+ }
+
+/// @notice Specify a batch of calls to be executed in sequence,
+/// @notice with the return values of some calls being passed as arguments to later calls.
+ struct LinkedExecution {
+ Execution execution;
+ ReturnDataLink[] links;
+ }
+
+library ExecutionLib {
+ using Address for address;
+
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
+ bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
+ bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
+ "CallWithoutValue(address to,bytes callData)";
+ bytes32 constant CALLWITHOUTVALUE_TYPEHASH = keccak256(CALLWITHOUTVALUE_TYPESTRING);
+
+ /**
+ * @notice Execute a call.
+ *
+ * @param call The call to execute.
+ */
+ function executeWithoutValue(CallWithoutValue memory call) internal {
+ call.to.functionCall(call.callData);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Call memory call) internal returns (bytes memory) {
+ return call.to.functionCallWithValue(call.callData, call.value);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
+ /**
+ * @notice Execute a batch of calls.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatch(Execution[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ execute(calls[i]);
+ }
+ }
+
+ /**
+ * @notice Execute a batch of calls with value.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatchWithoutValue(CallWithoutValue[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ executeWithoutValue(calls[i]);
+ }
+ }
+
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
+ }
+
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCall(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+
+ function hashCallWithoutValue(CallWithoutValue memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALLWITHOUTVALUE_TYPEHASH, call.to, keccak256(call.callData)));
+ }
+
+ function hashCallWithoutValueArray(
+ CallWithoutValue[] memory calls
+ ) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCallWithoutValue(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+}
+
+// This is a proxy contract representing governance. This allows a fixed
+// ethereum address to be the indefinite owner of the system. This works
+// nicely with ImmutableGovernance allowing owner to be stored in contract
+// code instead of storage. Note that a governance account only has to
+// interact with the "execute" method. Proposing new governance or accepting
+// governance is done through calls to "execute", simplifying voting
+// contracts that govern this proxy.
+/// @title Supa Governance Proxy
+contract GovernanceProxy {
+ using Address for address;
+
+ /*
+ * @dev This address controls the proxy and is allowed to execute
+ * @dev contract calls from this contracts account.
+ */
+ address public governance;
+ /*
+ * @dev To avoid losing governance by accidentally transferring governance
+ * @dev to a wrong address we use a propose mechanism, where the proposed
+ * @dev governance can also execute and by this action finalize the
+ * @dev the transfer of governance. This prevents accidentally transferring
+ * @dev control to an invalid address.
+ */
+ address public proposedGovernance;
+
+ event NewGovernanceProposed(address newGovernance);
+ event GovernanceChanged(address oldGovernance, address newGovernance);
+ event BatchExecuted(CallWithoutValue[] calls);
+
+ error OnlyGovernance();
+
+ constructor(address _governance) {
+ governance = FsUtils.nonNull(_governance);
+ }
+
+ /// @notice Execute a batch of contract calls.
+ /// @param calls an array of calls.
+ function executeBatch(CallWithoutValue[] calldata calls) external {
+ if (msg.sender != governance) {
+ // If the caller is not governance we only accept if the previous
+ // governance has proposed it as the new governance account.
+ if (msg.sender != proposedGovernance) revert OnlyGovernance();
+ emit GovernanceChanged(governance, msg.sender);
+ governance = msg.sender;
+ proposedGovernance = address(0);
+ }
+ // Instead of monitoring each configuration change we opt for a
+ // simpler approach where we just emit an event for each batch of
+ // privileged calls.
+ emit BatchExecuted(calls);
+ ExecutionLib.executeBatchWithoutValue(calls);
+ }
+
+ /// @notice Propose a new account as governance account. Note that this can
+ /// only be called through the execute method above and hence only
+ /// by the current governance.
+ /// @param newGovernance address of the new governance account (or zero to revoke proposal)
+ function proposeGovernance(address newGovernance) external {
+ if (msg.sender != address(this)) revert OnlyGovernance();
+ emit NewGovernanceProposed(newGovernance);
+ proposedGovernance = newGovernance;
+ }
+}
+
diff --git a/flat/governance/OffchainEntityProxy.flat.sol b/flat/governance/OffchainEntityProxy.flat.sol
new file mode 100644
index 0000000..9ddcce0
--- /dev/null
+++ b/flat/governance/OffchainEntityProxy.flat.sol
@@ -0,0 +1,2889 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+ function _msgSender() internal view virtual returns (address) {
+ return msg.sender;
+ }
+
+ function _msgData() internal view virtual returns (bytes calldata) {
+ return msg.data;
+ }
+}
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+ address private _owner;
+
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+ /**
+ * @dev Initializes the contract setting the deployer as the initial owner.
+ */
+ constructor() {
+ _transferOwnership(_msgSender());
+ }
+
+ /**
+ * @dev Throws if called by any account other than the owner.
+ */
+ modifier onlyOwner() {
+ _checkOwner();
+ _;
+ }
+
+ /**
+ * @dev Returns the address of the current owner.
+ */
+ function owner() public view virtual returns (address) {
+ return _owner;
+ }
+
+ /**
+ * @dev Throws if the sender is not the owner.
+ */
+ function _checkOwner() internal view virtual {
+ require(owner() == _msgSender(), "Ownable: caller is not the owner");
+ }
+
+ /**
+ * @dev Leaves the contract without owner. It will not be possible to call
+ * `onlyOwner` functions anymore. Can only be called by the current owner.
+ *
+ * NOTE: Renouncing ownership will leave the contract without an owner,
+ * thereby removing any functionality that is only available to the owner.
+ */
+ function renounceOwnership() public virtual onlyOwner {
+ _transferOwnership(address(0));
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Can only be called by the current owner.
+ */
+ function transferOwnership(address newOwner) public virtual onlyOwner {
+ require(newOwner != address(0), "Ownable: new owner is the zero address");
+ _transferOwnership(newOwner);
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Internal function without access restriction.
+ */
+ function _transferOwnership(address newOwner) internal virtual {
+ address oldOwner = _owner;
+ _owner = newOwner;
+ emit OwnershipTransferred(oldOwner, newOwner);
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+ enum Rounding {
+ Down, // Toward negative infinity
+ Up, // Toward infinity
+ Zero // Toward zero
+ }
+
+ /**
+ * @dev Returns the largest of two numbers.
+ */
+ function max(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two numbers.
+ */
+ function min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two numbers. The result is rounded towards
+ * zero.
+ */
+ function average(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b) / 2 can overflow.
+ return (a & b) + (a ^ b) / 2;
+ }
+
+ /**
+ * @dev Returns the ceiling of the division of two numbers.
+ *
+ * This differs from standard division with `/` in that it rounds up instead
+ * of rounding down.
+ */
+ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b - 1) / b can overflow on addition, so we distribute.
+ return a == 0 ? 0 : (a - 1) / b + 1;
+ }
+
+ /**
+ * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+ * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+ * with further edits by Uniswap Labs also under MIT license.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator
+ ) internal pure returns (uint256 result) {
+ unchecked {
+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+ // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+ // variables such that product = prod1 * 2^256 + prod0.
+ uint256 prod0; // Least significant 256 bits of the product
+ uint256 prod1; // Most significant 256 bits of the product
+ assembly {
+ let mm := mulmod(x, y, not(0))
+ prod0 := mul(x, y)
+ prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+ }
+
+ // Handle non-overflow cases, 256 by 256 division.
+ if (prod1 == 0) {
+ return prod0 / denominator;
+ }
+
+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
+ require(denominator > prod1);
+
+ ///////////////////////////////////////////////
+ // 512 by 256 division.
+ ///////////////////////////////////////////////
+
+ // Make division exact by subtracting the remainder from [prod1 prod0].
+ uint256 remainder;
+ assembly {
+ // Compute remainder using mulmod.
+ remainder := mulmod(x, y, denominator)
+
+ // Subtract 256 bit number from 512 bit number.
+ prod1 := sub(prod1, gt(remainder, prod0))
+ prod0 := sub(prod0, remainder)
+ }
+
+ // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+ // See https://cs.stackexchange.com/q/138556/92363.
+
+ // Does not overflow because the denominator cannot be zero at this stage in the function.
+ uint256 twos = denominator & (~denominator + 1);
+ assembly {
+ // Divide denominator by twos.
+ denominator := div(denominator, twos)
+
+ // Divide [prod1 prod0] by twos.
+ prod0 := div(prod0, twos)
+
+ // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+ twos := add(div(sub(0, twos), twos), 1)
+ }
+
+ // Shift in bits from prod1 into prod0.
+ prod0 |= prod1 * twos;
+
+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+ // four bits. That is, denominator * inv = 1 mod 2^4.
+ uint256 inverse = (3 * denominator) ^ 2;
+
+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+ // in modular arithmetic, doubling the correct bits in each step.
+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+ // is no longer required.
+ result = prod0 * inverse;
+ return result;
+ }
+ }
+
+ /**
+ * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator,
+ Rounding rounding
+ ) internal pure returns (uint256) {
+ uint256 result = mulDiv(x, y, denominator);
+ if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+ result += 1;
+ }
+ return result;
+ }
+
+ /**
+ * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+ *
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+ */
+ function sqrt(uint256 a) internal pure returns (uint256) {
+ if (a == 0) {
+ return 0;
+ }
+
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+ //
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+ //
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+ //
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+ uint256 result = 1 << (log2(a) >> 1);
+
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+ // into the expected uint128 result.
+ unchecked {
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ return min(result, a / result);
+ }
+ }
+
+ /**
+ * @notice Calculates sqrt(a), following the selected rounding direction.
+ */
+ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = sqrt(a);
+ return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 2, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 128;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 64;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 32;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 16;
+ }
+ if (value >> 8 > 0) {
+ value >>= 8;
+ result += 8;
+ }
+ if (value >> 4 > 0) {
+ value >>= 4;
+ result += 4;
+ }
+ if (value >> 2 > 0) {
+ value >>= 2;
+ result += 2;
+ }
+ if (value >> 1 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log2(value);
+ return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 10, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >= 10**64) {
+ value /= 10**64;
+ result += 64;
+ }
+ if (value >= 10**32) {
+ value /= 10**32;
+ result += 32;
+ }
+ if (value >= 10**16) {
+ value /= 10**16;
+ result += 16;
+ }
+ if (value >= 10**8) {
+ value /= 10**8;
+ result += 8;
+ }
+ if (value >= 10**4) {
+ value /= 10**4;
+ result += 4;
+ }
+ if (value >= 10**2) {
+ value /= 10**2;
+ result += 2;
+ }
+ if (value >= 10**1) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log10(value);
+ return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 256, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ *
+ * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+ */
+ function log256(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 16;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 8;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 4;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 2;
+ }
+ if (value >> 8 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log256(value);
+ return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+ }
+ }
+}
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+ bytes16 private constant _SYMBOLS = "0123456789abcdef";
+ uint8 private constant _ADDRESS_LENGTH = 20;
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+ */
+ function toString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ uint256 length = Math.log10(value) + 1;
+ string memory buffer = new string(length);
+ uint256 ptr;
+ /// @solidity memory-safe-assembly
+ assembly {
+ ptr := add(buffer, add(32, length))
+ }
+ while (true) {
+ ptr--;
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+ }
+ value /= 10;
+ if (value == 0) break;
+ }
+ return buffer;
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+ */
+ function toHexString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ return toHexString(value, Math.log256(value) + 1);
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+ */
+ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+ bytes memory buffer = new bytes(2 * length + 2);
+ buffer[0] = "0";
+ buffer[1] = "x";
+ for (uint256 i = 2 * length + 1; i > 1; --i) {
+ buffer[i] = _SYMBOLS[value & 0xf];
+ value >>= 4;
+ }
+ require(value == 0, "Strings: hex length insufficient");
+ return string(buffer);
+ }
+
+ /**
+ * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+ */
+ function toHexString(address addr) internal pure returns (string memory) {
+ return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+ }
+}
+
+/**
+ * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
+ *
+ * These functions can be used to verify that a message was signed by the holder
+ * of the private keys of a given address.
+ */
+library ECDSA {
+ enum RecoverError {
+ NoError,
+ InvalidSignature,
+ InvalidSignatureLength,
+ InvalidSignatureS,
+ InvalidSignatureV // Deprecated in v4.8
+ }
+
+ function _throwError(RecoverError error) private pure {
+ if (error == RecoverError.NoError) {
+ return; // no error: do nothing
+ } else if (error == RecoverError.InvalidSignature) {
+ revert("ECDSA: invalid signature");
+ } else if (error == RecoverError.InvalidSignatureLength) {
+ revert("ECDSA: invalid signature length");
+ } else if (error == RecoverError.InvalidSignatureS) {
+ revert("ECDSA: invalid signature 's' value");
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature` or error string. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ *
+ * Documentation for signature generation:
+ * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
+ * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
+ if (signature.length == 65) {
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ // ecrecover takes the signature parameters, and the only way to get them
+ // currently is to use assembly.
+ /// @solidity memory-safe-assembly
+ assembly {
+ r := mload(add(signature, 0x20))
+ s := mload(add(signature, 0x40))
+ v := byte(0, mload(add(signature, 0x60)))
+ }
+ return tryRecover(hash, v, r, s);
+ } else {
+ return (address(0), RecoverError.InvalidSignatureLength);
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature`. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ */
+ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, signature);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
+ *
+ * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address, RecoverError) {
+ bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
+ uint8 v = uint8((uint256(vs) >> 255) + 27);
+ return tryRecover(hash, v, r, s);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
+ *
+ * _Available since v4.2._
+ */
+ function recover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, r, vs);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address, RecoverError) {
+ // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
+ // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
+ // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
+ // signatures from current libraries generate a unique signature with an s-value in the lower half order.
+ //
+ // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
+ // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
+ // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
+ // these malleable signatures as well.
+ if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
+ return (address(0), RecoverError.InvalidSignatureS);
+ }
+
+ // If the signature is valid (and not malleable), return the signer address
+ address signer = ecrecover(hash, v, r, s);
+ if (signer == address(0)) {
+ return (address(0), RecoverError.InvalidSignature);
+ }
+
+ return (signer, RecoverError.NoError);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ */
+ function recover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from a `hash`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
+ // 32 is the length in bytes of hash,
+ // enforced by the type signature above
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from `s`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Typed Data, created from a
+ * `domainSeparator` and a `structHash`. This produces hash corresponding
+ * to the one signed with the
+ * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
+ * JSON-RPC method as part of EIP-712.
+ *
+ * See {recover}.
+ */
+ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
+ }
+}
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
+ *
+ * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
+ * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
+ * they need in their contracts using a combination of `abi.encode` and `keccak256`.
+ *
+ * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
+ * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
+ * ({_hashTypedDataV4}).
+ *
+ * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
+ * the chain id to protect against replay attacks on an eventual fork of the chain.
+ *
+ * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
+ * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
+ *
+ * _Available since v3.4._
+ */
+abstract contract EIP712 {
+ /* solhint-disable var-name-mixedcase */
+ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
+ // invalidate the cached domain separator if the chain id changes.
+ bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
+ uint256 private immutable _CACHED_CHAIN_ID;
+ address private immutable _CACHED_THIS;
+
+ bytes32 private immutable _HASHED_NAME;
+ bytes32 private immutable _HASHED_VERSION;
+ bytes32 private immutable _TYPE_HASH;
+
+ /* solhint-enable var-name-mixedcase */
+
+ /**
+ * @dev Initializes the domain separator and parameter caches.
+ *
+ * The meaning of `name` and `version` is specified in
+ * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
+ *
+ * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
+ * - `version`: the current major version of the signing domain.
+ *
+ * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
+ * contract upgrade].
+ */
+ constructor(string memory name, string memory version) {
+ bytes32 hashedName = keccak256(bytes(name));
+ bytes32 hashedVersion = keccak256(bytes(version));
+ bytes32 typeHash = keccak256(
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
+ );
+ _HASHED_NAME = hashedName;
+ _HASHED_VERSION = hashedVersion;
+ _CACHED_CHAIN_ID = block.chainid;
+ _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
+ _CACHED_THIS = address(this);
+ _TYPE_HASH = typeHash;
+ }
+
+ /**
+ * @dev Returns the domain separator for the current chain.
+ */
+ function _domainSeparatorV4() internal view returns (bytes32) {
+ if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
+ return _CACHED_DOMAIN_SEPARATOR;
+ } else {
+ return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
+ }
+ }
+
+ function _buildDomainSeparator(
+ bytes32 typeHash,
+ bytes32 nameHash,
+ bytes32 versionHash
+ ) private view returns (bytes32) {
+ return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
+ }
+
+ /**
+ * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
+ * function returns the hash of the fully encoded EIP712 message for this domain.
+ *
+ * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
+ *
+ * ```solidity
+ * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
+ * keccak256("Mail(address to,string contents)"),
+ * mailTo,
+ * keccak256(bytes(mailContents))
+ * )));
+ * address signer = ECDSA.recover(digest, signature);
+ * ```
+ */
+ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
+ return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
+
+/**
+ * @title A serialized contract method call.
+ *
+ * @notice A call to a contract with no native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct CallWithoutValue {
+ address to;
+ bytes callData;
+ }
+
+/**
+ * @title A serialized contract method call, with value.
+ *
+ * @notice A call to a contract that may also have native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct Call {
+ address to;
+ bytes callData;
+ uint256 value;
+ }
+
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
+/// @notice Metadata to splice a return value into a call.
+ struct ReturnDataLink {
+ // index of the call with the return value
+ uint32 callIndex;
+ // offset of the return value in the return data
+ uint32 returnValueOffset;
+ // indicates whether the return value is static or dynamic
+ bool isStatic;
+ // offset in the callData where the return value should be spliced in
+ uint128 offset;
+ }
+
+/// @notice Specify a batch of calls to be executed in sequence,
+/// @notice with the return values of some calls being passed as arguments to later calls.
+ struct LinkedExecution {
+ Execution execution;
+ ReturnDataLink[] links;
+ }
+
+library ExecutionLib {
+ using Address for address;
+
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
+ bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
+ bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
+ "CallWithoutValue(address to,bytes callData)";
+ bytes32 constant CALLWITHOUTVALUE_TYPEHASH = keccak256(CALLWITHOUTVALUE_TYPESTRING);
+
+ /**
+ * @notice Execute a call.
+ *
+ * @param call The call to execute.
+ */
+ function executeWithoutValue(CallWithoutValue memory call) internal {
+ call.to.functionCall(call.callData);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Call memory call) internal returns (bytes memory) {
+ return call.to.functionCallWithValue(call.callData, call.value);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
+ /**
+ * @notice Execute a batch of calls.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatch(Execution[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ execute(calls[i]);
+ }
+ }
+
+ /**
+ * @notice Execute a batch of calls with value.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatchWithoutValue(CallWithoutValue[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ executeWithoutValue(calls[i]);
+ }
+ }
+
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
+ }
+
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCall(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+
+ function hashCallWithoutValue(CallWithoutValue memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALLWITHOUTVALUE_TYPEHASH, call.to, keccak256(call.callData)));
+ }
+
+ function hashCallWithoutValueArray(
+ CallWithoutValue[] memory calls
+ ) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCallWithoutValue(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+}
+
+// BEGIN STRIP
+// Used in `FsUtils.log` which is a debugging tool.
+
+library console {
+ address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
+
+ function _sendLogPayload(bytes memory payload) private view {
+ uint256 payloadLength = payload.length;
+ address consoleAddress = CONSOLE_ADDRESS;
+ /// @solidity memory-safe-assembly
+ assembly {
+ let payloadStart := add(payload, 32)
+ let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
+ }
+ }
+
+ function log() internal view {
+ _sendLogPayload(abi.encodeWithSignature("log()"));
+ }
+
+ function logInt(int p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
+ }
+
+ function logUint(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function logString(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function logBool(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function logAddress(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function logBytes(bytes memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
+ }
+
+ function logBytes1(bytes1 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
+ }
+
+ function logBytes2(bytes2 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
+ }
+
+ function logBytes3(bytes3 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
+ }
+
+ function logBytes4(bytes4 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
+ }
+
+ function logBytes5(bytes5 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
+ }
+
+ function logBytes6(bytes6 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
+ }
+
+ function logBytes7(bytes7 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
+ }
+
+ function logBytes8(bytes8 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
+ }
+
+ function logBytes9(bytes9 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
+ }
+
+ function logBytes10(bytes10 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
+ }
+
+ function logBytes11(bytes11 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
+ }
+
+ function logBytes12(bytes12 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
+ }
+
+ function logBytes13(bytes13 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
+ }
+
+ function logBytes14(bytes14 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
+ }
+
+ function logBytes15(bytes15 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
+ }
+
+ function logBytes16(bytes16 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
+ }
+
+ function logBytes17(bytes17 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
+ }
+
+ function logBytes18(bytes18 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
+ }
+
+ function logBytes19(bytes19 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
+ }
+
+ function logBytes20(bytes20 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
+ }
+
+ function logBytes21(bytes21 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
+ }
+
+ function logBytes22(bytes22 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
+ }
+
+ function logBytes23(bytes23 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
+ }
+
+ function logBytes24(bytes24 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
+ }
+
+ function logBytes25(bytes25 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
+ }
+
+ function logBytes26(bytes26 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
+ }
+
+ function logBytes27(bytes27 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
+ }
+
+ function logBytes28(bytes28 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
+ }
+
+ function logBytes29(bytes29 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
+ }
+
+ function logBytes30(bytes30 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
+ }
+
+ function logBytes31(bytes31 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
+ }
+
+ function logBytes32(bytes32 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
+ }
+
+ function log(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function log(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function log(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function log(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function log(uint p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
+ }
+
+ function log(uint p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
+ }
+
+ function log(uint p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
+ }
+
+ function log(uint p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
+ }
+
+ function log(string memory p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
+ }
+
+ function log(string memory p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
+ }
+
+ function log(string memory p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
+ }
+
+ function log(string memory p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
+ }
+
+ function log(bool p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
+ }
+
+ function log(bool p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
+ }
+
+ function log(bool p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
+ }
+
+ function log(bool p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
+ }
+
+ function log(address p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
+ }
+
+ function log(address p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
+ }
+
+ function log(address p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
+ }
+
+ function log(address p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
+ }
+
+ function log(uint p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
+ }
+
+}
+
+// END STRIP
+
+library FsUtils {
+ // BEGIN STRIP
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s) internal view {
+ console.log(s);
+ }
+
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s, int256 x) internal view {
+ console.log(s);
+ console.logInt(x);
+ }
+
+ function log(string memory s, address x) internal view {
+ console.log(s, x);
+ }
+
+ // END STRIP
+
+ function encodeToBytes32(bytes memory b) internal pure returns (bytes32) {
+ require(b.length < 32, "Byte array to long");
+ bytes32 out = bytes32(b);
+ out = (out & (~(bytes32(type(uint256).max) >> (8 * b.length)))) | bytes32(b.length);
+ return out;
+ }
+
+ function decodeFromBytes32(bytes32 b) internal pure returns (bytes memory) {
+ uint256 len = uint256(b) & 0xff;
+ bytes memory out = new bytes(len);
+ for (uint256 i = 0; i < len; i++) {
+ out[i] = b[i];
+ }
+ return out;
+ }
+
+ function nonNull(address _address) internal pure returns (address) {
+ require(_address != address(0), "Zero address");
+ return _address;
+ }
+
+ function revertBytes(bytes memory b) internal pure {
+ assembly ("memory-safe") {
+ revert(add(b, 0x20), mload(b))
+ }
+ }
+
+ // assert a condition. Assert should be used to assert an invariant that should be true
+ // logically.
+ // This is useful for readability and debugability. A failing assert is always a bug.
+ //
+ // In production builds (non-hardhat, and non-localhost deployments) this method is a noop.
+ //
+ // Use "require" to enforce requirements on data coming from outside of a contract. Ie.,
+ //
+ // ```solidity
+ // function nonNegativeX(int x) external { require(x >= 0, "non-negative"); }
+ // ```
+ //
+ // But
+ // ```solidity
+ // function nonNegativeX(int x) private { assert(x >= 0); }
+ // ```
+ //
+ // If a private function has a pre-condition that it should only be called with non-negative
+ // values it's a bug in the contract if it's called with a negative value.
+ // solhint-disable-next-line func-name-mixedcase
+ function Assert(bool cond) internal pure {
+ // BEGIN STRIP
+ assert(cond);
+ // END STRIP
+ }
+}
+
+// Signers (EOAs) are the only things that cross EVM chains as they have the same address on all chains.
+// To represent an entity cross chains therefore requires a dedicated signer. However this is cumbersome
+// to manage securely when the offchain entity is distributed (if the signer is hardware who possesses it, or
+// the security risk of sharing the private key). Instead, ideally we want a multisig smart contract
+// representing the entity but with a fixed address on all chains. We propose a simple proxy contract
+// that can be deployed to a fixed address on all chains, and can be owned by a multisig wallet. This
+// reduces the use of the key to infrequent initial setup for a new chain.
+
+// Note: we could deploy this contract with a dedicated deployer key. However this means we must guarantee
+// that deployment of this contract is always the first action on the chain for this key. Instead we
+// opt for a pattern that only needs the dedicated key to sign offchain.
+/// @title Offchain Entity Proxy
+contract OffchainEntityProxy is Ownable, EIP712 {
+ error InvalidSignature();
+
+ bytes32 private constant TAKEOWNERSHIP_TYPEHASH =
+ keccak256("TakeOwnership(address newOwner,uint256 nonce)");
+
+ bytes32 private immutable entityName;
+
+ uint256 public nonce;
+
+ // Due to offchain signer address being part of the deployment bytecode, the address at which
+ // this contract is deployed identifies the offchain signer.
+ constructor(
+ address offchainSigner,
+ string memory _entityName
+ ) EIP712("OffchainEntityProxy", "1") {
+ _transferOwnership(offchainSigner);
+ entityName = FsUtils.encodeToBytes32(bytes(_entityName));
+ }
+
+ /// @notice Take ownership of this contract.
+ /// @dev By using signature based ownership transfer, we can ensure that the signer can be
+ /// @dev purely offchain.
+ /// @param signature Signature of the owner to be.
+ function takeOwnership(bytes calldata signature) external {
+ bytes32 digest = _hashTypedDataV4(
+ keccak256(abi.encode(TAKEOWNERSHIP_TYPEHASH, msg.sender, nonce++))
+ );
+
+ address signer = ECDSA.recover(digest, signature);
+ if (signer != owner()) revert InvalidSignature();
+
+ _transferOwnership(msg.sender);
+ }
+
+ /// @notice Execute a batch of contract calls.
+ /// @dev Allow the owner to execute arbitrary calls on behalf of the entity through this proxy
+ /// @dev contract.
+ /// @param calls An array of calls to execute.
+ function executeBatch(Execution[] memory calls) external payable onlyOwner {
+ ExecutionLib.executeBatch(calls);
+ }
+
+ /// @notice Get the name of the entity.
+ /// @return The name of the entity.
+ function name() external view returns (string memory) {
+ return string(FsUtils.decodeFromBytes32(entityName));
+ }
+}
+
diff --git a/flat/supa/Liquifier.flat.sol b/flat/supa/Liquifier.flat.sol
new file mode 100644
index 0000000..dd2d200
--- /dev/null
+++ b/flat/supa/Liquifier.flat.sol
@@ -0,0 +1,3402 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+ /**
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
+ * another (`to`).
+ *
+ * Note that `value` may be zero.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 value);
+
+ /**
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+ * a call to {approve}. `value` is the new allowance.
+ */
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ /**
+ * @dev Returns the amount of tokens in existence.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns the amount of tokens owned by `account`.
+ */
+ function balanceOf(address account) external view returns (uint256);
+
+ /**
+ * @dev Moves `amount` tokens from the caller's account to `to`.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Returns the remaining number of tokens that `spender` will be
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
+ * zero by default.
+ *
+ * This value changes when {approve} or {transferFrom} are called.
+ */
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
+ * that someone may use both the old and the new allowance by unfortunate
+ * transaction ordering. One possible solution to mitigate this race
+ * condition is to first reduce the spender's allowance to 0 and set the
+ * desired value afterwards:
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Moves `amount` tokens from `from` to `to` using the
+ * allowance mechanism. `amount` is then deducted from the caller's
+ * allowance.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+pragma abicoder v2;
+
+/// @title Callback for IUniswapV3PoolActions#swap
+/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
+interface IUniswapV3SwapCallback {
+ /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
+ /// @dev In the implementation you must pay the pool tokens owed for the swap.
+ /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
+ /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
+ /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
+ /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
+ /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
+ /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
+ /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
+ function uniswapV3SwapCallback(
+ int256 amount0Delta,
+ int256 amount1Delta,
+ bytes calldata data
+ ) external;
+}
+
+/// @title Router token swapping functionality
+/// @notice Functions for swapping tokens via Uniswap V3
+interface ISwapRouter is IUniswapV3SwapCallback {
+ struct ExactInputSingleParams {
+ address tokenIn;
+ address tokenOut;
+ uint24 fee;
+ address recipient;
+ uint256 deadline;
+ uint256 amountIn;
+ uint256 amountOutMinimum;
+ uint160 sqrtPriceLimitX96;
+ }
+
+ /// @notice Swaps `amountIn` of one token for as much as possible of another token
+ /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
+ /// @return amountOut The amount of the received token
+ function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
+
+ struct ExactInputParams {
+ bytes path;
+ address recipient;
+ uint256 deadline;
+ uint256 amountIn;
+ uint256 amountOutMinimum;
+ }
+
+ /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
+ /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
+ /// @return amountOut The amount of the received token
+ function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
+
+ struct ExactOutputSingleParams {
+ address tokenIn;
+ address tokenOut;
+ uint24 fee;
+ address recipient;
+ uint256 deadline;
+ uint256 amountOut;
+ uint256 amountInMaximum;
+ uint160 sqrtPriceLimitX96;
+ }
+
+ /// @notice Swaps as little as possible of one token for `amountOut` of another token
+ /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
+ /// @return amountIn The amount of the input token
+ function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
+
+ struct ExactOutputParams {
+ bytes path;
+ address recipient;
+ uint256 deadline;
+ uint256 amountOut;
+ uint256 amountInMaximum;
+ }
+
+ /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
+ /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
+ /// @return amountIn The amount of the input token
+ function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
+
+/**
+ * @title A serialized contract method call.
+ *
+ * @notice A call to a contract with no native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct CallWithoutValue {
+ address to;
+ bytes callData;
+ }
+
+/**
+ * @title A serialized contract method call, with value.
+ *
+ * @notice A call to a contract that may also have native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct Call {
+ address to;
+ bytes callData;
+ uint256 value;
+ }
+
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
+/// @notice Metadata to splice a return value into a call.
+ struct ReturnDataLink {
+ // index of the call with the return value
+ uint32 callIndex;
+ // offset of the return value in the return data
+ uint32 returnValueOffset;
+ // indicates whether the return value is static or dynamic
+ bool isStatic;
+ // offset in the callData where the return value should be spliced in
+ uint128 offset;
+ }
+
+/// @notice Specify a batch of calls to be executed in sequence,
+/// @notice with the return values of some calls being passed as arguments to later calls.
+ struct LinkedExecution {
+ Execution execution;
+ ReturnDataLink[] links;
+ }
+
+library ExecutionLib {
+ using Address for address;
+
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
+ bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
+ bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
+ "CallWithoutValue(address to,bytes callData)";
+ bytes32 constant CALLWITHOUTVALUE_TYPEHASH = keccak256(CALLWITHOUTVALUE_TYPESTRING);
+
+ /**
+ * @notice Execute a call.
+ *
+ * @param call The call to execute.
+ */
+ function executeWithoutValue(CallWithoutValue memory call) internal {
+ call.to.functionCall(call.callData);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Call memory call) internal returns (bytes memory) {
+ return call.to.functionCallWithValue(call.callData, call.value);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
+ /**
+ * @notice Execute a batch of calls.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatch(Execution[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ execute(calls[i]);
+ }
+ }
+
+ /**
+ * @notice Execute a batch of calls with value.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatchWithoutValue(CallWithoutValue[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ executeWithoutValue(calls[i]);
+ }
+ }
+
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
+ }
+
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCall(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+
+ function hashCallWithoutValue(CallWithoutValue memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALLWITHOUTVALUE_TYPEHASH, call.to, keccak256(call.callData)));
+ }
+
+ function hashCallWithoutValueArray(
+ CallWithoutValue[] memory calls
+ ) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCallWithoutValue(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+}
+
+/// @title ERC20 value oracle interface
+interface IERC20ValueOracle {
+ /// @notice Emitted when risk factors are set
+ /// @param collateralFactor Collateral factor
+ /// @param borrowFactor Borrow factor
+ event RiskFactorsSet(int256 indexed collateralFactor, int256 indexed borrowFactor);
+
+ function collateralFactor() external view returns (int256 collateralFactor);
+
+ function borrowFactor() external view returns (int256 borrowFactor);
+
+ function calcValue(int256 balance) external view returns (int256 value, int256 riskAdjustedValue);
+
+ function getValues()
+ external
+ view
+ returns (int256 value, int256 collateralAdjustedValue, int256 borrowAdjustedValue);
+}
+
+/// @title NFT Value Oracle Interface
+interface INFTValueOracle {
+ function calcValue(
+ uint256 tokenId
+ ) external view returns (int256 value, int256 riskAdjustedValue);
+}
+
+type ERC20Share is int256;
+
+struct NFTTokenData {
+ uint240 tokenId; // 240 LSB of the tokenId of the NFT
+ uint16 walletIdx; // index in wallet NFT array
+ address approvedSpender; // approved spender for ERC721
+}
+
+struct ERC20Pool {
+ int256 tokens;
+ int256 shares;
+}
+
+struct ERC20Info {
+ address erc20Contract;
+ IERC20ValueOracle valueOracle;
+ ERC20Pool collateral;
+ ERC20Pool debt;
+ uint256 baseRate;
+ uint256 slope1;
+ uint256 slope2;
+ uint256 targetUtilization;
+ uint256 timestamp;
+}
+
+struct ERC721Info {
+ address erc721Contract;
+ INFTValueOracle valueOracle;
+}
+
+struct ContractData {
+ uint16 idx;
+ ContractKind kind; // 0 invalid, 1 ERC20, 2 ERC721
+}
+
+enum ContractKind {
+ Invalid,
+ ERC20,
+ ERC721
+}
+
+interface ISupaERC20 is IERC20 {
+ function mint(address account, uint256 amount) external;
+
+ function burn(address account, uint256 amount) external;
+}
+
+interface ISupaConfig {
+ struct Config {
+ address treasuryWallet; // The address of the treasury safe
+ uint256 treasuryInterestFraction; // Fraction of interest to send to treasury
+ uint256 maxSolvencyCheckGasCost;
+ int256 liqFraction; // Fraction for the user
+ int256 fractionalReserveLeverage; // Ratio of debt to reserves
+ }
+
+ struct TokenStorageConfig {
+ uint256 maxTokenStorage;
+ uint256 erc20Multiplier;
+ uint256 erc721Multiplier;
+ }
+
+ struct NFTData {
+ address erc721;
+ uint256 tokenId;
+ }
+
+ /// @notice Emitted when the implementation of a wallet is upgraded
+ /// @param wallet The address of the wallet
+ /// @param version The new implementation version
+ event WalletImplementationUpgraded(address indexed wallet, string indexed version, address implementation);
+
+ /// @notice Emitted when the ownership of a wallet is proposed to be transferred
+ /// @param wallet The address of the wallet
+ /// @param newOwner The address of the new owner
+ event WalletOwnershipTransferProposed(address indexed wallet, address indexed newOwner);
+
+ /// @notice Emitted when the ownership of a wallet is transferred
+ /// @param wallet The address of the wallet
+ /// @param newOwner The address of the new owner
+ event WalletOwnershipTransferred(address indexed wallet, address indexed newOwner);
+
+ /// @notice Emitted when a new ERC20 is added to the protocol
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param erc20 The address of the ERC20 contract
+ /// @param name The name of the ERC20
+ /// @param symbol The symbol of the ERC20
+ /// @param decimals The decimals of the ERC20
+ /// @param valueOracle The address of the value oracle for the ERC20
+ /// @param baseRate The interest rate at 0% utilization
+ /// @param slope1 The interest rate slope at 0% to target utilization
+ /// @param slope2 The interest rate slope at target utilization to 100% utilization
+ /// @param targetUtilization The target utilization for the ERC20
+ event ERC20Added(
+ uint16 erc20Idx,
+ address erc20,
+ string name,
+ string symbol,
+ uint8 decimals,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ );
+
+ /// @notice Emitted when a new ERC721 is added to the protocol
+ /// @param erc721Idx The index of the ERC721 in the protocol
+ /// @param erc721Contract The address of the ERC721 contract
+ /// @param valueOracleAddress The address of the value oracle for the ERC721
+ event ERC721Added(uint256 indexed erc721Idx, address indexed erc721Contract, address valueOracleAddress);
+
+ /// @notice Emitted when the config is set
+ /// @param config The new config
+ event ConfigSet(Config config);
+
+ /// @notice Emitted when the token storage config is set
+ /// @param tokenStorageConfig The new token storage config
+ event TokenStorageConfigSet(TokenStorageConfig tokenStorageConfig);
+
+ /// @notice Emitted when the version manager address is set
+ /// @param versionManager The version manager address
+ event VersionManagerSet(address indexed versionManager);
+
+ /// @notice Emitted when ERC20 Data is set
+ /// @param erc20 The address of the erc20 token
+ /// @param erc20Idx The index of the erc20 token
+ /// @param valueOracle The new value oracle
+ /// @param baseRate The new base interest rate
+ /// @param slope1 The new slope1
+ /// @param slope2 The new slope2
+ /// @param targetUtilization The new target utilization
+ event ERC20DataSet(
+ address indexed erc20,
+ uint16 indexed erc20Idx,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ );
+
+ /// @notice Emitted when a wallet is created
+ /// @param wallet The address of the wallet
+ /// @param owner The address of the owner
+ event WalletCreated(address wallet, address owner);
+
+ /// @notice upgrades the version of walletLogic contract for the `wallet`
+ /// @param version The new target version of walletLogic contract
+ function upgradeWalletImplementation(string calldata version) external;
+
+ /// @notice Transfers ownership of `msg.sender` to the `newOwner`
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param newOwner The new owner of the wallet
+ function transferWalletOwnership(address newOwner) external;
+
+ /// @notice Proposes the ownership transfer of `wallet` to the `newOwner`
+ /// @dev The ownership transfer must be executed by the `newOwner` to complete the transfer
+ /// @dev emits `WalletOwnershipTransferProposed` event
+ /// @param newOwner The new owner of the `wallet`
+ function proposeTransferWalletOwnership(address newOwner) external;
+
+ /// @notice Executes the ownership transfer of `wallet` to the `newOwner`
+ /// @dev The caller must be the `newOwner` and the `newOwner` must be the proposed new owner
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param wallet The address of the wallet
+ function executeTransferWalletOwnership(address wallet) external;
+
+ /// @notice add a new ERC20 to be used inside Supa
+ /// @dev For governance only.
+ /// @param erc20Contract The address of ERC20 to add
+ /// @param name The name of the ERC20. E.g. "Wrapped ETH"
+ /// @param symbol The symbol of the ERC20. E.g. "WETH"
+ /// @param decimals Decimals of the ERC20. E.g. 18 for WETH and 6 for USDC
+ /// @param valueOracle The address of the Value Oracle. Probably Uniswap one
+ /// @param baseRate The interest rate when utilization is 0
+ /// @param slope1 The interest rate slope when utilization is less than the targetUtilization
+ /// @param slope2 The interest rate slope when utilization is more than the targetUtilization
+ /// @param targetUtilization The target utilization for the asset
+ /// @return the index of the added ERC20 in the erc20Infos array
+ function addERC20Info(
+ address erc20Contract,
+ string calldata name,
+ string calldata symbol,
+ uint8 decimals,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ ) external returns (uint16);
+
+ /// @notice Add a new ERC721 to be used inside Supa.
+ /// @dev For governance only.
+ /// @param erc721Contract The address of the ERC721 to be added
+ /// @param valueOracleAddress The address of the Uniswap Oracle to get the price of a token
+ function addERC721Info(address erc721Contract, address valueOracleAddress) external;
+
+ /// @notice Updates the config of Supa
+ /// @dev for governance only.
+ /// @param _config the Config of ISupaConfig. A struct with Supa parameters
+ function setConfig(Config calldata _config) external;
+
+ /// @notice Updates the configuration setttings for credit account token storage
+ /// @dev for governance only.
+ /// @param _tokenStorageConfig the TokenStorageconfig of ISupaConfig
+ function setTokenStorageConfig(TokenStorageConfig calldata _tokenStorageConfig) external;
+
+ /// @notice Set the address of Version Manager contract
+ /// @dev for governance only.
+ /// @param _versionManager The address of the Version Manager contract to be set
+ function setVersionManager(address _versionManager) external;
+
+ /// @notice Updates some of ERC20 config parameters
+ /// @dev for governance only.
+ /// @param erc20 The address of ERC20 contract for which Supa config parameters should be updated
+ /// @param valueOracle The address of the erc20 value oracle
+ /// @param baseRate The interest rate when utilization is 0
+ /// @param slope1 The interest rate slope when utilization is less than the targetUtilization
+ /// @param slope2 The interest rate slope when utilization is more than the targetUtilization
+ /// @param targetUtilization The target utilization for the asset
+ function setERC20Data(
+ address erc20,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ ) external;
+
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @return wallet The address of the created wallet
+ function createWallet() external returns (address wallet);
+
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @param nonce The nonce to be used for the wallet creation (must be greater than 1B)
+ /// @return wallet The address of the created wallet
+ function createWallet(uint256 nonce) external returns (address wallet);
+
+ /// @notice Pause the contract
+ function pause() external;
+
+ /// @notice Unpause the contract
+ function unpause() external;
+
+ /// @notice Returns the amount of `erc20` tokens on creditAccount of wallet
+ /// @param walletAddr The address of the wallet for which creditAccount the amount of `erc20` should
+ /// be calculated
+ /// @param erc20 The address of ERC20 which balance on creditAccount of `wallet` should be calculated
+ /// @return the amount of `erc20` on the creditAccount of `wallet`
+ function getCreditAccountERC20(address walletAddr, IERC20 erc20) external view returns (int256);
+
+ /// @notice returns the NFTs on creditAccount of `wallet`
+ /// @param wallet The address of wallet which creditAccount NFTs should be returned
+ /// @return The array of NFT deposited on the creditAccount of `wallet`
+ function getCreditAccountERC721(address wallet) external view returns (NFTData[] memory);
+
+ /// @notice returns the amount of NFTs in creditAccount of `wallet`
+ /// @param wallet The address of the wallet that owns the creditAccount
+ /// @return The amount of NFTs in the creditAccount of `wallet`
+ function getCreditAccountERC721Counter(address wallet) external view returns (uint256);
+}
+
+interface ISupaCore {
+ struct Approval {
+ address ercContract; // ERC20/ERC721 contract
+ uint256 amountOrTokenId; // amount or tokenId
+ }
+
+ /// @notice Emitted when ERC20 tokens are transferred between credit accounts
+ /// @param erc20 The address of the ERC20 token
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param from The address of the sender
+ /// @param to The address of the receiver
+ /// @param value The amount of tokens transferred
+ event ERC20Transfer(address indexed erc20, uint16 erc20Idx, address indexed from, address indexed to, int256 value);
+
+ /// @notice Emitted when erc20 tokens are deposited or withdrawn from a credit account
+ /// @param erc20 The address of the ERC20 token
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param to The address of the wallet
+ /// @param amount The amount of tokens deposited or withdrawn
+ event ERC20BalanceChanged(address indexed erc20, uint16 erc20Idx, address indexed to, int256 amount);
+
+ /// @notice Emitted when a ERC721 is transferred between credit accounts
+ /// @param nftId The nftId of the ERC721 token
+ /// @param from The address of the sender
+ /// @param to The address of the receiver
+ event ERC721Transferred(uint256 indexed nftId, address indexed from, address indexed to);
+
+ /// @notice Emitted when an ERC721 token is deposited to a credit account
+ /// @param erc721 The address of the ERC721 token
+ /// @param to The address of the wallet
+ /// @param tokenId The id of the token deposited
+ event ERC721Deposited(address indexed erc721, address indexed to, uint256 indexed tokenId);
+
+ /// @notice Emitted when an ERC721 token is withdrawn from a credit account
+ /// @param erc721 The address of the ERC721 token
+ /// @param from The address of the wallet
+ /// @param tokenId The id of the token withdrawn
+ event ERC721Withdrawn(address indexed erc721, address indexed from, uint256 indexed tokenId);
+
+ /// @dev Emitted when `owner` approves `spender` to spend `value` tokens on their behalf.
+ /// @param erc20 The ERC20 token to approve
+ /// @param owner The address of the token owner
+ /// @param spender The address of the spender
+ /// @param value The amount of tokens to approve
+ event ERC20Approval(
+ address indexed erc20, uint16 erc20Idx, address indexed owner, address indexed spender, uint256 value
+ );
+
+ /// @dev Emitted when `owner` enables `approved` to manage the `tokenId` token on collection `collection`.
+ /// @param collection The address of the ERC721 collection
+ /// @param owner The address of the token owner
+ /// @param approved The address of the approved operator
+ /// @param tokenId The ID of the approved token
+ event ERC721Approval(address indexed collection, address indexed owner, address indexed approved, uint256 tokenId);
+
+ /// @dev Emitted when an ERC721 token is received
+ /// @param wallet The address of the wallet receiving the token
+ /// @param erc721 The address of the ERC721 token
+ /// @param tokenId The id of the token received
+ event ERC721Received(address indexed wallet, address indexed erc721, uint256 indexed tokenId);
+
+ /// @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its erc20s.
+ /// @param collection The address of the collection
+ /// @param owner The address of the owner
+ /// @param operator The address of the operator
+ /// @param approved True if the operator is approved, false to revoke approval
+ event ApprovalForAll(address indexed collection, address indexed owner, address indexed operator, bool approved);
+
+ /// @dev Emitted when an operator is added to a wallet
+ /// @param wallet The address of the wallet
+ /// @param operator The address of the operator
+ event OperatorAdded(address indexed wallet, address indexed operator);
+
+ /// @dev Emitted when an operator is removed from a wallet
+ /// @param wallet The address of the wallet
+ /// @param operator The address of the operator
+ event OperatorRemoved(address indexed wallet, address indexed operator);
+
+ /// @notice Emitted when a wallet is liquidated
+ /// @param wallet The address of the liquidated wallet
+ /// @param liquidator The address of the liquidator
+ event WalletLiquidated(address indexed wallet, address indexed liquidator, int256 collateral, int256 debt);
+
+ /// @notice top up the creditAccount owned by wallet `to` with `amount` of `erc20`
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param to Address of the wallet that creditAccount should be top up
+ /// @param amount The amount of `erc20` to be sent
+ function depositERC20ForWallet(address erc20, address to, uint256 amount) external;
+
+ /// @notice deposit `amount` of `erc20` to creditAccount from wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param amount The amount of `erc20` to be transferred
+ function depositERC20(IERC20 erc20, uint256 amount) external;
+
+ /// @notice deposit `amount` of `erc20` from creditAccount to wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param amount The amount of `erc20` to be transferred
+ function withdrawERC20(IERC20 erc20, uint256 amount) external;
+
+ /// @notice deposit all `erc20s` from wallet to creditAccount
+ /// @param erc20s Array of addresses of ERC20 to be transferred
+ function depositFull(IERC20[] calldata erc20s) external;
+
+ /// @notice withdraw all `erc20s` from creditAccount to wallet
+ /// @param erc20s Array of addresses of ERC20 to be transferred
+ function withdrawFull(IERC20[] calldata erc20s) external;
+
+ /// @notice deposit ERC721 `erc721Contract` token `tokenId` from wallet to creditAccount
+ /// @dev the part when we track the ownership of deposit NFT to a specific creditAccount is in
+ /// `onERC721Received` function of this contract
+ /// @param erc721Contract The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ function depositERC721(address erc721Contract, uint256 tokenId) external;
+
+ /// @notice deposit ERC721 `erc721Contract` token `tokenId` from wallet to creditAccount
+ /// @dev the part when we track the ownership of deposit NFT to a specific creditAccount is in
+ /// `onERC721Received` function of this contract
+ /// @param erc721Contract The address of the ERC721 contract that the token belongs to
+ /// @param to The wallet address for which the NFT will be deposited
+ /// @param tokenId The id of the token to be transferred
+ function depositERC721ForWallet(address erc721Contract, address to, uint256 tokenId) external;
+
+ /// @notice withdraw ERC721 `nftContract` token `tokenId` from creditAccount to wallet
+ /// @param erc721 The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ function withdrawERC721(address erc721, uint256 tokenId) external;
+
+ /// @notice transfer `amount` of `erc20` from creditAccount of caller wallet to creditAccount of `to` wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param to wallet address, whose creditAccount is the transfer target
+ /// @param amount The amount of `erc20` to be transferred
+ function transferERC20(IERC20 erc20, address to, uint256 amount) external;
+
+ /// @notice transfer NFT `erc721` token `tokenId` from creditAccount of caller wallet to creditAccount of
+ /// `to` wallet
+ /// @param erc721 The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ /// @param to wallet address, whose creditAccount is the transfer target
+ function transferERC721(address erc721, uint256 tokenId, address to) external;
+
+ /// @notice Transfer ERC20 tokens from creditAccount to another creditAccount
+ /// @dev Note: Allowance must be set with approveERC20
+ /// @param erc20 The index of the ERC20 token in erc20Infos array
+ /// @param from The address of the wallet to transfer from
+ /// @param to The address of the wallet to transfer to
+ /// @param amount The amount of tokens to transfer
+ /// @return true, when the transfer has been successfully finished without been reverted
+ function transferFromERC20(address erc20, address from, address to, uint256 amount) external returns (bool);
+
+ /// @notice Transfer ERC721 tokens from creditAccount to another creditAccount
+ /// @param collection The address of the ERC721 token
+ /// @param from The address of the wallet to transfer from
+ /// @param to The address of the wallet to transfer to
+ /// @param tokenId The id of the token to transfer
+ function transferFromERC721(address collection, address from, address to, uint256 tokenId) external;
+
+ /// @notice Liquidate an undercollateralized position
+ /// @dev if creditAccount of `wallet` has more debt then collateral then this function will
+ /// transfer all debt and collateral ERC20s and ERC721 from creditAccount of `wallet` to creditAccount of
+ /// caller. Considering that market price of collateral is higher then market price of debt,
+ /// a friction of that difference would be sent back to liquidated creditAccount in Supa base currency.
+ /// More specific - "some fraction" is `liqFraction` parameter of Supa.
+ /// Considering that call to this function would create debt on caller (debt is less then
+ /// gains, yet still), consider using `liquify` instead, that would liquidate and use
+ /// obtained assets to cover all created debt
+ /// If creditAccount of `wallet` has less debt then collateral then the transaction will be reverted
+ /// @param wallet The address of wallet whose creditAccount to be liquidate
+ function liquidate(address wallet) external;
+
+ /// @notice Approve an array of tokens and then call `onApprovalReceived` on msg.sender
+ /// @param approvals An array of ERC20 tokens with amounts, or ERC721 contracts with tokenIds
+ /// @param spender The address of the spender
+ /// @param data Additional data with no specified format, sent in call to `spender`
+ function approveAndCall(Approval[] calldata approvals, address spender, bytes calldata data) external;
+
+ /// @notice Add an operator for wallet
+ /// @param operator The address of the operator to add
+ /// @dev Operator can execute batch of transactions on behalf of wallet owner
+ function addOperator(address operator) external;
+
+ /// @notice Remove an operator for wallet
+ /// @param operator The address of the operator to remove
+ /// @dev Operator can execute batch of transactions on behalf of wallet owner
+ function removeOperator(address operator) external;
+
+ /// @notice Used to migrate wallet to this Supa contract
+ function migrateWallet(address wallet, address owner, address implementation) external;
+
+ /// @notice Execute a batch of calls
+ /// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
+ /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
+ /// and Supa reserve/debt must be sufficient
+ /// @param calls An array of transaction calls
+ function executeBatch(Execution[] memory calls) external;
+
+ /// @notice Returns the approved address for a token, or zero if no address set
+ /// @param collection The address of the ERC721 token
+ /// @param tokenId The id of the token to query
+ /// @return The wallet address that is allowed to transfer the ERC721 token
+ function getApproved(address collection, uint256 tokenId) external view returns (address);
+
+ /// @notice returns the collateral, debt and total value of `walletAddress`.
+ /// @dev Notice that both collateral and debt has some coefficients on the actual amount of deposit
+ /// and loan assets! E.g.
+ /// for a deposit of 1 ETH the collateral would be equivalent to like 0.8 ETH, and
+ /// for a loan of 1 ETH the debt would be equivalent to like 1.2 ETH.
+ /// At the same time, totalValue is the unmodified difference between deposits and loans.
+ /// @param walletAddress The address of wallet whose collateral, debt and total value would be returned
+ /// @return totalValue The difference between equivalents of deposit and loan assets
+ /// @return collateral The sum of deposited assets multiplied by their collateral factors
+ /// @return debt The sum of borrowed assets multiplied by their borrow factors
+ function getRiskAdjustedPositionValues(address walletAddress)
+ external
+ view
+ returns (int256 totalValue, int256 collateral, int256 debt);
+
+ /// @notice Returns if '_spender' is an operator of '_owner'
+ /// @param _owner The address of the owner
+ /// @param _spender The address of the spender
+ /// @return True if the spender is an operator of the owner, false otherwise
+ function isOperator(address _owner, address _spender) external view returns (bool);
+
+ /// @notice Returns the remaining amount of tokens that `spender` will be allowed to spend on
+ /// behalf of `owner` through {transferFrom}
+ /// @dev This value changes when {approve} or {transferFrom} are called
+ /// @param erc20 The address of the ERC20 to be checked
+ /// @param _owner The wallet address whose `erc20` are allowed to be transferred by `spender`
+ /// @param spender The wallet address who is allowed to spend `erc20` of `_owner`
+ /// @return the remaining amount of tokens that `spender` will be allowed to spend on
+ /// behalf of `owner` through {transferFrom}
+ function allowance(address erc20, address _owner, address spender) external view returns (uint256);
+
+ /// @notice Compute the interest rate of `underlying`
+ /// @param erc20Idx The underlying asset
+ /// @return The interest rate of `erc20Idx`
+ function computeInterestRate(uint16 erc20Idx) external view returns (int96);
+
+ /// @notice provides the specific version of walletLogic contract that is associated with `wallet`
+ /// @param wallet Address of wallet whose walletLogic contract should be returned
+ /// @return the address of the walletLogic contract that is associated with the `wallet`
+ function getImplementation(address wallet) external view returns (address);
+
+ /// @notice provides the owner of `wallet`. Owner of the wallet is the address who created the wallet
+ /// @param wallet The address of wallet whose owner should be returned
+ /// @return the owner address of the `wallet`. Owner is the one who created the `wallet`
+ function getWalletOwner(address wallet) external view returns (address);
+
+ /// @notice Checks if the account's positions are overcollateralized
+ /// @dev checks the eventual state of `executeBatch` function execution:
+ /// * `wallet` must have collateral >= debt
+ /// * Supa must have sufficient balance of deposits and loans for each ERC20 token
+ /// @dev when called by the end of `executeBatch`, isSolvent checks the potential target state
+ /// of Supa. Calling this function separately would check current state of Supa, that is always
+ /// solvable, and so the return value would always be `true`, unless the `wallet` is liquidatable
+ /// @param wallet The address of a wallet who performed the `executeBatch`
+ /// @return Whether the position is solvent.
+ function isSolvent(address wallet) external view returns (bool);
+}
+
+interface ISupa is ISupaCore, ISupaConfig {}
+
+// BEGIN STRIP
+// Used in `FsUtils.log` which is a debugging tool.
+
+library console {
+ address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
+
+ function _sendLogPayload(bytes memory payload) private view {
+ uint256 payloadLength = payload.length;
+ address consoleAddress = CONSOLE_ADDRESS;
+ /// @solidity memory-safe-assembly
+ assembly {
+ let payloadStart := add(payload, 32)
+ let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
+ }
+ }
+
+ function log() internal view {
+ _sendLogPayload(abi.encodeWithSignature("log()"));
+ }
+
+ function logInt(int p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
+ }
+
+ function logUint(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function logString(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function logBool(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function logAddress(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function logBytes(bytes memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
+ }
+
+ function logBytes1(bytes1 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
+ }
+
+ function logBytes2(bytes2 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
+ }
+
+ function logBytes3(bytes3 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
+ }
+
+ function logBytes4(bytes4 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
+ }
+
+ function logBytes5(bytes5 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
+ }
+
+ function logBytes6(bytes6 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
+ }
+
+ function logBytes7(bytes7 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
+ }
+
+ function logBytes8(bytes8 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
+ }
+
+ function logBytes9(bytes9 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
+ }
+
+ function logBytes10(bytes10 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
+ }
+
+ function logBytes11(bytes11 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
+ }
+
+ function logBytes12(bytes12 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
+ }
+
+ function logBytes13(bytes13 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
+ }
+
+ function logBytes14(bytes14 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
+ }
+
+ function logBytes15(bytes15 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
+ }
+
+ function logBytes16(bytes16 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
+ }
+
+ function logBytes17(bytes17 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
+ }
+
+ function logBytes18(bytes18 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
+ }
+
+ function logBytes19(bytes19 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
+ }
+
+ function logBytes20(bytes20 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
+ }
+
+ function logBytes21(bytes21 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
+ }
+
+ function logBytes22(bytes22 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
+ }
+
+ function logBytes23(bytes23 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
+ }
+
+ function logBytes24(bytes24 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
+ }
+
+ function logBytes25(bytes25 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
+ }
+
+ function logBytes26(bytes26 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
+ }
+
+ function logBytes27(bytes27 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
+ }
+
+ function logBytes28(bytes28 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
+ }
+
+ function logBytes29(bytes29 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
+ }
+
+ function logBytes30(bytes30 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
+ }
+
+ function logBytes31(bytes31 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
+ }
+
+ function logBytes32(bytes32 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
+ }
+
+ function log(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function log(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function log(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function log(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function log(uint p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
+ }
+
+ function log(uint p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
+ }
+
+ function log(uint p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
+ }
+
+ function log(uint p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
+ }
+
+ function log(string memory p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
+ }
+
+ function log(string memory p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
+ }
+
+ function log(string memory p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
+ }
+
+ function log(string memory p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
+ }
+
+ function log(bool p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
+ }
+
+ function log(bool p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
+ }
+
+ function log(bool p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
+ }
+
+ function log(bool p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
+ }
+
+ function log(address p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
+ }
+
+ function log(address p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
+ }
+
+ function log(address p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
+ }
+
+ function log(address p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
+ }
+
+ function log(uint p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
+ }
+
+}
+
+// END STRIP
+
+library FsUtils {
+ // BEGIN STRIP
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s) internal view {
+ console.log(s);
+ }
+
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s, int256 x) internal view {
+ console.log(s);
+ console.logInt(x);
+ }
+
+ function log(string memory s, address x) internal view {
+ console.log(s, x);
+ }
+
+ // END STRIP
+
+ function encodeToBytes32(bytes memory b) internal pure returns (bytes32) {
+ require(b.length < 32, "Byte array to long");
+ bytes32 out = bytes32(b);
+ out = (out & (~(bytes32(type(uint256).max) >> (8 * b.length)))) | bytes32(b.length);
+ return out;
+ }
+
+ function decodeFromBytes32(bytes32 b) internal pure returns (bytes memory) {
+ uint256 len = uint256(b) & 0xff;
+ bytes memory out = new bytes(len);
+ for (uint256 i = 0; i < len; i++) {
+ out[i] = b[i];
+ }
+ return out;
+ }
+
+ function nonNull(address _address) internal pure returns (address) {
+ require(_address != address(0), "Zero address");
+ return _address;
+ }
+
+ function revertBytes(bytes memory b) internal pure {
+ assembly ("memory-safe") {
+ revert(add(b, 0x20), mload(b))
+ }
+ }
+
+ // assert a condition. Assert should be used to assert an invariant that should be true
+ // logically.
+ // This is useful for readability and debugability. A failing assert is always a bug.
+ //
+ // In production builds (non-hardhat, and non-localhost deployments) this method is a noop.
+ //
+ // Use "require" to enforce requirements on data coming from outside of a contract. Ie.,
+ //
+ // ```solidity
+ // function nonNegativeX(int x) external { require(x >= 0, "non-negative"); }
+ // ```
+ //
+ // But
+ // ```solidity
+ // function nonNegativeX(int x) private { assert(x >= 0); }
+ // ```
+ //
+ // If a private function has a pre-condition that it should only be called with non-negative
+ // values it's a bug in the contract if it's called with a negative value.
+ // solhint-disable-next-line func-name-mixedcase
+ function Assert(bool cond) internal pure {
+ // BEGIN STRIP
+ assert(cond);
+ // END STRIP
+ }
+}
+
+/// @title Errors
+/// @notice Library containing all custom errors the protocol may revert with.
+library Errors {
+ /*//////////////////////////////////////////////////////////////////////////
+ GENERICS
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The address cannot be the zero address
+ error AddressZero();
+ /// @notice The signature is invalid
+ error InvalidSignature();
+ /// @notice Data does not match the expected format
+ error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
+ /// @notice Nonce has already been used
+ error NonceAlreadyUsed();
+ /// @notice Deadline has expired
+ error DeadlineExpired();
+ /// @notice Only Supa can call this function
+ error OnlySupa();
+ /// @notice Only the owner or operator can call this function
+ error NotOwnerOrOperator();
+ /// @notice Only the owner can call this function
+ error OnlyOwner();
+ /// @notice Only this address can call this function
+ error OnlyThisAddress();
+ /// @notice Transfer failed
+ error TransferFailed();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC20
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC721
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The receiving address is not a contract
+ error ReceiverNotContract();
+ /// @notice The receiver does not implement the required interface
+ error ReceiverNoImplementation();
+ /// @notice The receiver did not return the correct value - transaction failed
+ error WrongDataReturned();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ORACLES
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Borrow factor must be greater than zero
+ error InvalidBorrowFactor();
+/// @notice Chainlink price oracle must return a valid price (>0)
+ error InvalidPrice();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ SUPA
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Sender is not approved to spend wallet erc20
+ error NotApprovedOrOwner();
+ /// @notice Sender is not the owner of the wallet;
+ /// @param sender The address of the sender
+ /// @param owner The address of the owner
+ error NotOwner(address sender, address owner);
+ /// @notice Transfer amount exceeds allowance
+ error InsufficientAllowance();
+ /// @notice Cannot approve self as spender
+ error SelfApproval();
+ /// @notice Asset is not an NFT
+ error NotNFT();
+ /// @notice NFT must be owned the the user or user's wallet
+ error NotNFTOwner();
+ /// @notice Operation leaves wallet insolvent
+ error Insolvent();
+ /// @notice Thrown if a wallet accumulates too many assets
+ error SolvencyCheckTooExpensive();
+ /// @notice Cannot withdraw debt
+ error CannotWithdrawDebt();
+ /// @notice Wallet is not liquidatable
+ error NotLiquidatable();
+ /// @notice There are insufficient reserves in the protocol for the debt
+ error InsufficientReserves();
+ /// @notice This operation would add too many tokens to the credit account
+ error TokenStorageExceeded();
+ /// @notice The address is not a registered ERC20
+ error NotERC20();
+ /// @notice `newOwner` is not the proposed new owner
+ /// @param proposedOwner The address of the proposed new owner
+ /// @param newOwner The address of the attempted new owner
+ error InvalidNewOwner(address proposedOwner, address newOwner);
+ /// @notice Only wallet can call this function
+ error OnlyWallet();
+ /// @notice Recipient is not a valid wallet
+ error WalletNonExistent();
+ /// @notice Asset is not registered
+ /// @param token The unregistered asset
+ error NotRegistered(address token);
+ /// @notice Thrown when the function is unimplemented
+ error NotImplemented();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ VERSION MANAGER
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The implementation must be a contract
+ error InvalidImplementation();
+ /// @notice The version is deprecated
+ error DeprecatedVersion();
+ /// @notice The bug level is too high
+ error BugLevelTooHigh();
+ /// @notice Recommended Version does not exist
+ error NoRecommendedVersion();
+ /// @notice version is not registered
+ error VersionNotRegistered();
+ /// @notice Specified status is out of range
+ error InvalidStatus();
+ /// @notice Specified bug level is out of range
+ error InvalidBugLevel();
+ /// @notice version name cannot be the empty string
+ error InvalidVersionName();
+ /// @notice version is deprecated or has a bug
+ error InvalidVersion();
+ /// @notice version is already registered
+ error VersionAlreadyRegistered();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ TRANSFER AND CALL 2
+ //////////////////////////////////////////////////////////////////////////*/
+
+ error TransfersUnsorted();
+
+ error EthDoesntMatchWethTransfer();
+
+ error UnauthorizedOperator(address operator, address from);
+
+ error ExpiredPermit();
+}
+
+/// @title the state part of the WalletLogic. A parent to all contracts that form wallet
+/// @dev the contract is abstract because it is not expected to be used separately from wallet
+abstract contract WalletState {
+ modifier onlyOwner() {
+ require(msg.sender == supa.getWalletOwner(address(this)), "WalletState: only this");
+ _;
+ }
+
+ /// @dev Supa instance to be used by all other wallet contracts
+ ISupa public supa;
+
+ /// @param _supa - address of a deployed Supa contract
+ constructor(address _supa) {
+ // slither-disable-next-line missing-zero-check
+ supa = ISupa(FsUtils.nonNull(_supa));
+ }
+
+ /// @notice Point the wallet to a new Supa contract
+ /// @dev This function is only callable by the wallet itself
+ /// @param _supa - address of a deployed Supa contract
+ function updateSupa(address _supa) external onlyOwner {
+ // 1. Get the current wallet details
+ // 1a. Get the wallet owner
+ address currentOwner = supa.getWalletOwner(address(this));
+ // 1b. Get the current implementation
+ address implementation = supa.getImplementation(address(this));
+
+ // 2. Update the supa implementation
+ if (_supa == address(0) || _supa == address(supa)) {
+ revert Errors.AddressZero();
+ }
+ supa = ISupa(_supa);
+
+ // 3. Call the new supa to update the wallet owner
+ supa.migrateWallet(address(this), currentOwner, implementation);
+ }
+}
+
+// All this file is taken from @uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol
+// Commented out the code that is not compatible with owr OpenZeppelin version.
+// So the rest may be used to create an interface for a deployed instance of this contract
+
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+pragma abicoder v2;
+
+//import '@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol';
+//import '@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol';
+
+//import './IPoolInitializer.sol';
+//import './IERC721Permit.sol';
+//import './IPeripheryPayments.sol';
+//import './IPeripheryImmutableState.sol';
+//import '../libraries/PoolAddress.sol';
+
+/// @title Non-fungible token for positions
+/// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred
+/// and authorized.
+//is
+//IPoolInitializer,
+//IPeripheryPayments,
+//IPeripheryImmutableState,
+//IERC721Metadata,
+//IERC721Enumerable,
+//IERC721Permit
+interface INonfungiblePositionManager {
+ /// @notice Emitted when liquidity is increased for a position NFT
+ /// @dev Also emitted when a token is minted
+ /// @param tokenId The ID of the token for which liquidity was increased
+ /// @param liquidity The amount by which liquidity for the NFT position was increased
+ /// @param amount0 The amount of token0 that was paid for the increase in liquidity
+ /// @param amount1 The amount of token1 that was paid for the increase in liquidity
+ event IncreaseLiquidity(
+ uint256 indexed tokenId,
+ uint128 liquidity,
+ uint256 amount0,
+ uint256 amount1
+ );
+ /// @notice Emitted when liquidity is decreased for a position NFT
+ /// @param tokenId The ID of the token for which liquidity was decreased
+ /// @param liquidity The amount by which liquidity for the NFT position was decreased
+ /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity
+ /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity
+ event DecreaseLiquidity(
+ uint256 indexed tokenId,
+ uint128 liquidity,
+ uint256 amount0,
+ uint256 amount1
+ );
+ /// @notice Emitted when tokens are collected for a position NFT
+ /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
+ /// @param tokenId The ID of the token for which underlying tokens were collected
+ /// @param recipient The address of the account that received the collected tokens
+ /// @param amount0 The amount of token0 owed to the position that was collected
+ /// @param amount1 The amount of token1 owed to the position that was collected
+ event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1);
+
+ /// @notice Returns the position information associated with a given token ID.
+ /// @dev Throws if the token ID is not valid.
+ /// @param tokenId The ID of the token that represents the position
+ /// @return nonce The nonce for permits
+ /// @return operator The address that is approved for spending
+ /// @return token0 The address of the token0 for a specific pool
+ /// @return token1 The address of the token1 for a specific pool
+ /// @return fee The fee associated with the pool
+ /// @return tickLower The lower end of the tick range for the position
+ /// @return tickUpper The higher end of the tick range for the position
+ /// @return liquidity The liquidity of the position
+ /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
+ /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
+ /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
+ /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
+ function positions(
+ uint256 tokenId
+ )
+ external
+ view
+ returns (
+ uint96 nonce,
+ address operator,
+ address token0,
+ address token1,
+ uint24 fee,
+ int24 tickLower,
+ int24 tickUpper,
+ uint128 liquidity,
+ uint256 feeGrowthInside0LastX128,
+ uint256 feeGrowthInside1LastX128,
+ uint128 tokensOwed0,
+ uint128 tokensOwed1
+ );
+
+ struct MintParams {
+ address token0;
+ address token1;
+ uint24 fee;
+ int24 tickLower;
+ int24 tickUpper;
+ uint256 amount0Desired;
+ uint256 amount1Desired;
+ uint256 amount0Min;
+ uint256 amount1Min;
+ address recipient;
+ uint256 deadline;
+ }
+
+ /// @notice Creates a new position wrapped in a NFT
+ /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
+ /// a method does not exist, i.e. the pool is assumed to be initialized.
+ /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
+ /// @return tokenId The ID of the token that represents the minted position
+ /// @return liquidity The amount of liquidity for this position
+ /// @return amount0 The amount of token0
+ /// @return amount1 The amount of token1
+ function mint(
+ MintParams calldata params
+ )
+ external
+ payable
+ returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
+
+ struct IncreaseLiquidityParams {
+ uint256 tokenId;
+ uint256 amount0Desired;
+ uint256 amount1Desired;
+ uint256 amount0Min;
+ uint256 amount1Min;
+ uint256 deadline;
+ }
+
+ /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
+ /// @param params tokenId The ID of the token for which liquidity is being increased,
+ /// amount0Desired The desired amount of token0 to be spent,
+ /// amount1Desired The desired amount of token1 to be spent,
+ /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
+ /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
+ /// deadline The time by which the transaction must be included to effect the change
+ /// @return liquidity The new liquidity amount as a result of the increase
+ /// @return amount0 The amount of token0 to acheive resulting liquidity
+ /// @return amount1 The amount of token1 to acheive resulting liquidity
+ function increaseLiquidity(
+ IncreaseLiquidityParams calldata params
+ ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1);
+
+ struct DecreaseLiquidityParams {
+ uint256 tokenId;
+ uint128 liquidity;
+ uint256 amount0Min;
+ uint256 amount1Min;
+ uint256 deadline;
+ }
+
+ /// @notice Decreases the amount of liquidity in a position and accounts it to the position
+ /// @param params tokenId The ID of the token for which liquidity is being decreased,
+ /// amount The amount by which liquidity will be decreased,
+ /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
+ /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
+ /// deadline The time by which the transaction must be included to effect the change
+ /// @return amount0 The amount of token0 accounted to the position's tokens owed
+ /// @return amount1 The amount of token1 accounted to the position's tokens owed
+ function decreaseLiquidity(
+ DecreaseLiquidityParams calldata params
+ ) external payable returns (uint256 amount0, uint256 amount1);
+
+ struct CollectParams {
+ uint256 tokenId;
+ address recipient;
+ uint128 amount0Max;
+ uint128 amount1Max;
+ }
+
+ /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
+ /// @param params tokenId The ID of the NFT for which tokens are being collected,
+ /// recipient The account that should receive the tokens,
+ /// amount0Max The maximum amount of token0 to collect,
+ /// amount1Max The maximum amount of token1 to collect
+ /// @return amount0 The amount of fees collected in token0
+ /// @return amount1 The amount of fees collected in token1
+ function collect(
+ CollectParams calldata params
+ ) external payable returns (uint256 amount0, uint256 amount1);
+
+ /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens
+ /// must be collected first.
+ /// @param tokenId The ID of the token that is being burned
+ function burn(uint256 tokenId) external payable;
+}
+
+struct SqrtPricePriceRangeX96 {
+ uint160 minSell;
+ uint160 maxBuy;
+}
+
+/// @title Logic for liquify functionality of wallet
+/// @dev It is designed to be an extension for walletLogic contract.
+/// Functionally, it's a part of the walletLogic contract, but has been extracted into a separate
+/// contract for better code structuring. This is why the contract is declared as abstract
+/// The only function it exports is `liquify`. The rest are private function that are parts of
+/// `liquify`
+abstract contract Liquifier is WalletState {
+ /// @notice Only this address or the Wallet owner can call this function
+ error OnlySelfOrOwner();
+
+ modifier selfOrWalletOwner() {
+ if (msg.sender != address(this) && msg.sender != supa.getWalletOwner(address(this))) {
+ revert OnlySelfOrOwner();
+ }
+ _;
+ }
+
+ /// @notice Advanced version of liquidate function. Potentially unwanted side-affect of
+ /// liquidation is a debt on the liquidator. So liquify would liquidate and then re-balance
+ /// obtained assets to have no debt. This is the algorithm:
+ /// * liquidate creditAccount of target `wallet`
+ /// * terminate all obtained ERC721s (NFTs)
+ /// * buy/sell `erc20s` for `numeraire` so the balance of `wallet` on that ERC20s matches the
+ /// debt of `wallet` on it's creditAccount. E.g.:
+ /// - for 1 WETH of debt on creditAccount and 3 WETH on the balance of wallet - sell 2 WETH
+ /// - for 3 WETH of debt on creditAccount and 1 WETH on the balance of wallet - buy 2 WETH
+ /// - for no debt on creditAccount and 1 WETH on the balance of wallet - sell 2 WETH
+ /// - for 1 WETH of debt on creditAccount and no WETH on the balance of dSave - buy 1 WETH
+ /// * deposit `erc20s` and `numeraire` to cover debts
+ ///
+ /// !! IMPORTANT: because this function executes quite a lot of logic on top of Supa.liquidate(),
+ /// there is a risk that for liquidatable position with a long list of NFTs it will run out
+ /// of gas. As for now, it's up to liquidator to estimate if specific position is liquifiable,
+ /// or Supa.liquidate() need to be used (with further assets re-balancing in other transactions)
+ /// @dev notes on erc20s: the reason for erc20s been a call parameter, and not been calculated
+ /// inside of liquify, is reducing gas costs
+ /// erc20s should NOT include numeraire. Otherwise, the transaction would be reverted with an
+ /// error from uniswap router
+ /// It's the responsibility of caller to provide the correct list of erc20s. Assets
+ /// re-balancing would be performed only by this list of tokens and numeraire.
+ /// * if erc20s misses a token that liquidatable have debt on - the debt on this erc20 would
+ /// persist on liquidator's creditAccount as-is
+ /// * if erc20s misses a token that liquidatable have collateral on - the token would persist
+ /// on liquidator's creditAccount. It may result in generating debt in numeraire on liquidator
+ /// creditAccount by the end of liquify (because the token would not be soled for numeraire,
+ /// there may not be enough numeraire to buy tokens to cover debts, and so they will be
+ /// bought in debt)
+ /// * if erc20s misses a token that would be obtained as the result of NFT termination - same
+ /// as previous, except of the token to be persisted on wallet instead of creditAccount of
+ /// liquidator
+ /// Because no buy/sell would be done for prices from outside of the erc20sAllowedPriceRanges,
+ /// too narrow range may result in not having enough of some ERC20 to cover the debt. So the
+ /// eventual state would still include some debt
+ /// @param wallet - the address of a wallet to liquidate
+ /// @param swapRouter - the address of a Uniswap swap router to be used to buy/sell erc20s
+ /// @param nftManager - the address of a Uniswap NonFungibleTokenManager to be used to terminate
+ /// ERC721 (NFTs)
+ /// @param numeraire - the address of an ERC20 to be used to convert to and from erc20s. The
+ /// liquidation reward would be in this token
+ /// @param erc20s - the list of ERC20 that liquidated has debt, collateral or that would be
+ /// obtained from termination of any ERC721 that he owns. Except of numeraire, that should
+ /// never be included in erc20s array
+ /// @param erc20sAllowedPriceRanges - the list of root squares of allowed prices in Q96 for
+ /// `erc20s` swaps on Uniswap in `numeraire`. This is the protection against sandwich-attack -
+ /// if the price would be lower/higher for sell/buy
+ /// It's up to liquidator to decide what range is acceptable. +/- 1% of price before liquify
+ /// call seems to be reasonable
+ /// Zero minSell/maxBuy value for a specific ERC20 would disable the corresponding check
+ /// Uniswap docs - https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps
+ /// It doesn't explained in Uniswap docs, but this is how it actually works:
+ /// * if the price for each token would be below the specified limit
+ /// then full amount would be converted and no error would be thrown
+ /// * if at least some amount of tokens can be bought by the price that is below the limit
+ /// then only that amount of tokens would be bought and no error would be thrown
+ /// * if no tokens can be bought by the price below the limit
+ /// then error would be thrown with message "SPL"
+ function liquify(
+ address wallet,
+ address swapRouter,
+ address nftManager,
+ address numeraire,
+ IERC20[] calldata erc20s,
+ SqrtPricePriceRangeX96[] calldata erc20sAllowedPriceRanges
+ ) external selfOrWalletOwner {
+ if (msg.sender != address(this)) {
+ /* prettier-ignore */ // list of liquify arguments as-is
+ return callOverBatchExecute(wallet, swapRouter, nftManager, numeraire, erc20s, erc20sAllowedPriceRanges);
+ }
+
+ supa.liquidate(wallet);
+
+ (
+ IERC20[] memory erc20sCollateral,
+ uint256[] memory erc20sDebtAmounts
+ ) = analyseCreditAccountStructure(erc20s, numeraire);
+
+ supa.withdrawFull(erc20sCollateral);
+ terminateERC721s(nftManager);
+
+ (
+ uint256[] memory erc20sToSellAmounts,
+ uint256[] memory erc20sToBuyAmounts
+ ) = calcSellAndBuyERC20Amounts(erc20s, erc20sDebtAmounts);
+ sellERC20s(swapRouter, erc20s, erc20sToSellAmounts, numeraire, erc20sAllowedPriceRanges);
+ buyERC20s(swapRouter, erc20s, erc20sToBuyAmounts, numeraire, erc20sAllowedPriceRanges);
+
+ deposit(erc20s, numeraire);
+ }
+
+ function callOverBatchExecute(
+ address wallet,
+ address swapRouter,
+ address nftManager,
+ address numeraire,
+ IERC20[] calldata erc20s,
+ SqrtPricePriceRangeX96[] calldata erc20sAllowedPriceRanges
+ ) private {
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(this),
+ callData: abi.encodeWithSelector(
+ this.liquify.selector,
+ wallet,
+ swapRouter,
+ nftManager,
+ numeraire,
+ erc20s,
+ erc20sAllowedPriceRanges
+ ),
+ value: 0
+ });
+ supa.executeBatch(calls);
+ }
+
+ /// @param nftManager - passed as-is from liquify function. The address of a Uniswap
+ /// NonFungibleTokenManager to be used to terminate ERC721 (NFTs)
+ function terminateERC721s(address nftManager) private {
+ INonfungiblePositionManager manager = INonfungiblePositionManager(nftManager);
+ ISupa.NFTData[] memory nfts = supa.getCreditAccountERC721(address(this));
+ for (uint256 i = 0; i < nfts.length; i++) {
+ ISupa.NFTData memory nft = nfts[i];
+ supa.withdrawERC721(nft.erc721, nft.tokenId);
+ (, , , , , , , uint128 nftLiquidity, , , , ) = manager.positions(nft.tokenId);
+ manager.decreaseLiquidity(
+ INonfungiblePositionManager.DecreaseLiquidityParams({
+ tokenId: nft.tokenId,
+ liquidity: nftLiquidity,
+ amount0Min: 0,
+ amount1Min: 0,
+ deadline: type(uint256).max
+ })
+ );
+ manager.collect(
+ INonfungiblePositionManager.CollectParams({
+ tokenId: nft.tokenId,
+ recipient: address(this),
+ amount0Max: type(uint128).max,
+ amount1Max: type(uint128).max
+ })
+ );
+
+ manager.burn(nft.tokenId);
+ }
+ }
+
+ function analyseCreditAccountStructure(
+ IERC20[] calldata erc20s,
+ address numeraire
+ ) private view returns (IERC20[] memory erc20sCollateral, uint256[] memory erc20sDebtAmounts) {
+ uint256 numOfERC20sCollateral = 0;
+ int256[] memory balances = new int256[](erc20s.length);
+
+ for (uint256 i = 0; i < erc20s.length; i++) {
+ int256 balance = supa.getCreditAccountERC20(address(this), erc20s[i]);
+ if (balance > 0) {
+ numOfERC20sCollateral++;
+ balances[i] = balance;
+ } else if (balance < 0) {
+ balances[i] = balance;
+ }
+ }
+
+ int256 creditAccountNumeraireBalance = supa.getCreditAccountERC20(
+ address(this),
+ IERC20(numeraire)
+ );
+ if (creditAccountNumeraireBalance > 0) {
+ numOfERC20sCollateral++;
+ }
+
+ erc20sCollateral = new IERC20[](numOfERC20sCollateral);
+ erc20sDebtAmounts = new uint256[](erc20s.length);
+
+ if (creditAccountNumeraireBalance > 0) {
+ erc20sCollateral[0] = IERC20(numeraire);
+ }
+
+ for (uint256 i = 0; i < erc20s.length; i++) {
+ if (balances[i] > 0) {
+ erc20sCollateral[--numOfERC20sCollateral] = erc20s[i];
+ } else if (balances[i] < 0) {
+ erc20sDebtAmounts[i] = uint256(-balances[i]);
+ }
+ }
+ }
+
+ function calcSellAndBuyERC20Amounts(
+ IERC20[] calldata erc20s,
+ uint256[] memory erc20sDebtAmounts
+ )
+ private
+ view
+ returns (uint256[] memory erc20ToSellAmounts, uint256[] memory erc20ToBuyAmounts)
+ {
+ erc20ToBuyAmounts = new uint256[](erc20s.length);
+ erc20ToSellAmounts = new uint256[](erc20s.length);
+
+ for (uint256 i = 0; i < erc20s.length; i++) {
+ uint256 balance = erc20s[i].balanceOf(address(this));
+ if (balance > erc20sDebtAmounts[i]) {
+ erc20ToSellAmounts[i] = balance - erc20sDebtAmounts[i];
+ } else if (balance < erc20sDebtAmounts[i]) {
+ erc20ToBuyAmounts[i] = erc20sDebtAmounts[i] - balance;
+ }
+ }
+ }
+
+ function sellERC20s(
+ address swapRouter,
+ IERC20[] memory erc20sToSell,
+ uint256[] memory amountsToSell,
+ address erc20ToSellFor,
+ SqrtPricePriceRangeX96[] calldata erc20sAllowedPriceRanges
+ ) private {
+ for (uint256 i = 0; i < erc20sToSell.length; i++) {
+ if (amountsToSell[i] == 0) continue;
+
+ ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
+ tokenIn: address(erc20sToSell[i]),
+ tokenOut: erc20ToSellFor,
+ fee: 500,
+ recipient: address(this),
+ deadline: type(uint256).max, // ignore - total transaction type should be limited at Supa level
+ amountIn: amountsToSell[i],
+ amountOutMinimum: 0,
+ // see comments on `erc20sAllowedPriceRanges` parameter of `liquify`
+ sqrtPriceLimitX96: erc20sAllowedPriceRanges[i].minSell
+ });
+
+ try ISwapRouter(swapRouter).exactInputSingle(params) {} catch Error(
+ string memory reason
+ ) {
+ // "SPL" means that proposed sell price is too low. If so - silently skip conversion.
+ // For any other error - revert
+ // Consider emitting or logging
+ // Consider ignoring some other errors if it's appropriate
+ // Consider replacing with `Strings.equal` on OpenZeppelin next release
+ if (keccak256(abi.encodePacked(reason)) != keccak256(abi.encodePacked("SPL"))) {
+ revert(reason);
+ }
+ }
+ }
+ }
+
+ function buyERC20s(
+ address swapRouter,
+ IERC20[] memory erc20sToBuy,
+ uint256[] memory amountsToBuy,
+ address erc20ToBuyFor,
+ SqrtPricePriceRangeX96[] calldata erc20sAllowedPriceRanges
+ ) private {
+ for (uint256 i = 0; i < erc20sToBuy.length; i++) {
+ if (amountsToBuy[i] == 0) continue;
+
+ ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter
+ .ExactOutputSingleParams({
+ tokenIn: erc20ToBuyFor,
+ tokenOut: address(erc20sToBuy[i]),
+ fee: 500,
+ recipient: address(this),
+ deadline: type(uint256).max, // ignore - total transaction type should be limited at Supa level
+ amountOut: amountsToBuy[i],
+ amountInMaximum: type(uint256).max,
+ // see comments on `erc20sAllowedPriceRanges` parameter of `liquify`
+ sqrtPriceLimitX96: erc20sAllowedPriceRanges[i].maxBuy
+ });
+
+ try ISwapRouter(swapRouter).exactOutputSingle(params) {} catch Error(
+ string memory reason
+ ) {
+ // "SPL" means that proposed buy price is too high. If so - silently skip conversion.
+ // For any other error - revert
+ // Consider emitting or logging
+ // Consider ignoring some other errors if it's appropriate
+ // Consider replacing with `Strings.equal` on OpenZeppelin next release
+ if (keccak256(abi.encodePacked(reason)) != keccak256(abi.encodePacked("SPL"))) {
+ revert(reason);
+ }
+ }
+ }
+ }
+
+ function deposit(IERC20[] memory erc20s, address numeraire) private {
+ supa.depositFull(erc20s);
+ IERC20[] memory numeraireArray = new IERC20[](1);
+ numeraireArray[0] = IERC20(numeraire);
+ supa.depositFull(numeraireArray);
+ }
+}
+
diff --git a/flat/supa/Supa.flat.sol b/flat/supa/Supa.flat.sol
index 29d72ea..f330e1e 100644
--- a/flat/supa/Supa.flat.sol
+++ b/flat/supa/Supa.flat.sol
@@ -1761,6 +1761,12 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
uint256 value;
}
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
/// @notice Metadata to splice a return value into a call.
struct ReturnDataLink {
// index of the call with the return value
@@ -1775,15 +1781,15 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
/// @notice Specify a batch of calls to be executed in sequence,
/// @notice with the return values of some calls being passed as arguments to later calls.
- struct LinkedCall {
- Call call;
+ struct LinkedExecution {
+ Execution execution;
ReturnDataLink[] links;
}
-library CallLib {
+library ExecutionLib {
using Address for address;
- bytes internal constant CALL_TYPESTRING = "Call(address to,bytes callData,uint256 value)";
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
"CallWithoutValue(address to,bytes callData)";
@@ -1807,12 +1813,32 @@ library CallLib {
return call.to.functionCallWithValue(call.callData, call.value);
}
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
/**
* @notice Execute a batch of calls.
*
* @param calls The calls to execute.
*/
- function executeBatch(Call[] memory calls) internal {
+ function executeBatch(Execution[] memory calls) internal {
for (uint256 i = 0; i < calls.length; i++) {
execute(calls[i]);
}
@@ -1829,11 +1855,11 @@ library CallLib {
}
}
- function hashCall(Call memory call) internal pure returns (bytes32) {
- return keccak256(abi.encode(CALL_TYPEHASH, call.to, keccak256(call.callData), call.value));
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
}
- function hashCallArray(Call[] memory calls) internal pure returns (bytes32) {
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
hashes[i] = hashCall(calls[i]);
@@ -2033,6 +2059,11 @@ interface ISupaConfig {
/// @param version The new target version of walletLogic contract
function upgradeWalletImplementation(string calldata version) external;
+ /// @notice Transfers ownership of `msg.sender` to the `newOwner`
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param newOwner The new owner of the wallet
+ function transferWalletOwnership(address newOwner) external;
+
/// @notice Proposes the ownership transfer of `wallet` to the `newOwner`
/// @dev The ownership transfer must be executed by the `newOwner` to complete the transfer
/// @dev emits `WalletOwnershipTransferProposed` event
@@ -2111,6 +2142,11 @@ interface ISupaConfig {
/// @return wallet The address of the created wallet
function createWallet() external returns (address wallet);
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @param nonce The nonce to be used for the wallet creation (must be greater than 1B)
+ /// @return wallet The address of the created wallet
+ function createWallet(uint256 nonce) external returns (address wallet);
+
/// @notice Pause the contract
function pause() external;
@@ -2328,7 +2364,7 @@ interface ISupaCore {
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
/// and Supa reserve/debt must be sufficient
/// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external;
+ function executeBatch(Execution[] memory calls) external;
/// @notice Returns the approved address for a token, or zero if no address set
/// @param collection The address of the ERC721 token
@@ -4604,6 +4640,8 @@ library Errors {
error InvalidSignature();
/// @notice Data does not match the expected format
error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
/// @notice Nonce has already been used
error NonceAlreadyUsed();
/// @notice Deadline has expired
@@ -4951,12 +4989,12 @@ contract WalletProxy is WalletState, Proxy {
receive() external payable override {}
// Allow Supa to make arbitrary calls in lieu of this wallet
- function executeBatch(Call[] calldata calls) external payable ifSupa {
+ function executeBatch(Execution[] calldata calls) external payable ifSupa {
// Function is payable to allow for ETH transfers to the logic
// contract, but supa should never send eth (supa contract should
// never contain eth / other than what's self-destructed into it)
FsUtils.Assert(msg.value == 0);
- CallLib.executeBatch(calls);
+ ExecutionLib.executeBatch(calls);
}
// The implementation of the delegate is controlled by Supa
@@ -4969,7 +5007,7 @@ interface IERC1363SpenderExtended {
function onApprovalReceived(
address owner,
uint256 value,
- Call calldata call
+ Execution calldata call
) external returns (bytes4);
}
@@ -5245,7 +5283,7 @@ contract Supa is SupaState, ISupaCore, IERC721Receiver, Proxy {
}
/// @inheritdoc ISupaCore
- function executeBatch(Call[] memory calls) external override onlyWallet whenNotPaused {
+ function executeBatch(Execution[] memory calls) external onlyWallet whenNotPaused {
WalletProxy(payable(msg.sender)).executeBatch(calls);
if (!isSolvent(msg.sender)) {
revert Errors.Insolvent();
@@ -5474,7 +5512,11 @@ contract Supa is SupaState, ISupaCore, IERC721Receiver, Proxy {
revert Errors.ReceiverNotContract();
}
- Call memory call = Call({to: target, callData: data, value: msg.value});
+ Execution memory call = Execution({
+ target: target,
+ callData: data,
+ value: msg.value
+ });
try IERC1363SpenderExtended(spender).onApprovalReceived(msg.sender, amount, call) returns (bytes4 retval) {
return retval == IERC1363SpenderExtended.onApprovalReceived.selector;
diff --git a/flat/supa/SupaConfig.flat.sol b/flat/supa/SupaConfig.flat.sol
index 12f6caf..9ab0a68 100644
--- a/flat/supa/SupaConfig.flat.sol
+++ b/flat/supa/SupaConfig.flat.sol
@@ -1778,6 +1778,12 @@ abstract contract Pausable is Context {
uint256 value;
}
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
/// @notice Metadata to splice a return value into a call.
struct ReturnDataLink {
// index of the call with the return value
@@ -1792,15 +1798,15 @@ abstract contract Pausable is Context {
/// @notice Specify a batch of calls to be executed in sequence,
/// @notice with the return values of some calls being passed as arguments to later calls.
- struct LinkedCall {
- Call call;
+ struct LinkedExecution {
+ Execution execution;
ReturnDataLink[] links;
}
-library CallLib {
+library ExecutionLib {
using Address for address;
- bytes internal constant CALL_TYPESTRING = "Call(address to,bytes callData,uint256 value)";
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
"CallWithoutValue(address to,bytes callData)";
@@ -1824,12 +1830,32 @@ library CallLib {
return call.to.functionCallWithValue(call.callData, call.value);
}
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
/**
* @notice Execute a batch of calls.
*
* @param calls The calls to execute.
*/
- function executeBatch(Call[] memory calls) internal {
+ function executeBatch(Execution[] memory calls) internal {
for (uint256 i = 0; i < calls.length; i++) {
execute(calls[i]);
}
@@ -1846,11 +1872,11 @@ library CallLib {
}
}
- function hashCall(Call memory call) internal pure returns (bytes32) {
- return keccak256(abi.encode(CALL_TYPEHASH, call.to, keccak256(call.callData), call.value));
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
}
- function hashCallArray(Call[] memory calls) internal pure returns (bytes32) {
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
hashes[i] = hashCall(calls[i]);
@@ -2050,6 +2076,11 @@ interface ISupaConfig {
/// @param version The new target version of walletLogic contract
function upgradeWalletImplementation(string calldata version) external;
+ /// @notice Transfers ownership of `msg.sender` to the `newOwner`
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param newOwner The new owner of the wallet
+ function transferWalletOwnership(address newOwner) external;
+
/// @notice Proposes the ownership transfer of `wallet` to the `newOwner`
/// @dev The ownership transfer must be executed by the `newOwner` to complete the transfer
/// @dev emits `WalletOwnershipTransferProposed` event
@@ -2128,6 +2159,11 @@ interface ISupaConfig {
/// @return wallet The address of the created wallet
function createWallet() external returns (address wallet);
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @param nonce The nonce to be used for the wallet creation (must be greater than 1B)
+ /// @return wallet The address of the created wallet
+ function createWallet(uint256 nonce) external returns (address wallet);
+
/// @notice Pause the contract
function pause() external;
@@ -2345,7 +2381,7 @@ interface ISupaCore {
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
/// and Supa reserve/debt must be sufficient
/// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external;
+ function executeBatch(Execution[] memory calls) external;
/// @notice Returns the approved address for a token, or zero if no address set
/// @param collection The address of the ERC721 token
@@ -4520,6 +4556,8 @@ library Errors {
error InvalidSignature();
/// @notice Data does not match the expected format
error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
/// @notice Nonce has already been used
error NonceAlreadyUsed();
/// @notice Deadline has expired
@@ -4951,12 +4989,12 @@ contract WalletProxy is WalletState, Proxy {
receive() external payable override {}
// Allow Supa to make arbitrary calls in lieu of this wallet
- function executeBatch(Call[] calldata calls) external payable ifSupa {
+ function executeBatch(Execution[] calldata calls) external payable ifSupa {
// Function is payable to allow for ETH transfers to the logic
// contract, but supa should never send eth (supa contract should
// never contain eth / other than what's self-destructed into it)
FsUtils.Assert(msg.value == 0);
- CallLib.executeBatch(calls);
+ ExecutionLib.executeBatch(calls);
}
// The implementation of the delegate is controlled by Supa
@@ -5017,6 +5055,12 @@ contract SupaConfig is SupaState, ImmutableGovernance, ISupaConfig {
emit ISupaConfig.WalletImplementationUpgraded(msg.sender, version, implementation);
}
+ /// @inheritdoc ISupaConfig
+ function transferWalletOwnership(address newOwner) external override onlyWallet whenNotPaused {
+ wallets[msg.sender].owner = newOwner;
+ emit ISupaConfig.WalletOwnershipTransferred(msg.sender, newOwner);
+ }
+
/// @inheritdoc ISupaConfig
function proposeTransferWalletOwnership(
address newOwner
@@ -5162,6 +5206,20 @@ contract SupaConfig is SupaState, ImmutableGovernance, ISupaConfig {
emit ISupaConfig.WalletCreated(wallet, msg.sender);
}
+ /// @inheritdoc ISupaConfig
+ function createWallet(uint256 nonce) external override whenNotPaused returns (address wallet) {
+ if (nonce < 1_000_000_000) {
+ revert Errors.InvalidNonce();
+ }
+ wallet = address(new WalletProxy{salt: keccak256(abi.encode(msg.sender, nonce))}(address(this)));
+ wallets[wallet].owner = msg.sender;
+
+ // add a version parameter if users should pick a specific version
+ (, , , address implementation, ) = versionManager.getRecommendedVersion();
+ walletLogic[wallet] = implementation;
+ emit ISupaConfig.WalletCreated(wallet, msg.sender);
+ }
+
/// @inheritdoc ISupaConfig
function getCreditAccountERC20(
address walletAddr,
diff --git a/flat/supa/SupaState.flat.sol b/flat/supa/SupaState.flat.sol
index 8eda868..9af6379 100644
--- a/flat/supa/SupaState.flat.sol
+++ b/flat/supa/SupaState.flat.sol
@@ -1610,6 +1610,12 @@ abstract contract Pausable is Context {
uint256 value;
}
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
/// @notice Metadata to splice a return value into a call.
struct ReturnDataLink {
// index of the call with the return value
@@ -1624,15 +1630,15 @@ abstract contract Pausable is Context {
/// @notice Specify a batch of calls to be executed in sequence,
/// @notice with the return values of some calls being passed as arguments to later calls.
- struct LinkedCall {
- Call call;
+ struct LinkedExecution {
+ Execution execution;
ReturnDataLink[] links;
}
-library CallLib {
+library ExecutionLib {
using Address for address;
- bytes internal constant CALL_TYPESTRING = "Call(address to,bytes callData,uint256 value)";
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
"CallWithoutValue(address to,bytes callData)";
@@ -1656,12 +1662,32 @@ library CallLib {
return call.to.functionCallWithValue(call.callData, call.value);
}
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
/**
* @notice Execute a batch of calls.
*
* @param calls The calls to execute.
*/
- function executeBatch(Call[] memory calls) internal {
+ function executeBatch(Execution[] memory calls) internal {
for (uint256 i = 0; i < calls.length; i++) {
execute(calls[i]);
}
@@ -1678,11 +1704,11 @@ library CallLib {
}
}
- function hashCall(Call memory call) internal pure returns (bytes32) {
- return keccak256(abi.encode(CALL_TYPEHASH, call.to, keccak256(call.callData), call.value));
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
}
- function hashCallArray(Call[] memory calls) internal pure returns (bytes32) {
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
hashes[i] = hashCall(calls[i]);
@@ -1882,6 +1908,11 @@ interface ISupaConfig {
/// @param version The new target version of walletLogic contract
function upgradeWalletImplementation(string calldata version) external;
+ /// @notice Transfers ownership of `msg.sender` to the `newOwner`
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param newOwner The new owner of the wallet
+ function transferWalletOwnership(address newOwner) external;
+
/// @notice Proposes the ownership transfer of `wallet` to the `newOwner`
/// @dev The ownership transfer must be executed by the `newOwner` to complete the transfer
/// @dev emits `WalletOwnershipTransferProposed` event
@@ -1960,6 +1991,11 @@ interface ISupaConfig {
/// @return wallet The address of the created wallet
function createWallet() external returns (address wallet);
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @param nonce The nonce to be used for the wallet creation (must be greater than 1B)
+ /// @return wallet The address of the created wallet
+ function createWallet(uint256 nonce) external returns (address wallet);
+
/// @notice Pause the contract
function pause() external;
@@ -2177,7 +2213,7 @@ interface ISupaCore {
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
/// and Supa reserve/debt must be sufficient
/// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external;
+ function executeBatch(Execution[] memory calls) external;
/// @notice Returns the approved address for a token, or zero if no address set
/// @param collection The address of the ERC721 token
@@ -4352,6 +4388,8 @@ library Errors {
error InvalidSignature();
/// @notice Data does not match the expected format
error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
/// @notice Nonce has already been used
error NonceAlreadyUsed();
/// @notice Deadline has expired
diff --git a/flat/supa/TransferAndCall2.flat.sol b/flat/supa/TransferAndCall2.flat.sol
new file mode 100644
index 0000000..d9a0a50
--- /dev/null
+++ b/flat/supa/TransferAndCall2.flat.sol
@@ -0,0 +1,3281 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+ enum Rounding {
+ Down, // Toward negative infinity
+ Up, // Toward infinity
+ Zero // Toward zero
+ }
+
+ /**
+ * @dev Returns the largest of two numbers.
+ */
+ function max(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two numbers.
+ */
+ function min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two numbers. The result is rounded towards
+ * zero.
+ */
+ function average(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b) / 2 can overflow.
+ return (a & b) + (a ^ b) / 2;
+ }
+
+ /**
+ * @dev Returns the ceiling of the division of two numbers.
+ *
+ * This differs from standard division with `/` in that it rounds up instead
+ * of rounding down.
+ */
+ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b - 1) / b can overflow on addition, so we distribute.
+ return a == 0 ? 0 : (a - 1) / b + 1;
+ }
+
+ /**
+ * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+ * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+ * with further edits by Uniswap Labs also under MIT license.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator
+ ) internal pure returns (uint256 result) {
+ unchecked {
+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+ // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+ // variables such that product = prod1 * 2^256 + prod0.
+ uint256 prod0; // Least significant 256 bits of the product
+ uint256 prod1; // Most significant 256 bits of the product
+ assembly {
+ let mm := mulmod(x, y, not(0))
+ prod0 := mul(x, y)
+ prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+ }
+
+ // Handle non-overflow cases, 256 by 256 division.
+ if (prod1 == 0) {
+ return prod0 / denominator;
+ }
+
+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
+ require(denominator > prod1);
+
+ ///////////////////////////////////////////////
+ // 512 by 256 division.
+ ///////////////////////////////////////////////
+
+ // Make division exact by subtracting the remainder from [prod1 prod0].
+ uint256 remainder;
+ assembly {
+ // Compute remainder using mulmod.
+ remainder := mulmod(x, y, denominator)
+
+ // Subtract 256 bit number from 512 bit number.
+ prod1 := sub(prod1, gt(remainder, prod0))
+ prod0 := sub(prod0, remainder)
+ }
+
+ // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+ // See https://cs.stackexchange.com/q/138556/92363.
+
+ // Does not overflow because the denominator cannot be zero at this stage in the function.
+ uint256 twos = denominator & (~denominator + 1);
+ assembly {
+ // Divide denominator by twos.
+ denominator := div(denominator, twos)
+
+ // Divide [prod1 prod0] by twos.
+ prod0 := div(prod0, twos)
+
+ // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+ twos := add(div(sub(0, twos), twos), 1)
+ }
+
+ // Shift in bits from prod1 into prod0.
+ prod0 |= prod1 * twos;
+
+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+ // four bits. That is, denominator * inv = 1 mod 2^4.
+ uint256 inverse = (3 * denominator) ^ 2;
+
+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+ // in modular arithmetic, doubling the correct bits in each step.
+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+ // is no longer required.
+ result = prod0 * inverse;
+ return result;
+ }
+ }
+
+ /**
+ * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator,
+ Rounding rounding
+ ) internal pure returns (uint256) {
+ uint256 result = mulDiv(x, y, denominator);
+ if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+ result += 1;
+ }
+ return result;
+ }
+
+ /**
+ * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+ *
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+ */
+ function sqrt(uint256 a) internal pure returns (uint256) {
+ if (a == 0) {
+ return 0;
+ }
+
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+ //
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+ //
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+ //
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+ uint256 result = 1 << (log2(a) >> 1);
+
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+ // into the expected uint128 result.
+ unchecked {
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ return min(result, a / result);
+ }
+ }
+
+ /**
+ * @notice Calculates sqrt(a), following the selected rounding direction.
+ */
+ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = sqrt(a);
+ return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 2, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 128;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 64;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 32;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 16;
+ }
+ if (value >> 8 > 0) {
+ value >>= 8;
+ result += 8;
+ }
+ if (value >> 4 > 0) {
+ value >>= 4;
+ result += 4;
+ }
+ if (value >> 2 > 0) {
+ value >>= 2;
+ result += 2;
+ }
+ if (value >> 1 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log2(value);
+ return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 10, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >= 10**64) {
+ value /= 10**64;
+ result += 64;
+ }
+ if (value >= 10**32) {
+ value /= 10**32;
+ result += 32;
+ }
+ if (value >= 10**16) {
+ value /= 10**16;
+ result += 16;
+ }
+ if (value >= 10**8) {
+ value /= 10**8;
+ result += 8;
+ }
+ if (value >= 10**4) {
+ value /= 10**4;
+ result += 4;
+ }
+ if (value >= 10**2) {
+ value /= 10**2;
+ result += 2;
+ }
+ if (value >= 10**1) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log10(value);
+ return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 256, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ *
+ * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+ */
+ function log256(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 16;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 8;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 4;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 2;
+ }
+ if (value >> 8 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log256(value);
+ return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+ }
+ }
+}
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+ bytes16 private constant _SYMBOLS = "0123456789abcdef";
+ uint8 private constant _ADDRESS_LENGTH = 20;
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+ */
+ function toString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ uint256 length = Math.log10(value) + 1;
+ string memory buffer = new string(length);
+ uint256 ptr;
+ /// @solidity memory-safe-assembly
+ assembly {
+ ptr := add(buffer, add(32, length))
+ }
+ while (true) {
+ ptr--;
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+ }
+ value /= 10;
+ if (value == 0) break;
+ }
+ return buffer;
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+ */
+ function toHexString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ return toHexString(value, Math.log256(value) + 1);
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+ */
+ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+ bytes memory buffer = new bytes(2 * length + 2);
+ buffer[0] = "0";
+ buffer[1] = "x";
+ for (uint256 i = 2 * length + 1; i > 1; --i) {
+ buffer[i] = _SYMBOLS[value & 0xf];
+ value >>= 4;
+ }
+ require(value == 0, "Strings: hex length insufficient");
+ return string(buffer);
+ }
+
+ /**
+ * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+ */
+ function toHexString(address addr) internal pure returns (string memory) {
+ return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+ }
+}
+
+/**
+ * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
+ *
+ * These functions can be used to verify that a message was signed by the holder
+ * of the private keys of a given address.
+ */
+library ECDSA {
+ enum RecoverError {
+ NoError,
+ InvalidSignature,
+ InvalidSignatureLength,
+ InvalidSignatureS,
+ InvalidSignatureV // Deprecated in v4.8
+ }
+
+ function _throwError(RecoverError error) private pure {
+ if (error == RecoverError.NoError) {
+ return; // no error: do nothing
+ } else if (error == RecoverError.InvalidSignature) {
+ revert("ECDSA: invalid signature");
+ } else if (error == RecoverError.InvalidSignatureLength) {
+ revert("ECDSA: invalid signature length");
+ } else if (error == RecoverError.InvalidSignatureS) {
+ revert("ECDSA: invalid signature 's' value");
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature` or error string. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ *
+ * Documentation for signature generation:
+ * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
+ * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
+ if (signature.length == 65) {
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ // ecrecover takes the signature parameters, and the only way to get them
+ // currently is to use assembly.
+ /// @solidity memory-safe-assembly
+ assembly {
+ r := mload(add(signature, 0x20))
+ s := mload(add(signature, 0x40))
+ v := byte(0, mload(add(signature, 0x60)))
+ }
+ return tryRecover(hash, v, r, s);
+ } else {
+ return (address(0), RecoverError.InvalidSignatureLength);
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature`. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ */
+ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, signature);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
+ *
+ * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address, RecoverError) {
+ bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
+ uint8 v = uint8((uint256(vs) >> 255) + 27);
+ return tryRecover(hash, v, r, s);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
+ *
+ * _Available since v4.2._
+ */
+ function recover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, r, vs);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address, RecoverError) {
+ // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
+ // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
+ // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
+ // signatures from current libraries generate a unique signature with an s-value in the lower half order.
+ //
+ // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
+ // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
+ // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
+ // these malleable signatures as well.
+ if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
+ return (address(0), RecoverError.InvalidSignatureS);
+ }
+
+ // If the signature is valid (and not malleable), return the signer address
+ address signer = ecrecover(hash, v, r, s);
+ if (signer == address(0)) {
+ return (address(0), RecoverError.InvalidSignature);
+ }
+
+ return (signer, RecoverError.NoError);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ */
+ function recover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from a `hash`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
+ // 32 is the length in bytes of hash,
+ // enforced by the type signature above
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from `s`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Typed Data, created from a
+ * `domainSeparator` and a `structHash`. This produces hash corresponding
+ * to the one signed with the
+ * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
+ * JSON-RPC method as part of EIP-712.
+ *
+ * See {recover}.
+ */
+ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
+ }
+}
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
+ *
+ * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
+ * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
+ * they need in their contracts using a combination of `abi.encode` and `keccak256`.
+ *
+ * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
+ * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
+ * ({_hashTypedDataV4}).
+ *
+ * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
+ * the chain id to protect against replay attacks on an eventual fork of the chain.
+ *
+ * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
+ * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
+ *
+ * _Available since v3.4._
+ */
+abstract contract EIP712 {
+ /* solhint-disable var-name-mixedcase */
+ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
+ // invalidate the cached domain separator if the chain id changes.
+ bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
+ uint256 private immutable _CACHED_CHAIN_ID;
+ address private immutable _CACHED_THIS;
+
+ bytes32 private immutable _HASHED_NAME;
+ bytes32 private immutable _HASHED_VERSION;
+ bytes32 private immutable _TYPE_HASH;
+
+ /* solhint-enable var-name-mixedcase */
+
+ /**
+ * @dev Initializes the domain separator and parameter caches.
+ *
+ * The meaning of `name` and `version` is specified in
+ * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
+ *
+ * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
+ * - `version`: the current major version of the signing domain.
+ *
+ * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
+ * contract upgrade].
+ */
+ constructor(string memory name, string memory version) {
+ bytes32 hashedName = keccak256(bytes(name));
+ bytes32 hashedVersion = keccak256(bytes(version));
+ bytes32 typeHash = keccak256(
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
+ );
+ _HASHED_NAME = hashedName;
+ _HASHED_VERSION = hashedVersion;
+ _CACHED_CHAIN_ID = block.chainid;
+ _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
+ _CACHED_THIS = address(this);
+ _TYPE_HASH = typeHash;
+ }
+
+ /**
+ * @dev Returns the domain separator for the current chain.
+ */
+ function _domainSeparatorV4() internal view returns (bytes32) {
+ if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
+ return _CACHED_DOMAIN_SEPARATOR;
+ } else {
+ return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
+ }
+ }
+
+ function _buildDomainSeparator(
+ bytes32 typeHash,
+ bytes32 nameHash,
+ bytes32 versionHash
+ ) private view returns (bytes32) {
+ return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
+ }
+
+ /**
+ * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
+ * function returns the hash of the fully encoded EIP712 message for this domain.
+ *
+ * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
+ *
+ * ```solidity
+ * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
+ * keccak256("Mail(address to,string contents)"),
+ * mailTo,
+ * keccak256(bytes(mailContents))
+ * )));
+ * address signer = ECDSA.recover(digest, signature);
+ * ```
+ */
+ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
+ return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol)
+
+library console {
+ address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
+
+ function _sendLogPayload(bytes memory payload) private view {
+ uint256 payloadLength = payload.length;
+ address consoleAddress = CONSOLE_ADDRESS;
+ /// @solidity memory-safe-assembly
+ assembly {
+ let payloadStart := add(payload, 32)
+ let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
+ }
+ }
+
+ function log() internal view {
+ _sendLogPayload(abi.encodeWithSignature("log()"));
+ }
+
+ function logInt(int p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
+ }
+
+ function logUint(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function logString(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function logBool(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function logAddress(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function logBytes(bytes memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
+ }
+
+ function logBytes1(bytes1 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
+ }
+
+ function logBytes2(bytes2 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
+ }
+
+ function logBytes3(bytes3 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
+ }
+
+ function logBytes4(bytes4 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
+ }
+
+ function logBytes5(bytes5 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
+ }
+
+ function logBytes6(bytes6 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
+ }
+
+ function logBytes7(bytes7 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
+ }
+
+ function logBytes8(bytes8 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
+ }
+
+ function logBytes9(bytes9 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
+ }
+
+ function logBytes10(bytes10 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
+ }
+
+ function logBytes11(bytes11 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
+ }
+
+ function logBytes12(bytes12 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
+ }
+
+ function logBytes13(bytes13 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
+ }
+
+ function logBytes14(bytes14 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
+ }
+
+ function logBytes15(bytes15 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
+ }
+
+ function logBytes16(bytes16 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
+ }
+
+ function logBytes17(bytes17 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
+ }
+
+ function logBytes18(bytes18 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
+ }
+
+ function logBytes19(bytes19 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
+ }
+
+ function logBytes20(bytes20 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
+ }
+
+ function logBytes21(bytes21 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
+ }
+
+ function logBytes22(bytes22 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
+ }
+
+ function logBytes23(bytes23 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
+ }
+
+ function logBytes24(bytes24 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
+ }
+
+ function logBytes25(bytes25 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
+ }
+
+ function logBytes26(bytes26 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
+ }
+
+ function logBytes27(bytes27 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
+ }
+
+ function logBytes28(bytes28 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
+ }
+
+ function logBytes29(bytes29 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
+ }
+
+ function logBytes30(bytes30 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
+ }
+
+ function logBytes31(bytes31 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
+ }
+
+ function logBytes32(bytes32 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
+ }
+
+ function log(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function log(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function log(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function log(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function log(uint p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
+ }
+
+ function log(uint p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
+ }
+
+ function log(uint p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
+ }
+
+ function log(uint p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
+ }
+
+ function log(string memory p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
+ }
+
+ function log(string memory p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
+ }
+
+ function log(string memory p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
+ }
+
+ function log(string memory p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
+ }
+
+ function log(bool p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
+ }
+
+ function log(bool p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
+ }
+
+ function log(bool p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
+ }
+
+ function log(bool p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
+ }
+
+ function log(address p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
+ }
+
+ function log(address p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
+ }
+
+ function log(address p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
+ }
+
+ function log(address p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
+ }
+
+ function log(uint p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
+ }
+
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
+
+// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
+
+/**
+ * @dev Interface of the ERC1271 standard signature validation method for
+ * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
+ *
+ * _Available since v4.1._
+ */
+interface IERC1271 {
+ /**
+ * @dev Should return whether the signature provided is valid for the provided data
+ * @param hash Hash of the data to be signed
+ * @param signature Signature byte array associated with _data
+ */
+ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
+}
+
+/**
+ * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
+ * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
+ * Argent and Gnosis Safe.
+ *
+ * _Available since v4.1._
+ */
+library SignatureChecker {
+ /**
+ * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
+ * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
+ *
+ * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
+ * change through time. It could return true at block N and false at block N+1 (or the opposite).
+ */
+ function isValidSignatureNow(
+ address signer,
+ bytes32 hash,
+ bytes memory signature
+ ) internal view returns (bool) {
+ (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
+ console.log("recovered:", recovered);
+ if (error == ECDSA.RecoverError.NoError && recovered == signer) {
+ return true;
+ }
+
+ (bool success, bytes memory result) = signer.staticcall(
+ abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
+ );
+ return (success &&
+ result.length == 32 &&
+ abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
+ }
+}
+
+// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363Receiver.sol)
+
+interface IERC1363Receiver {
+ /*
+ * Note: the ERC-165 identifier for this interface is 0x88a7ca5c.
+ * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))
+ */
+
+ /**
+ * @notice Handle the receipt of ERC1363 tokens
+ * @dev Any ERC1363 smart contract calls this function on the recipient
+ * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the
+ * transfer. Return of other than the magic value MUST result in the
+ * transaction being reverted.
+ * Note: the token contract address is always the message sender.
+ * @param operator address The address which called `transferAndCall` or `transferFromAndCall` function
+ * @param from address The address which are token transferred from
+ * @param value uint256 The amount of tokens transferred
+ * @param data bytes Additional data with no specified format
+ * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`
+ * unless throwing
+ */
+ function onTransferReceived(
+ address operator,
+ address from,
+ uint256 value,
+ bytes memory data
+ ) external returns (bytes4);
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
+
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+ /**
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
+ * another (`to`).
+ *
+ * Note that `value` may be zero.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 value);
+
+ /**
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+ * a call to {approve}. `value` is the new allowance.
+ */
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ /**
+ * @dev Returns the amount of tokens in existence.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns the amount of tokens owned by `account`.
+ */
+ function balanceOf(address account) external view returns (uint256);
+
+ /**
+ * @dev Moves `amount` tokens from the caller's account to `to`.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Returns the remaining number of tokens that `spender` will be
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
+ * zero by default.
+ *
+ * This value changes when {approve} or {transferFrom} are called.
+ */
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
+ * that someone may use both the old and the new allowance by unfortunate
+ * transaction ordering. One possible solution to mitigate this race
+ * condition is to first reduce the spender's allowance to 0 and set the
+ * desired value afterwards:
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Moves `amount` tokens from `from` to `to` using the
+ * allowance mechanism. `amount` is then deducted from the caller's
+ * allowance.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
+
+/**
+ * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ */
+interface IERC20Permit {
+ /**
+ * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+ * given ``owner``'s signed approval.
+ *
+ * IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ * ordering also apply here.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `deadline` must be a timestamp in the future.
+ * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+ * over the EIP712-formatted function arguments.
+ * - the signature must use ``owner``'s current nonce (see {nonces}).
+ *
+ * For more information on the signature format, see the
+ * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+ * section].
+ */
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ /**
+ * @dev Returns the current nonce for `owner`. This value must be
+ * included whenever a signature is generated for {permit}.
+ *
+ * Every successful call to {permit} increases ``owner``'s nonce by one. This
+ * prevents a signature from being used multiple times.
+ */
+ function nonces(address owner) external view returns (uint256);
+
+ /**
+ * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function DOMAIN_SEPARATOR() external view returns (bytes32);
+}
+
+/**
+ * @title SafeERC20
+ * @dev Wrappers around ERC20 operations that throw on failure (when the token
+ * contract returns false). Tokens that return no value (and instead revert or
+ * throw on failure) are also supported, non-reverting calls are assumed to be
+ * successful.
+ * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
+ * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
+ */
+library SafeERC20 {
+ using Address for address;
+
+ function safeTransfer(
+ IERC20 token,
+ address to,
+ uint256 value
+ ) internal {
+ _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
+ }
+
+ function safeTransferFrom(
+ IERC20 token,
+ address from,
+ address to,
+ uint256 value
+ ) internal {
+ _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
+ }
+
+ /**
+ * @dev Deprecated. This function has issues similar to the ones found in
+ * {IERC20-approve}, and its usage is discouraged.
+ *
+ * Whenever possible, use {safeIncreaseAllowance} and
+ * {safeDecreaseAllowance} instead.
+ */
+ function safeApprove(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ // safeApprove should only be called when setting an initial allowance,
+ // or when resetting it to zero. To increase and decrease it, use
+ // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
+ require(
+ (value == 0) || (token.allowance(address(this), spender) == 0),
+ "SafeERC20: approve from non-zero to non-zero allowance"
+ );
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
+ }
+
+ function safeIncreaseAllowance(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ uint256 newAllowance = token.allowance(address(this), spender) + value;
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
+ }
+
+ function safeDecreaseAllowance(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ unchecked {
+ uint256 oldAllowance = token.allowance(address(this), spender);
+ require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
+ uint256 newAllowance = oldAllowance - value;
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
+ }
+ }
+
+ function safePermit(
+ IERC20Permit token,
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal {
+ uint256 nonceBefore = token.nonces(owner);
+ token.permit(owner, spender, value, deadline, v, r, s);
+ uint256 nonceAfter = token.nonces(owner);
+ require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
+ }
+
+ /**
+ * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
+ * on the return value: the return value is optional (but if data is returned, it must not be false).
+ * @param token The token targeted by the call.
+ * @param data The call data (encoded using abi.encode or one of its variants).
+ */
+ function _callOptionalReturn(IERC20 token, bytes memory data) private {
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
+ // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
+ // the target address contains contract code and also asserts for success in the low-level call.
+
+ bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
+ if (returndata.length > 0) {
+ // Return data is optional
+ require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
+ }
+ }
+}
+
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
+
+/**
+ * @dev Interface for the optional metadata functions from the ERC20 standard.
+ *
+ * _Available since v4.1._
+ */
+interface IERC20Metadata is IERC20 {
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() external view returns (string memory);
+
+ /**
+ * @dev Returns the symbol of the token.
+ */
+ function symbol() external view returns (string memory);
+
+ /**
+ * @dev Returns the decimals places of the token.
+ */
+ function decimals() external view returns (uint8);
+}
+
+interface IERC20WithMetadata is IERC20, IERC20Metadata {}
+
+interface IWETH9 is IERC20WithMetadata {
+ receive() external payable;
+
+ function deposit() external payable;
+
+ function withdraw(uint256 wad) external;
+}
+
+// This address is in flux as long as the bytecode of this contract is not fixed. For now
+// we deploy it on local block chain on fixed address, when we go deploy this needs to change
+// to the permanent address.
+address constant TRANSFER_AND_CALL2 = address(0x1554b484D2392672F0375C56d80e91c1d070a007);
+
+// Contracts that implement can receive multiple ERC20 transfers in a single transaction,
+// with backwards compatibility for legacy ERC20's not implementing ERC677.
+abstract contract ITransferReceiver2 {
+ error InvalidSender(address sender);
+
+ struct Transfer {
+ address token;
+ uint256 amount;
+ }
+
+ /// @dev Called by a token to indicate a transfer into the callee
+ /// @param operator The account that initiated the transfer
+ /// @param from The account that has sent the token
+ /// @param transfers Transfers that have been made
+ /// @param data The extra data being passed to the receiving contract
+ function onTransferReceived2(
+ address operator,
+ address from,
+ Transfer[] calldata transfers,
+ bytes calldata data
+ ) external virtual returns (bytes4);
+
+ modifier onlyTransferAndCall2() {
+ if (msg.sender != TRANSFER_AND_CALL2) revert InvalidSender(msg.sender);
+ _;
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol)
+
+/**
+ * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
+ * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
+ */
+library BitMaps {
+ struct BitMap {
+ mapping(uint256 => uint256) _data;
+ }
+
+ /**
+ * @dev Returns whether the bit at `index` is set.
+ */
+ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
+ uint256 bucket = index >> 8;
+ uint256 mask = 1 << (index & 0xff);
+ return bitmap._data[bucket] & mask != 0;
+ }
+
+ /**
+ * @dev Sets the bit at `index` to the boolean `value`.
+ */
+ function setTo(
+ BitMap storage bitmap,
+ uint256 index,
+ bool value
+ ) internal {
+ if (value) {
+ set(bitmap, index);
+ } else {
+ unset(bitmap, index);
+ }
+ }
+
+ /**
+ * @dev Sets the bit at `index`.
+ */
+ function set(BitMap storage bitmap, uint256 index) internal {
+ uint256 bucket = index >> 8;
+ uint256 mask = 1 << (index & 0xff);
+ bitmap._data[bucket] |= mask;
+ }
+
+ /**
+ * @dev Unsets the bit at `index`.
+ */
+ function unset(BitMap storage bitmap, uint256 index) internal {
+ uint256 bucket = index >> 8;
+ uint256 mask = 1 << (index & 0xff);
+ bitmap._data[bucket] &= ~mask;
+ }
+}
+
+struct NonceMap {
+ BitMaps.BitMap bitMap;
+}
+
+library NonceMapLib {
+ using BitMaps for BitMaps.BitMap;
+
+ function validateAndUseNonce(NonceMap storage self, uint256 nonce) internal {
+ require(!self.bitMap.get(nonce), "Nonce already used");
+ self.bitMap.set(nonce);
+ }
+
+ function getNonce(NonceMap storage self, uint256 nonce) internal view returns (bool) {
+ return self.bitMap.get(nonce);
+ }
+}
+
+/// @title Errors
+/// @notice Library containing all custom errors the protocol may revert with.
+library Errors {
+ /*//////////////////////////////////////////////////////////////////////////
+ GENERICS
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The address cannot be the zero address
+ error AddressZero();
+ /// @notice The signature is invalid
+ error InvalidSignature();
+ /// @notice Data does not match the expected format
+ error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
+ /// @notice Nonce has already been used
+ error NonceAlreadyUsed();
+ /// @notice Deadline has expired
+ error DeadlineExpired();
+ /// @notice Only Supa can call this function
+ error OnlySupa();
+ /// @notice Only the owner or operator can call this function
+ error NotOwnerOrOperator();
+ /// @notice Only the owner can call this function
+ error OnlyOwner();
+ /// @notice Only this address can call this function
+ error OnlyThisAddress();
+ /// @notice Transfer failed
+ error TransferFailed();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC20
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC721
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The receiving address is not a contract
+ error ReceiverNotContract();
+ /// @notice The receiver does not implement the required interface
+ error ReceiverNoImplementation();
+ /// @notice The receiver did not return the correct value - transaction failed
+ error WrongDataReturned();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ORACLES
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Borrow factor must be greater than zero
+ error InvalidBorrowFactor();
+/// @notice Chainlink price oracle must return a valid price (>0)
+ error InvalidPrice();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ SUPA
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Sender is not approved to spend wallet erc20
+ error NotApprovedOrOwner();
+ /// @notice Sender is not the owner of the wallet;
+ /// @param sender The address of the sender
+ /// @param owner The address of the owner
+ error NotOwner(address sender, address owner);
+ /// @notice Transfer amount exceeds allowance
+ error InsufficientAllowance();
+ /// @notice Cannot approve self as spender
+ error SelfApproval();
+ /// @notice Asset is not an NFT
+ error NotNFT();
+ /// @notice NFT must be owned the the user or user's wallet
+ error NotNFTOwner();
+ /// @notice Operation leaves wallet insolvent
+ error Insolvent();
+ /// @notice Thrown if a wallet accumulates too many assets
+ error SolvencyCheckTooExpensive();
+ /// @notice Cannot withdraw debt
+ error CannotWithdrawDebt();
+ /// @notice Wallet is not liquidatable
+ error NotLiquidatable();
+ /// @notice There are insufficient reserves in the protocol for the debt
+ error InsufficientReserves();
+ /// @notice This operation would add too many tokens to the credit account
+ error TokenStorageExceeded();
+ /// @notice The address is not a registered ERC20
+ error NotERC20();
+ /// @notice `newOwner` is not the proposed new owner
+ /// @param proposedOwner The address of the proposed new owner
+ /// @param newOwner The address of the attempted new owner
+ error InvalidNewOwner(address proposedOwner, address newOwner);
+ /// @notice Only wallet can call this function
+ error OnlyWallet();
+ /// @notice Recipient is not a valid wallet
+ error WalletNonExistent();
+ /// @notice Asset is not registered
+ /// @param token The unregistered asset
+ error NotRegistered(address token);
+ /// @notice Thrown when the function is unimplemented
+ error NotImplemented();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ VERSION MANAGER
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The implementation must be a contract
+ error InvalidImplementation();
+ /// @notice The version is deprecated
+ error DeprecatedVersion();
+ /// @notice The bug level is too high
+ error BugLevelTooHigh();
+ /// @notice Recommended Version does not exist
+ error NoRecommendedVersion();
+ /// @notice version is not registered
+ error VersionNotRegistered();
+ /// @notice Specified status is out of range
+ error InvalidStatus();
+ /// @notice Specified bug level is out of range
+ error InvalidBugLevel();
+ /// @notice version name cannot be the empty string
+ error InvalidVersionName();
+ /// @notice version is deprecated or has a bug
+ error InvalidVersion();
+ /// @notice version is already registered
+ error VersionAlreadyRegistered();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ TRANSFER AND CALL 2
+ //////////////////////////////////////////////////////////////////////////*/
+
+ error TransfersUnsorted();
+
+ error EthDoesntMatchWethTransfer();
+
+ error UnauthorizedOperator(address operator, address from);
+
+ error ExpiredPermit();
+}
+
+// Bringing ERC1363 to all tokens, it's to ERC1363 what Permit2 is to ERC2612.
+// This should be proposed as an EIP and should be deployed cross chain on
+// fixed address using AnyswapCreate2Deployer.
+contract TransferAndCall2 is IERC1363Receiver, EIP712 {
+ using Address for address;
+ using SafeERC20 for IERC20;
+ using NonceMapLib for NonceMap;
+
+ error onTransferReceivedFailed(
+ address to,
+ address operator,
+ address from,
+ ITransferReceiver2.Transfer[] transfers,
+ bytes data
+ );
+
+ bytes private constant TRANSFER_TYPESTRING = "Transfer(address token,uint256 amount)";
+ bytes private constant PERMIT_TYPESTRING =
+ "Permit(address receiver,Transfer[] transfers,bytes data,uint256 nonce,uint256 deadline)";
+ bytes32 private constant TRANSFER_TYPEHASH = keccak256(TRANSFER_TYPESTRING);
+ bytes32 private constant PERMIT_TYPEHASH =
+ keccak256(abi.encodePacked(PERMIT_TYPESTRING, TRANSFER_TYPESTRING));
+
+ mapping(address => mapping(address => bool)) public approvalByOwnerByOperator;
+ mapping(address => NonceMap) private nonceMap;
+
+ constructor() EIP712("TransferAndCall2", "1") {}
+
+ /// @dev Set approval for all token transfers from msg.sender to a particular operator
+ function setApprovalForAll(address operator, bool approved) external {
+ approvalByOwnerByOperator[msg.sender][operator] = approved;
+ }
+
+ /// @dev Called by a token to indicate a transfer into the callee
+ /// @param receiver The account to sent the tokens
+ /// @param transfers Transfers that have been made
+ /// @param data The extra data being passed to the receiving contract
+ function transferAndCall2(
+ address receiver,
+ ITransferReceiver2.Transfer[] calldata transfers,
+ bytes calldata data
+ ) external {
+ _transferFromAndCall2Impl(msg.sender, receiver, address(0), transfers, data);
+ }
+
+ /// @dev Called by a token to indicate a transfer into the callee, converting ETH to WETH
+ /// @param receiver The account to sent the tokens
+ /// @param weth The WETH9 contract address
+ /// @param transfers Transfers that have been made
+ /// @param data The extra data being passed to the receiving contract
+ function transferAndCall2WithValue(
+ address receiver,
+ address weth,
+ ITransferReceiver2.Transfer[] calldata transfers,
+ bytes calldata data
+ ) external payable {
+ _transferFromAndCall2Impl(msg.sender, receiver, weth, transfers, data);
+ }
+
+ /// @dev Called by a token to indicate a transfer into the callee
+ /// @param from The account that has sent the tokens
+ /// @param receiver The account to sent the tokens
+ /// @param transfers Transfers that have been made
+ /// @param data The extra data being passed to the receiving contract
+ function transferFromAndCall2(
+ address from,
+ address receiver,
+ ITransferReceiver2.Transfer[] calldata transfers,
+ bytes calldata data
+ ) external {
+ if (!approvalByOwnerByOperator[from][msg.sender]) {
+ revert Errors.UnauthorizedOperator(msg.sender, from);
+ }
+ _transferFromAndCall2Impl(from, receiver, address(0), transfers, data);
+ }
+
+ function transferAndCall2WithPermit(
+ address from,
+ address receiver,
+ ITransferReceiver2.Transfer[] calldata transfers,
+ bytes calldata data,
+ uint256 nonce,
+ uint256 deadline,
+ bytes calldata signature
+ ) external {
+ nonceMap[from].validateAndUseNonce(nonce);
+ if (block.timestamp > deadline) {
+ revert Errors.ExpiredPermit();
+ }
+ bytes32[] memory transferHashes = new bytes32[](transfers.length);
+ for (uint256 i = 0; i < transfers.length; i++) {
+ transferHashes[i] = keccak256(
+ abi.encodePacked(TRANSFER_TYPEHASH, transfers[i].token, transfers[i].amount)
+ );
+ }
+ bytes32 digest = _hashTypedDataV4(
+ keccak256(
+ abi.encode(
+ PERMIT_TYPEHASH,
+ receiver,
+ keccak256(abi.encodePacked(transferHashes)),
+ data,
+ nonce,
+ deadline
+ )
+ )
+ );
+ if (!SignatureChecker.isValidSignatureNow(from, digest, signature)) {
+ revert Errors.InvalidSignature();
+ }
+ _transferFromAndCall2Impl(from, receiver, address(0), transfers, data);
+ }
+
+ /// @notice Callback for ERC1363 transferAndCall
+ /// @param _operator The address which called `transferAndCall` function
+ /// @param _from The address which previously owned the token
+ /// @param _amount The amount of tokens being transferred
+ /// @param _data Additional data containing the receiver address and the extra data
+ function onTransferReceived(
+ address _operator,
+ address _from,
+ uint256 _amount,
+ bytes calldata _data
+ ) external override returns (bytes4) {
+ (address to, bytes memory decodedData) = abi.decode(_data, (address, bytes));
+ ITransferReceiver2.Transfer[] memory transfers = new ITransferReceiver2.Transfer[](1);
+ transfers[0] = ITransferReceiver2.Transfer(msg.sender, _amount);
+ _callOnTransferReceived2(to, _operator, _from, transfers, decodedData);
+ return IERC1363Receiver.onTransferReceived.selector;
+ }
+
+ function _transferFromAndCall2Impl(
+ address from,
+ address receiver,
+ address weth,
+ ITransferReceiver2.Transfer[] calldata transfers,
+ bytes memory data
+ ) internal {
+ uint256 ethAmount = msg.value;
+ if (ethAmount != 0) {
+ IWETH9(payable(weth)).deposit{value: msg.value}();
+ IERC20(weth).safeTransfer(receiver, msg.value);
+ }
+ address prev = address(0);
+ for (uint256 i = 0; i < transfers.length; i++) {
+ address tokenAddress = transfers[i].token;
+ if (prev >= tokenAddress) revert Errors.TransfersUnsorted();
+ prev = tokenAddress;
+ uint256 amount = transfers[i].amount;
+ if (tokenAddress == weth) {
+ // Already send WETH
+ amount -= ethAmount; // reverts if msg.value > amount
+ ethAmount = 0;
+ }
+ IERC20 token = IERC20(tokenAddress);
+ if (amount > 0) token.safeTransferFrom(from, receiver, amount);
+ }
+ if (ethAmount != 0) revert Errors.EthDoesntMatchWethTransfer();
+ if (receiver.isContract()) {
+ _callOnTransferReceived2(receiver, msg.sender, from, transfers, data);
+ }
+ }
+
+ function _callOnTransferReceived2(
+ address to,
+ address operator,
+ address from,
+ ITransferReceiver2.Transfer[] memory transfers,
+ bytes memory data
+ ) internal {
+ if (
+ ITransferReceiver2(to).onTransferReceived2(operator, from, transfers, data) !=
+ ITransferReceiver2.onTransferReceived2.selector
+ ) {
+ revert onTransferReceivedFailed(to, operator, from, transfers, data);
+ }
+ }
+}
+
diff --git a/flat/supa/VersoinManager.flat.sol b/flat/supa/VersionManager.flat.sol
similarity index 99%
rename from flat/supa/VersoinManager.flat.sol
rename to flat/supa/VersionManager.flat.sol
index 44b544f..3d06ea7 100644
--- a/flat/supa/VersoinManager.flat.sol
+++ b/flat/supa/VersionManager.flat.sol
@@ -2016,6 +2016,8 @@ library Errors {
error InvalidSignature();
/// @notice Data does not match the expected format
error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
/// @notice Nonce has already been used
error NonceAlreadyUsed();
/// @notice Deadline has expired
diff --git a/flat/wallet/WalletProxy.flat.sol b/flat/wallet/WalletProxy.flat.sol
new file mode 100644
index 0000000..eee8b2a
--- /dev/null
+++ b/flat/wallet/WalletProxy.flat.sol
@@ -0,0 +1,3341 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+ /**
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
+ * another (`to`).
+ *
+ * Note that `value` may be zero.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 value);
+
+ /**
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+ * a call to {approve}. `value` is the new allowance.
+ */
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ /**
+ * @dev Returns the amount of tokens in existence.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns the amount of tokens owned by `account`.
+ */
+ function balanceOf(address account) external view returns (uint256);
+
+ /**
+ * @dev Moves `amount` tokens from the caller's account to `to`.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Returns the remaining number of tokens that `spender` will be
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
+ * zero by default.
+ *
+ * This value changes when {approve} or {transferFrom} are called.
+ */
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
+ * that someone may use both the old and the new allowance by unfortunate
+ * transaction ordering. One possible solution to mitigate this race
+ * condition is to first reduce the spender's allowance to 0 and set the
+ * desired value afterwards:
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Moves `amount` tokens from `from` to `to` using the
+ * allowance mechanism. `amount` is then deducted from the caller's
+ * allowance.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
+
+// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
+
+/**
+ * @dev Interface of the ERC165 standard, as defined in the
+ * https://eips.ethereum.org/EIPS/eip-165[EIP].
+ *
+ * Implementers can declare support of contract interfaces, which can then be
+ * queried by others ({ERC165Checker}).
+ *
+ * For an implementation, see {ERC165}.
+ */
+interface IERC165 {
+ /**
+ * @dev Returns true if this contract implements the interface defined by
+ * `interfaceId`. See the corresponding
+ * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
+ * to learn more about how these ids are created.
+ *
+ * This function call must use less than 30 000 gas.
+ */
+ function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
+
+/**
+ * @dev Required interface of an ERC721 compliant contract.
+ */
+interface IERC721 is IERC165 {
+ /**
+ * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+
+ /**
+ * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
+ */
+ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+
+ /**
+ * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
+ */
+ event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+
+ /**
+ * @dev Returns the number of tokens in ``owner``'s account.
+ */
+ function balanceOf(address owner) external view returns (uint256 balance);
+
+ /**
+ * @dev Returns the owner of the `tokenId` token.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function ownerOf(uint256 tokenId) external view returns (address owner);
+
+ /**
+ * @dev Safely transfers `tokenId` token from `from` to `to`.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must exist and be owned by `from`.
+ * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes calldata data
+ ) external;
+
+ /**
+ * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
+ * are aware of the ERC721 protocol to prevent tokens from being forever locked.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must exist and be owned by `from`.
+ * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /**
+ * @dev Transfers `tokenId` token from `from` to `to`.
+ *
+ * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
+ * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
+ * understand this adds an external call which potentially creates a reentrancy vulnerability.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must be owned by `from`.
+ * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /**
+ * @dev Gives permission to `to` to transfer `tokenId` token to another account.
+ * The approval is cleared when the token is transferred.
+ *
+ * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
+ *
+ * Requirements:
+ *
+ * - The caller must own the token or be an approved operator.
+ * - `tokenId` must exist.
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address to, uint256 tokenId) external;
+
+ /**
+ * @dev Approve or remove `operator` as an operator for the caller.
+ * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
+ *
+ * Requirements:
+ *
+ * - The `operator` cannot be the caller.
+ *
+ * Emits an {ApprovalForAll} event.
+ */
+ function setApprovalForAll(address operator, bool _approved) external;
+
+ /**
+ * @dev Returns the account approved for `tokenId` token.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function getApproved(uint256 tokenId) external view returns (address operator);
+
+ /**
+ * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
+ *
+ * See {setApprovalForAll}
+ */
+ function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
+
+// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
+
+/**
+ * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
+ * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
+ * be specified by overriding the virtual {_implementation} function.
+ *
+ * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
+ * different contract through the {_delegate} function.
+ *
+ * The success and return data of the delegated call will be returned back to the caller of the proxy.
+ */
+abstract contract Proxy {
+ /**
+ * @dev Delegates the current call to `implementation`.
+ *
+ * This function does not return to its internal call site, it will return directly to the external caller.
+ */
+ function _delegate(address implementation) internal virtual {
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+ calldatacopy(0, 0, calldatasize())
+
+ // Call the implementation.
+ // out and outsize are 0 because we don't know the size yet.
+ let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
+
+ // Copy the returned data.
+ returndatacopy(0, 0, returndatasize())
+
+ switch result
+ // delegatecall returns 0 on error.
+ case 0 {
+ revert(0, returndatasize())
+ }
+ default {
+ return(0, returndatasize())
+ }
+ }
+ }
+
+ /**
+ * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
+ * and {_fallback} should delegate.
+ */
+ function _implementation() internal view virtual returns (address);
+
+ /**
+ * @dev Delegates the current call to the address returned by `_implementation()`.
+ *
+ * This function does not return to its internal call site, it will return directly to the external caller.
+ */
+ function _fallback() internal virtual {
+ _beforeFallback();
+ _delegate(_implementation());
+ }
+
+ /**
+ * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
+ * function in the contract matches the call data.
+ */
+ fallback() external payable virtual {
+ _fallback();
+ }
+
+ /**
+ * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
+ * is empty.
+ */
+ receive() external payable virtual {
+ _fallback();
+ }
+
+ /**
+ * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
+ * call, or as part of the Solidity `fallback` or `receive` functions.
+ *
+ * If overridden should call `super._beforeFallback()`.
+ */
+ function _beforeFallback() internal virtual {}
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
+
+/**
+ * @title A serialized contract method call.
+ *
+ * @notice A call to a contract with no native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct CallWithoutValue {
+ address to;
+ bytes callData;
+ }
+
+/**
+ * @title A serialized contract method call, with value.
+ *
+ * @notice A call to a contract that may also have native value transferred as part of the call.
+ *
+ * We often need to pass calls around, so this is a common representation to use.
+ */
+ struct Call {
+ address to;
+ bytes callData;
+ uint256 value;
+ }
+
+ struct Execution {
+ address target;
+ uint256 value;
+ bytes callData;
+ }
+
+/// @notice Metadata to splice a return value into a call.
+ struct ReturnDataLink {
+ // index of the call with the return value
+ uint32 callIndex;
+ // offset of the return value in the return data
+ uint32 returnValueOffset;
+ // indicates whether the return value is static or dynamic
+ bool isStatic;
+ // offset in the callData where the return value should be spliced in
+ uint128 offset;
+ }
+
+/// @notice Specify a batch of calls to be executed in sequence,
+/// @notice with the return values of some calls being passed as arguments to later calls.
+ struct LinkedExecution {
+ Execution execution;
+ ReturnDataLink[] links;
+ }
+
+library ExecutionLib {
+ using Address for address;
+
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
+ bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
+ bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
+ "CallWithoutValue(address to,bytes callData)";
+ bytes32 constant CALLWITHOUTVALUE_TYPEHASH = keccak256(CALLWITHOUTVALUE_TYPESTRING);
+
+ /**
+ * @notice Execute a call.
+ *
+ * @param call The call to execute.
+ */
+ function executeWithoutValue(CallWithoutValue memory call) internal {
+ call.to.functionCall(call.callData);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Call memory call) internal returns (bytes memory) {
+ return call.to.functionCallWithValue(call.callData, call.value);
+ }
+
+ /**
+ * @notice Execute a call with value.
+ *
+ * @param call The call to execute.
+ */
+ function execute(Execution memory call) internal returns (bytes memory) {
+ return call.target.functionCallWithValue(call.callData, call.value);
+ }
+
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
+
+ /**
+ * @notice Execute a batch of calls.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatch(Execution[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ execute(calls[i]);
+ }
+ }
+
+ /**
+ * @notice Execute a batch of calls with value.
+ *
+ * @param calls The calls to execute.
+ */
+ function executeBatchWithoutValue(CallWithoutValue[] memory calls) internal {
+ for (uint256 i = 0; i < calls.length; i++) {
+ executeWithoutValue(calls[i]);
+ }
+ }
+
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
+ }
+
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCall(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+
+ function hashCallWithoutValue(CallWithoutValue memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALLWITHOUTVALUE_TYPEHASH, call.to, keccak256(call.callData)));
+ }
+
+ function hashCallWithoutValueArray(
+ CallWithoutValue[] memory calls
+ ) internal pure returns (bytes32) {
+ bytes32[] memory hashes = new bytes32[](calls.length);
+ for (uint256 i = 0; i < calls.length; i++) {
+ hashes[i] = hashCallWithoutValue(calls[i]);
+ }
+ return keccak256(abi.encodePacked(hashes));
+ }
+}
+
+/// @title ERC20 value oracle interface
+interface IERC20ValueOracle {
+ /// @notice Emitted when risk factors are set
+ /// @param collateralFactor Collateral factor
+ /// @param borrowFactor Borrow factor
+ event RiskFactorsSet(int256 indexed collateralFactor, int256 indexed borrowFactor);
+
+ function collateralFactor() external view returns (int256 collateralFactor);
+
+ function borrowFactor() external view returns (int256 borrowFactor);
+
+ function calcValue(int256 balance) external view returns (int256 value, int256 riskAdjustedValue);
+
+ function getValues()
+ external
+ view
+ returns (int256 value, int256 collateralAdjustedValue, int256 borrowAdjustedValue);
+}
+
+/// @title NFT Value Oracle Interface
+interface INFTValueOracle {
+ function calcValue(
+ uint256 tokenId
+ ) external view returns (int256 value, int256 riskAdjustedValue);
+}
+
+type ERC20Share is int256;
+
+struct NFTTokenData {
+ uint240 tokenId; // 240 LSB of the tokenId of the NFT
+ uint16 walletIdx; // index in wallet NFT array
+ address approvedSpender; // approved spender for ERC721
+}
+
+struct ERC20Pool {
+ int256 tokens;
+ int256 shares;
+}
+
+struct ERC20Info {
+ address erc20Contract;
+ IERC20ValueOracle valueOracle;
+ ERC20Pool collateral;
+ ERC20Pool debt;
+ uint256 baseRate;
+ uint256 slope1;
+ uint256 slope2;
+ uint256 targetUtilization;
+ uint256 timestamp;
+}
+
+struct ERC721Info {
+ address erc721Contract;
+ INFTValueOracle valueOracle;
+}
+
+struct ContractData {
+ uint16 idx;
+ ContractKind kind; // 0 invalid, 1 ERC20, 2 ERC721
+}
+
+enum ContractKind {
+ Invalid,
+ ERC20,
+ ERC721
+}
+
+interface ISupaERC20 is IERC20 {
+ function mint(address account, uint256 amount) external;
+
+ function burn(address account, uint256 amount) external;
+}
+
+interface ISupaConfig {
+ struct Config {
+ address treasuryWallet; // The address of the treasury safe
+ uint256 treasuryInterestFraction; // Fraction of interest to send to treasury
+ uint256 maxSolvencyCheckGasCost;
+ int256 liqFraction; // Fraction for the user
+ int256 fractionalReserveLeverage; // Ratio of debt to reserves
+ }
+
+ struct TokenStorageConfig {
+ uint256 maxTokenStorage;
+ uint256 erc20Multiplier;
+ uint256 erc721Multiplier;
+ }
+
+ struct NFTData {
+ address erc721;
+ uint256 tokenId;
+ }
+
+ /// @notice Emitted when the implementation of a wallet is upgraded
+ /// @param wallet The address of the wallet
+ /// @param version The new implementation version
+ event WalletImplementationUpgraded(address indexed wallet, string indexed version, address implementation);
+
+ /// @notice Emitted when the ownership of a wallet is proposed to be transferred
+ /// @param wallet The address of the wallet
+ /// @param newOwner The address of the new owner
+ event WalletOwnershipTransferProposed(address indexed wallet, address indexed newOwner);
+
+ /// @notice Emitted when the ownership of a wallet is transferred
+ /// @param wallet The address of the wallet
+ /// @param newOwner The address of the new owner
+ event WalletOwnershipTransferred(address indexed wallet, address indexed newOwner);
+
+ /// @notice Emitted when a new ERC20 is added to the protocol
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param erc20 The address of the ERC20 contract
+ /// @param name The name of the ERC20
+ /// @param symbol The symbol of the ERC20
+ /// @param decimals The decimals of the ERC20
+ /// @param valueOracle The address of the value oracle for the ERC20
+ /// @param baseRate The interest rate at 0% utilization
+ /// @param slope1 The interest rate slope at 0% to target utilization
+ /// @param slope2 The interest rate slope at target utilization to 100% utilization
+ /// @param targetUtilization The target utilization for the ERC20
+ event ERC20Added(
+ uint16 erc20Idx,
+ address erc20,
+ string name,
+ string symbol,
+ uint8 decimals,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ );
+
+ /// @notice Emitted when a new ERC721 is added to the protocol
+ /// @param erc721Idx The index of the ERC721 in the protocol
+ /// @param erc721Contract The address of the ERC721 contract
+ /// @param valueOracleAddress The address of the value oracle for the ERC721
+ event ERC721Added(uint256 indexed erc721Idx, address indexed erc721Contract, address valueOracleAddress);
+
+ /// @notice Emitted when the config is set
+ /// @param config The new config
+ event ConfigSet(Config config);
+
+ /// @notice Emitted when the token storage config is set
+ /// @param tokenStorageConfig The new token storage config
+ event TokenStorageConfigSet(TokenStorageConfig tokenStorageConfig);
+
+ /// @notice Emitted when the version manager address is set
+ /// @param versionManager The version manager address
+ event VersionManagerSet(address indexed versionManager);
+
+ /// @notice Emitted when ERC20 Data is set
+ /// @param erc20 The address of the erc20 token
+ /// @param erc20Idx The index of the erc20 token
+ /// @param valueOracle The new value oracle
+ /// @param baseRate The new base interest rate
+ /// @param slope1 The new slope1
+ /// @param slope2 The new slope2
+ /// @param targetUtilization The new target utilization
+ event ERC20DataSet(
+ address indexed erc20,
+ uint16 indexed erc20Idx,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ );
+
+ /// @notice Emitted when a wallet is created
+ /// @param wallet The address of the wallet
+ /// @param owner The address of the owner
+ event WalletCreated(address wallet, address owner);
+
+ /// @notice upgrades the version of walletLogic contract for the `wallet`
+ /// @param version The new target version of walletLogic contract
+ function upgradeWalletImplementation(string calldata version) external;
+
+ /// @notice Transfers ownership of `msg.sender` to the `newOwner`
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param newOwner The new owner of the wallet
+ function transferWalletOwnership(address newOwner) external;
+
+ /// @notice Proposes the ownership transfer of `wallet` to the `newOwner`
+ /// @dev The ownership transfer must be executed by the `newOwner` to complete the transfer
+ /// @dev emits `WalletOwnershipTransferProposed` event
+ /// @param newOwner The new owner of the `wallet`
+ function proposeTransferWalletOwnership(address newOwner) external;
+
+ /// @notice Executes the ownership transfer of `wallet` to the `newOwner`
+ /// @dev The caller must be the `newOwner` and the `newOwner` must be the proposed new owner
+ /// @dev emits `WalletOwnershipTransferred` event
+ /// @param wallet The address of the wallet
+ function executeTransferWalletOwnership(address wallet) external;
+
+ /// @notice add a new ERC20 to be used inside Supa
+ /// @dev For governance only.
+ /// @param erc20Contract The address of ERC20 to add
+ /// @param name The name of the ERC20. E.g. "Wrapped ETH"
+ /// @param symbol The symbol of the ERC20. E.g. "WETH"
+ /// @param decimals Decimals of the ERC20. E.g. 18 for WETH and 6 for USDC
+ /// @param valueOracle The address of the Value Oracle. Probably Uniswap one
+ /// @param baseRate The interest rate when utilization is 0
+ /// @param slope1 The interest rate slope when utilization is less than the targetUtilization
+ /// @param slope2 The interest rate slope when utilization is more than the targetUtilization
+ /// @param targetUtilization The target utilization for the asset
+ /// @return the index of the added ERC20 in the erc20Infos array
+ function addERC20Info(
+ address erc20Contract,
+ string calldata name,
+ string calldata symbol,
+ uint8 decimals,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ ) external returns (uint16);
+
+ /// @notice Add a new ERC721 to be used inside Supa.
+ /// @dev For governance only.
+ /// @param erc721Contract The address of the ERC721 to be added
+ /// @param valueOracleAddress The address of the Uniswap Oracle to get the price of a token
+ function addERC721Info(address erc721Contract, address valueOracleAddress) external;
+
+ /// @notice Updates the config of Supa
+ /// @dev for governance only.
+ /// @param _config the Config of ISupaConfig. A struct with Supa parameters
+ function setConfig(Config calldata _config) external;
+
+ /// @notice Updates the configuration setttings for credit account token storage
+ /// @dev for governance only.
+ /// @param _tokenStorageConfig the TokenStorageconfig of ISupaConfig
+ function setTokenStorageConfig(TokenStorageConfig calldata _tokenStorageConfig) external;
+
+ /// @notice Set the address of Version Manager contract
+ /// @dev for governance only.
+ /// @param _versionManager The address of the Version Manager contract to be set
+ function setVersionManager(address _versionManager) external;
+
+ /// @notice Updates some of ERC20 config parameters
+ /// @dev for governance only.
+ /// @param erc20 The address of ERC20 contract for which Supa config parameters should be updated
+ /// @param valueOracle The address of the erc20 value oracle
+ /// @param baseRate The interest rate when utilization is 0
+ /// @param slope1 The interest rate slope when utilization is less than the targetUtilization
+ /// @param slope2 The interest rate slope when utilization is more than the targetUtilization
+ /// @param targetUtilization The target utilization for the asset
+ function setERC20Data(
+ address erc20,
+ address valueOracle,
+ uint256 baseRate,
+ uint256 slope1,
+ uint256 slope2,
+ uint256 targetUtilization
+ ) external;
+
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @return wallet The address of the created wallet
+ function createWallet() external returns (address wallet);
+
+ /// @notice creates a new wallet with sender as the owner and returns the wallet address
+ /// @param nonce The nonce to be used for the wallet creation (must be greater than 1B)
+ /// @return wallet The address of the created wallet
+ function createWallet(uint256 nonce) external returns (address wallet);
+
+ /// @notice Pause the contract
+ function pause() external;
+
+ /// @notice Unpause the contract
+ function unpause() external;
+
+ /// @notice Returns the amount of `erc20` tokens on creditAccount of wallet
+ /// @param walletAddr The address of the wallet for which creditAccount the amount of `erc20` should
+ /// be calculated
+ /// @param erc20 The address of ERC20 which balance on creditAccount of `wallet` should be calculated
+ /// @return the amount of `erc20` on the creditAccount of `wallet`
+ function getCreditAccountERC20(address walletAddr, IERC20 erc20) external view returns (int256);
+
+ /// @notice returns the NFTs on creditAccount of `wallet`
+ /// @param wallet The address of wallet which creditAccount NFTs should be returned
+ /// @return The array of NFT deposited on the creditAccount of `wallet`
+ function getCreditAccountERC721(address wallet) external view returns (NFTData[] memory);
+
+ /// @notice returns the amount of NFTs in creditAccount of `wallet`
+ /// @param wallet The address of the wallet that owns the creditAccount
+ /// @return The amount of NFTs in the creditAccount of `wallet`
+ function getCreditAccountERC721Counter(address wallet) external view returns (uint256);
+}
+
+interface ISupaCore {
+ struct Approval {
+ address ercContract; // ERC20/ERC721 contract
+ uint256 amountOrTokenId; // amount or tokenId
+ }
+
+ /// @notice Emitted when ERC20 tokens are transferred between credit accounts
+ /// @param erc20 The address of the ERC20 token
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param from The address of the sender
+ /// @param to The address of the receiver
+ /// @param value The amount of tokens transferred
+ event ERC20Transfer(address indexed erc20, uint16 erc20Idx, address indexed from, address indexed to, int256 value);
+
+ /// @notice Emitted when erc20 tokens are deposited or withdrawn from a credit account
+ /// @param erc20 The address of the ERC20 token
+ /// @param erc20Idx The index of the ERC20 in the protocol
+ /// @param to The address of the wallet
+ /// @param amount The amount of tokens deposited or withdrawn
+ event ERC20BalanceChanged(address indexed erc20, uint16 erc20Idx, address indexed to, int256 amount);
+
+ /// @notice Emitted when a ERC721 is transferred between credit accounts
+ /// @param nftId The nftId of the ERC721 token
+ /// @param from The address of the sender
+ /// @param to The address of the receiver
+ event ERC721Transferred(uint256 indexed nftId, address indexed from, address indexed to);
+
+ /// @notice Emitted when an ERC721 token is deposited to a credit account
+ /// @param erc721 The address of the ERC721 token
+ /// @param to The address of the wallet
+ /// @param tokenId The id of the token deposited
+ event ERC721Deposited(address indexed erc721, address indexed to, uint256 indexed tokenId);
+
+ /// @notice Emitted when an ERC721 token is withdrawn from a credit account
+ /// @param erc721 The address of the ERC721 token
+ /// @param from The address of the wallet
+ /// @param tokenId The id of the token withdrawn
+ event ERC721Withdrawn(address indexed erc721, address indexed from, uint256 indexed tokenId);
+
+ /// @dev Emitted when `owner` approves `spender` to spend `value` tokens on their behalf.
+ /// @param erc20 The ERC20 token to approve
+ /// @param owner The address of the token owner
+ /// @param spender The address of the spender
+ /// @param value The amount of tokens to approve
+ event ERC20Approval(
+ address indexed erc20, uint16 erc20Idx, address indexed owner, address indexed spender, uint256 value
+ );
+
+ /// @dev Emitted when `owner` enables `approved` to manage the `tokenId` token on collection `collection`.
+ /// @param collection The address of the ERC721 collection
+ /// @param owner The address of the token owner
+ /// @param approved The address of the approved operator
+ /// @param tokenId The ID of the approved token
+ event ERC721Approval(address indexed collection, address indexed owner, address indexed approved, uint256 tokenId);
+
+ /// @dev Emitted when an ERC721 token is received
+ /// @param wallet The address of the wallet receiving the token
+ /// @param erc721 The address of the ERC721 token
+ /// @param tokenId The id of the token received
+ event ERC721Received(address indexed wallet, address indexed erc721, uint256 indexed tokenId);
+
+ /// @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its erc20s.
+ /// @param collection The address of the collection
+ /// @param owner The address of the owner
+ /// @param operator The address of the operator
+ /// @param approved True if the operator is approved, false to revoke approval
+ event ApprovalForAll(address indexed collection, address indexed owner, address indexed operator, bool approved);
+
+ /// @dev Emitted when an operator is added to a wallet
+ /// @param wallet The address of the wallet
+ /// @param operator The address of the operator
+ event OperatorAdded(address indexed wallet, address indexed operator);
+
+ /// @dev Emitted when an operator is removed from a wallet
+ /// @param wallet The address of the wallet
+ /// @param operator The address of the operator
+ event OperatorRemoved(address indexed wallet, address indexed operator);
+
+ /// @notice Emitted when a wallet is liquidated
+ /// @param wallet The address of the liquidated wallet
+ /// @param liquidator The address of the liquidator
+ event WalletLiquidated(address indexed wallet, address indexed liquidator, int256 collateral, int256 debt);
+
+ /// @notice top up the creditAccount owned by wallet `to` with `amount` of `erc20`
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param to Address of the wallet that creditAccount should be top up
+ /// @param amount The amount of `erc20` to be sent
+ function depositERC20ForWallet(address erc20, address to, uint256 amount) external;
+
+ /// @notice deposit `amount` of `erc20` to creditAccount from wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param amount The amount of `erc20` to be transferred
+ function depositERC20(IERC20 erc20, uint256 amount) external;
+
+ /// @notice deposit `amount` of `erc20` from creditAccount to wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param amount The amount of `erc20` to be transferred
+ function withdrawERC20(IERC20 erc20, uint256 amount) external;
+
+ /// @notice deposit all `erc20s` from wallet to creditAccount
+ /// @param erc20s Array of addresses of ERC20 to be transferred
+ function depositFull(IERC20[] calldata erc20s) external;
+
+ /// @notice withdraw all `erc20s` from creditAccount to wallet
+ /// @param erc20s Array of addresses of ERC20 to be transferred
+ function withdrawFull(IERC20[] calldata erc20s) external;
+
+ /// @notice deposit ERC721 `erc721Contract` token `tokenId` from wallet to creditAccount
+ /// @dev the part when we track the ownership of deposit NFT to a specific creditAccount is in
+ /// `onERC721Received` function of this contract
+ /// @param erc721Contract The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ function depositERC721(address erc721Contract, uint256 tokenId) external;
+
+ /// @notice deposit ERC721 `erc721Contract` token `tokenId` from wallet to creditAccount
+ /// @dev the part when we track the ownership of deposit NFT to a specific creditAccount is in
+ /// `onERC721Received` function of this contract
+ /// @param erc721Contract The address of the ERC721 contract that the token belongs to
+ /// @param to The wallet address for which the NFT will be deposited
+ /// @param tokenId The id of the token to be transferred
+ function depositERC721ForWallet(address erc721Contract, address to, uint256 tokenId) external;
+
+ /// @notice withdraw ERC721 `nftContract` token `tokenId` from creditAccount to wallet
+ /// @param erc721 The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ function withdrawERC721(address erc721, uint256 tokenId) external;
+
+ /// @notice transfer `amount` of `erc20` from creditAccount of caller wallet to creditAccount of `to` wallet
+ /// @param erc20 Address of the ERC20 token to be transferred
+ /// @param to wallet address, whose creditAccount is the transfer target
+ /// @param amount The amount of `erc20` to be transferred
+ function transferERC20(IERC20 erc20, address to, uint256 amount) external;
+
+ /// @notice transfer NFT `erc721` token `tokenId` from creditAccount of caller wallet to creditAccount of
+ /// `to` wallet
+ /// @param erc721 The address of the ERC721 contract that the token belongs to
+ /// @param tokenId The id of the token to be transferred
+ /// @param to wallet address, whose creditAccount is the transfer target
+ function transferERC721(address erc721, uint256 tokenId, address to) external;
+
+ /// @notice Transfer ERC20 tokens from creditAccount to another creditAccount
+ /// @dev Note: Allowance must be set with approveERC20
+ /// @param erc20 The index of the ERC20 token in erc20Infos array
+ /// @param from The address of the wallet to transfer from
+ /// @param to The address of the wallet to transfer to
+ /// @param amount The amount of tokens to transfer
+ /// @return true, when the transfer has been successfully finished without been reverted
+ function transferFromERC20(address erc20, address from, address to, uint256 amount) external returns (bool);
+
+ /// @notice Transfer ERC721 tokens from creditAccount to another creditAccount
+ /// @param collection The address of the ERC721 token
+ /// @param from The address of the wallet to transfer from
+ /// @param to The address of the wallet to transfer to
+ /// @param tokenId The id of the token to transfer
+ function transferFromERC721(address collection, address from, address to, uint256 tokenId) external;
+
+ /// @notice Liquidate an undercollateralized position
+ /// @dev if creditAccount of `wallet` has more debt then collateral then this function will
+ /// transfer all debt and collateral ERC20s and ERC721 from creditAccount of `wallet` to creditAccount of
+ /// caller. Considering that market price of collateral is higher then market price of debt,
+ /// a friction of that difference would be sent back to liquidated creditAccount in Supa base currency.
+ /// More specific - "some fraction" is `liqFraction` parameter of Supa.
+ /// Considering that call to this function would create debt on caller (debt is less then
+ /// gains, yet still), consider using `liquify` instead, that would liquidate and use
+ /// obtained assets to cover all created debt
+ /// If creditAccount of `wallet` has less debt then collateral then the transaction will be reverted
+ /// @param wallet The address of wallet whose creditAccount to be liquidate
+ function liquidate(address wallet) external;
+
+ /// @notice Approve an array of tokens and then call `onApprovalReceived` on msg.sender
+ /// @param approvals An array of ERC20 tokens with amounts, or ERC721 contracts with tokenIds
+ /// @param spender The address of the spender
+ /// @param data Additional data with no specified format, sent in call to `spender`
+ function approveAndCall(Approval[] calldata approvals, address spender, bytes calldata data) external;
+
+ /// @notice Add an operator for wallet
+ /// @param operator The address of the operator to add
+ /// @dev Operator can execute batch of transactions on behalf of wallet owner
+ function addOperator(address operator) external;
+
+ /// @notice Remove an operator for wallet
+ /// @param operator The address of the operator to remove
+ /// @dev Operator can execute batch of transactions on behalf of wallet owner
+ function removeOperator(address operator) external;
+
+ /// @notice Used to migrate wallet to this Supa contract
+ function migrateWallet(address wallet, address owner, address implementation) external;
+
+ /// @notice Execute a batch of calls
+ /// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
+ /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
+ /// and Supa reserve/debt must be sufficient
+ /// @param calls An array of transaction calls
+ function executeBatch(Execution[] memory calls) external;
+
+ /// @notice Returns the approved address for a token, or zero if no address set
+ /// @param collection The address of the ERC721 token
+ /// @param tokenId The id of the token to query
+ /// @return The wallet address that is allowed to transfer the ERC721 token
+ function getApproved(address collection, uint256 tokenId) external view returns (address);
+
+ /// @notice returns the collateral, debt and total value of `walletAddress`.
+ /// @dev Notice that both collateral and debt has some coefficients on the actual amount of deposit
+ /// and loan assets! E.g.
+ /// for a deposit of 1 ETH the collateral would be equivalent to like 0.8 ETH, and
+ /// for a loan of 1 ETH the debt would be equivalent to like 1.2 ETH.
+ /// At the same time, totalValue is the unmodified difference between deposits and loans.
+ /// @param walletAddress The address of wallet whose collateral, debt and total value would be returned
+ /// @return totalValue The difference between equivalents of deposit and loan assets
+ /// @return collateral The sum of deposited assets multiplied by their collateral factors
+ /// @return debt The sum of borrowed assets multiplied by their borrow factors
+ function getRiskAdjustedPositionValues(address walletAddress)
+ external
+ view
+ returns (int256 totalValue, int256 collateral, int256 debt);
+
+ /// @notice Returns if '_spender' is an operator of '_owner'
+ /// @param _owner The address of the owner
+ /// @param _spender The address of the spender
+ /// @return True if the spender is an operator of the owner, false otherwise
+ function isOperator(address _owner, address _spender) external view returns (bool);
+
+ /// @notice Returns the remaining amount of tokens that `spender` will be allowed to spend on
+ /// behalf of `owner` through {transferFrom}
+ /// @dev This value changes when {approve} or {transferFrom} are called
+ /// @param erc20 The address of the ERC20 to be checked
+ /// @param _owner The wallet address whose `erc20` are allowed to be transferred by `spender`
+ /// @param spender The wallet address who is allowed to spend `erc20` of `_owner`
+ /// @return the remaining amount of tokens that `spender` will be allowed to spend on
+ /// behalf of `owner` through {transferFrom}
+ function allowance(address erc20, address _owner, address spender) external view returns (uint256);
+
+ /// @notice Compute the interest rate of `underlying`
+ /// @param erc20Idx The underlying asset
+ /// @return The interest rate of `erc20Idx`
+ function computeInterestRate(uint16 erc20Idx) external view returns (int96);
+
+ /// @notice provides the specific version of walletLogic contract that is associated with `wallet`
+ /// @param wallet Address of wallet whose walletLogic contract should be returned
+ /// @return the address of the walletLogic contract that is associated with the `wallet`
+ function getImplementation(address wallet) external view returns (address);
+
+ /// @notice provides the owner of `wallet`. Owner of the wallet is the address who created the wallet
+ /// @param wallet The address of wallet whose owner should be returned
+ /// @return the owner address of the `wallet`. Owner is the one who created the `wallet`
+ function getWalletOwner(address wallet) external view returns (address);
+
+ /// @notice Checks if the account's positions are overcollateralized
+ /// @dev checks the eventual state of `executeBatch` function execution:
+ /// * `wallet` must have collateral >= debt
+ /// * Supa must have sufficient balance of deposits and loans for each ERC20 token
+ /// @dev when called by the end of `executeBatch`, isSolvent checks the potential target state
+ /// of Supa. Calling this function separately would check current state of Supa, that is always
+ /// solvable, and so the return value would always be `true`, unless the `wallet` is liquidatable
+ /// @param wallet The address of a wallet who performed the `executeBatch`
+ /// @return Whether the position is solvent.
+ function isSolvent(address wallet) external view returns (bool);
+}
+
+interface ISupa is ISupaCore, ISupaConfig {}
+
+// BEGIN STRIP
+// Used in `FsUtils.log` which is a debugging tool.
+
+library console {
+ address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
+
+ function _sendLogPayload(bytes memory payload) private view {
+ uint256 payloadLength = payload.length;
+ address consoleAddress = CONSOLE_ADDRESS;
+ /// @solidity memory-safe-assembly
+ assembly {
+ let payloadStart := add(payload, 32)
+ let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
+ }
+ }
+
+ function log() internal view {
+ _sendLogPayload(abi.encodeWithSignature("log()"));
+ }
+
+ function logInt(int p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
+ }
+
+ function logUint(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function logString(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function logBool(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function logAddress(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function logBytes(bytes memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
+ }
+
+ function logBytes1(bytes1 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
+ }
+
+ function logBytes2(bytes2 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
+ }
+
+ function logBytes3(bytes3 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
+ }
+
+ function logBytes4(bytes4 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
+ }
+
+ function logBytes5(bytes5 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
+ }
+
+ function logBytes6(bytes6 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
+ }
+
+ function logBytes7(bytes7 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
+ }
+
+ function logBytes8(bytes8 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
+ }
+
+ function logBytes9(bytes9 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
+ }
+
+ function logBytes10(bytes10 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
+ }
+
+ function logBytes11(bytes11 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
+ }
+
+ function logBytes12(bytes12 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
+ }
+
+ function logBytes13(bytes13 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
+ }
+
+ function logBytes14(bytes14 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
+ }
+
+ function logBytes15(bytes15 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
+ }
+
+ function logBytes16(bytes16 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
+ }
+
+ function logBytes17(bytes17 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
+ }
+
+ function logBytes18(bytes18 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
+ }
+
+ function logBytes19(bytes19 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
+ }
+
+ function logBytes20(bytes20 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
+ }
+
+ function logBytes21(bytes21 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
+ }
+
+ function logBytes22(bytes22 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
+ }
+
+ function logBytes23(bytes23 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
+ }
+
+ function logBytes24(bytes24 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
+ }
+
+ function logBytes25(bytes25 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
+ }
+
+ function logBytes26(bytes26 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
+ }
+
+ function logBytes27(bytes27 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
+ }
+
+ function logBytes28(bytes28 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
+ }
+
+ function logBytes29(bytes29 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
+ }
+
+ function logBytes30(bytes30 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
+ }
+
+ function logBytes31(bytes31 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
+ }
+
+ function logBytes32(bytes32 p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
+ }
+
+ function log(uint p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
+ }
+
+ function log(string memory p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
+ }
+
+ function log(bool p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
+ }
+
+ function log(address p0) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
+ }
+
+ function log(uint p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
+ }
+
+ function log(uint p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
+ }
+
+ function log(uint p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
+ }
+
+ function log(uint p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
+ }
+
+ function log(string memory p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
+ }
+
+ function log(string memory p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
+ }
+
+ function log(string memory p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
+ }
+
+ function log(string memory p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
+ }
+
+ function log(bool p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
+ }
+
+ function log(bool p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
+ }
+
+ function log(bool p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
+ }
+
+ function log(bool p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
+ }
+
+ function log(address p0, uint p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
+ }
+
+ function log(address p0, string memory p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
+ }
+
+ function log(address p0, bool p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
+ }
+
+ function log(address p0, address p1) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
+ }
+
+ function log(uint p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
+ }
+
+ function log(uint p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
+ }
+
+ function log(string memory p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
+ }
+
+ function log(bool p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, uint p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, string memory p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, bool p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, uint p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, string memory p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, bool p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
+ }
+
+ function log(address p0, address p1, address p2) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
+ }
+
+ function log(uint p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(uint p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(string memory p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(bool p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, uint p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, string memory p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, bool p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, uint p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, string memory p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, bool p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, uint p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, string memory p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, bool p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
+ }
+
+ function log(address p0, address p1, address p2, address p3) internal view {
+ _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
+ }
+
+}
+
+// END STRIP
+
+library FsUtils {
+ // BEGIN STRIP
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s) internal view {
+ console.log(s);
+ }
+
+ // This method is only mean to be used in local testing. See `preprocess` property in
+ // `packages/contracts/hardhat.config.ts`.
+ // Slither sees this function is not used, but it is convenient to have it around for debugging
+ // purposes.
+ // slither-disable-next-line dead-code
+ function log(string memory s, int256 x) internal view {
+ console.log(s);
+ console.logInt(x);
+ }
+
+ function log(string memory s, address x) internal view {
+ console.log(s, x);
+ }
+
+ // END STRIP
+
+ function encodeToBytes32(bytes memory b) internal pure returns (bytes32) {
+ require(b.length < 32, "Byte array to long");
+ bytes32 out = bytes32(b);
+ out = (out & (~(bytes32(type(uint256).max) >> (8 * b.length)))) | bytes32(b.length);
+ return out;
+ }
+
+ function decodeFromBytes32(bytes32 b) internal pure returns (bytes memory) {
+ uint256 len = uint256(b) & 0xff;
+ bytes memory out = new bytes(len);
+ for (uint256 i = 0; i < len; i++) {
+ out[i] = b[i];
+ }
+ return out;
+ }
+
+ function nonNull(address _address) internal pure returns (address) {
+ require(_address != address(0), "Zero address");
+ return _address;
+ }
+
+ function revertBytes(bytes memory b) internal pure {
+ assembly ("memory-safe") {
+ revert(add(b, 0x20), mload(b))
+ }
+ }
+
+ // assert a condition. Assert should be used to assert an invariant that should be true
+ // logically.
+ // This is useful for readability and debugability. A failing assert is always a bug.
+ //
+ // In production builds (non-hardhat, and non-localhost deployments) this method is a noop.
+ //
+ // Use "require" to enforce requirements on data coming from outside of a contract. Ie.,
+ //
+ // ```solidity
+ // function nonNegativeX(int x) external { require(x >= 0, "non-negative"); }
+ // ```
+ //
+ // But
+ // ```solidity
+ // function nonNegativeX(int x) private { assert(x >= 0); }
+ // ```
+ //
+ // If a private function has a pre-condition that it should only be called with non-negative
+ // values it's a bug in the contract if it's called with a negative value.
+ // solhint-disable-next-line func-name-mixedcase
+ function Assert(bool cond) internal pure {
+ // BEGIN STRIP
+ assert(cond);
+ // END STRIP
+ }
+}
+
+/// @title Errors
+/// @notice Library containing all custom errors the protocol may revert with.
+library Errors {
+ /*//////////////////////////////////////////////////////////////////////////
+ GENERICS
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The address cannot be the zero address
+ error AddressZero();
+ /// @notice The signature is invalid
+ error InvalidSignature();
+ /// @notice Data does not match the expected format
+ error InvalidData();
+ /// @notice Nonce is out of range
+ error InvalidNonce();
+ /// @notice Nonce has already been used
+ error NonceAlreadyUsed();
+ /// @notice Deadline has expired
+ error DeadlineExpired();
+ /// @notice Only Supa can call this function
+ error OnlySupa();
+ /// @notice Only the owner or operator can call this function
+ error NotOwnerOrOperator();
+ /// @notice Only the owner can call this function
+ error OnlyOwner();
+ /// @notice Only this address can call this function
+ error OnlyThisAddress();
+ /// @notice Transfer failed
+ error TransferFailed();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC20
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ERC721
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The receiving address is not a contract
+ error ReceiverNotContract();
+ /// @notice The receiver does not implement the required interface
+ error ReceiverNoImplementation();
+ /// @notice The receiver did not return the correct value - transaction failed
+ error WrongDataReturned();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ ORACLES
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Borrow factor must be greater than zero
+ error InvalidBorrowFactor();
+/// @notice Chainlink price oracle must return a valid price (>0)
+ error InvalidPrice();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ SUPA
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice Sender is not approved to spend wallet erc20
+ error NotApprovedOrOwner();
+ /// @notice Sender is not the owner of the wallet;
+ /// @param sender The address of the sender
+ /// @param owner The address of the owner
+ error NotOwner(address sender, address owner);
+ /// @notice Transfer amount exceeds allowance
+ error InsufficientAllowance();
+ /// @notice Cannot approve self as spender
+ error SelfApproval();
+ /// @notice Asset is not an NFT
+ error NotNFT();
+ /// @notice NFT must be owned the the user or user's wallet
+ error NotNFTOwner();
+ /// @notice Operation leaves wallet insolvent
+ error Insolvent();
+ /// @notice Thrown if a wallet accumulates too many assets
+ error SolvencyCheckTooExpensive();
+ /// @notice Cannot withdraw debt
+ error CannotWithdrawDebt();
+ /// @notice Wallet is not liquidatable
+ error NotLiquidatable();
+ /// @notice There are insufficient reserves in the protocol for the debt
+ error InsufficientReserves();
+ /// @notice This operation would add too many tokens to the credit account
+ error TokenStorageExceeded();
+ /// @notice The address is not a registered ERC20
+ error NotERC20();
+ /// @notice `newOwner` is not the proposed new owner
+ /// @param proposedOwner The address of the proposed new owner
+ /// @param newOwner The address of the attempted new owner
+ error InvalidNewOwner(address proposedOwner, address newOwner);
+ /// @notice Only wallet can call this function
+ error OnlyWallet();
+ /// @notice Recipient is not a valid wallet
+ error WalletNonExistent();
+ /// @notice Asset is not registered
+ /// @param token The unregistered asset
+ error NotRegistered(address token);
+ /// @notice Thrown when the function is unimplemented
+ error NotImplemented();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ VERSION MANAGER
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /// @notice The implementation must be a contract
+ error InvalidImplementation();
+ /// @notice The version is deprecated
+ error DeprecatedVersion();
+ /// @notice The bug level is too high
+ error BugLevelTooHigh();
+ /// @notice Recommended Version does not exist
+ error NoRecommendedVersion();
+ /// @notice version is not registered
+ error VersionNotRegistered();
+ /// @notice Specified status is out of range
+ error InvalidStatus();
+ /// @notice Specified bug level is out of range
+ error InvalidBugLevel();
+ /// @notice version name cannot be the empty string
+ error InvalidVersionName();
+ /// @notice version is deprecated or has a bug
+ error InvalidVersion();
+ /// @notice version is already registered
+ error VersionAlreadyRegistered();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ TRANSFER AND CALL 2
+ //////////////////////////////////////////////////////////////////////////*/
+
+ error TransfersUnsorted();
+
+ error EthDoesntMatchWethTransfer();
+
+ error UnauthorizedOperator(address operator, address from);
+
+ error ExpiredPermit();
+}
+
+/// @title the state part of the WalletLogic. A parent to all contracts that form wallet
+/// @dev the contract is abstract because it is not expected to be used separately from wallet
+abstract contract WalletState {
+ modifier onlyOwner() {
+ require(msg.sender == supa.getWalletOwner(address(this)), "WalletState: only this");
+ _;
+ }
+
+ /// @dev Supa instance to be used by all other wallet contracts
+ ISupa public supa;
+
+ /// @param _supa - address of a deployed Supa contract
+ constructor(address _supa) {
+ // slither-disable-next-line missing-zero-check
+ supa = ISupa(FsUtils.nonNull(_supa));
+ }
+
+ /// @notice Point the wallet to a new Supa contract
+ /// @dev This function is only callable by the wallet itself
+ /// @param _supa - address of a deployed Supa contract
+ function updateSupa(address _supa) external onlyOwner {
+ // 1. Get the current wallet details
+ // 1a. Get the wallet owner
+ address currentOwner = supa.getWalletOwner(address(this));
+ // 1b. Get the current implementation
+ address implementation = supa.getImplementation(address(this));
+
+ // 2. Update the supa implementation
+ if (_supa == address(0) || _supa == address(supa)) {
+ revert Errors.AddressZero();
+ }
+ supa = ISupa(_supa);
+
+ // 3. Call the new supa to update the wallet owner
+ supa.migrateWallet(address(this), currentOwner, implementation);
+ }
+}
+
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
+
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
+
+/**
+ * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ */
+interface IERC20Permit {
+ /**
+ * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+ * given ``owner``'s signed approval.
+ *
+ * IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ * ordering also apply here.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `deadline` must be a timestamp in the future.
+ * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+ * over the EIP712-formatted function arguments.
+ * - the signature must use ``owner``'s current nonce (see {nonces}).
+ *
+ * For more information on the signature format, see the
+ * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+ * section].
+ */
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ /**
+ * @dev Returns the current nonce for `owner`. This value must be
+ * included whenever a signature is generated for {permit}.
+ *
+ * Every successful call to {permit} increases ``owner``'s nonce by one. This
+ * prevents a signature from being used multiple times.
+ */
+ function nonces(address owner) external view returns (uint256);
+
+ /**
+ * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function DOMAIN_SEPARATOR() external view returns (bytes32);
+}
+
+/**
+ * @title SafeERC20
+ * @dev Wrappers around ERC20 operations that throw on failure (when the token
+ * contract returns false). Tokens that return no value (and instead revert or
+ * throw on failure) are also supported, non-reverting calls are assumed to be
+ * successful.
+ * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
+ * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
+ */
+library SafeERC20 {
+ using Address for address;
+
+ function safeTransfer(
+ IERC20 token,
+ address to,
+ uint256 value
+ ) internal {
+ _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
+ }
+
+ function safeTransferFrom(
+ IERC20 token,
+ address from,
+ address to,
+ uint256 value
+ ) internal {
+ _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
+ }
+
+ /**
+ * @dev Deprecated. This function has issues similar to the ones found in
+ * {IERC20-approve}, and its usage is discouraged.
+ *
+ * Whenever possible, use {safeIncreaseAllowance} and
+ * {safeDecreaseAllowance} instead.
+ */
+ function safeApprove(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ // safeApprove should only be called when setting an initial allowance,
+ // or when resetting it to zero. To increase and decrease it, use
+ // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
+ require(
+ (value == 0) || (token.allowance(address(this), spender) == 0),
+ "SafeERC20: approve from non-zero to non-zero allowance"
+ );
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
+ }
+
+ function safeIncreaseAllowance(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ uint256 newAllowance = token.allowance(address(this), spender) + value;
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
+ }
+
+ function safeDecreaseAllowance(
+ IERC20 token,
+ address spender,
+ uint256 value
+ ) internal {
+ unchecked {
+ uint256 oldAllowance = token.allowance(address(this), spender);
+ require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
+ uint256 newAllowance = oldAllowance - value;
+ _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
+ }
+ }
+
+ function safePermit(
+ IERC20Permit token,
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal {
+ uint256 nonceBefore = token.nonces(owner);
+ token.permit(owner, spender, value, deadline, v, r, s);
+ uint256 nonceAfter = token.nonces(owner);
+ require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
+ }
+
+ /**
+ * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
+ * on the return value: the return value is optional (but if data is returned, it must not be false).
+ * @param token The token targeted by the call.
+ * @param data The call data (encoded using abi.encode or one of its variants).
+ */
+ function _callOptionalReturn(IERC20 token, bytes memory data) private {
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
+ // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
+ // the target address contains contract code and also asserts for success in the low-level call.
+
+ bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
+ if (returndata.length > 0) {
+ // Return data is optional
+ require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
+ }
+ }
+}
+
+// This address is in flux as long as the bytecode of this contract is not fixed. For now
+// we deploy it on local block chain on fixed address, when we go deploy this needs to change
+// to the permanent address.
+address constant TRANSFER_AND_CALL2 = address(0x1554b484D2392672F0375C56d80e91c1d070a007);
+
+// Contracts that implement can receive multiple ERC20 transfers in a single transaction,
+// with backwards compatibility for legacy ERC20's not implementing ERC677.
+abstract contract ITransferReceiver2 {
+ error InvalidSender(address sender);
+
+ struct Transfer {
+ address token;
+ uint256 amount;
+ }
+
+ /// @dev Called by a token to indicate a transfer into the callee
+ /// @param operator The account that initiated the transfer
+ /// @param from The account that has sent the token
+ /// @param transfers Transfers that have been made
+ /// @param data The extra data being passed to the receiving contract
+ function onTransferReceived2(
+ address operator,
+ address from,
+ Transfer[] calldata transfers,
+ bytes calldata data
+ ) external virtual returns (bytes4);
+
+ modifier onlyTransferAndCall2() {
+ if (msg.sender != TRANSFER_AND_CALL2) revert InvalidSender(msg.sender);
+ _;
+ }
+}
+
+// https://docs.uniswap.org/contracts/permit2/overview
+// https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3#code
+IPermit2 constant PERMIT2 = IPermit2(0x000000000022D473030F116dDEE9F6B43aC78BA3);
+
+// Minimal Permit2 interface, derived from
+// https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol
+interface IPermit2 {
+ // Token and amount in a permit message.
+ struct TokenPermissions {
+ // Token to transfer.
+ IERC20 token;
+ // Amount to transfer.
+ uint256 amount;
+ }
+
+ // The permit2 message.
+ struct PermitTransferFrom {
+ // Permitted token and amount.
+ TokenPermissions permitted;
+ // Unique identifier for this permit.
+ uint256 nonce;
+ // Expiration for this permit.
+ uint256 deadline;
+ }
+
+ // Transfer details for permitTransferFrom().
+ struct SignatureTransferDetails {
+ // Recipient of tokens.
+ address to;
+ // Amount to transfer.
+ uint256 requestedAmount;
+ }
+
+ // Consume a permit2 message and transfer tokens.
+ function permitTransferFrom(
+ PermitTransferFrom calldata permit,
+ SignatureTransferDetails calldata transferDetails,
+ address owner,
+ bytes calldata signature
+ ) external;
+}
+
+/// @title Wallet Proxy
+/// @notice Proxy contract for Supa Wallets
+// Inspired by TransparentUpdatableProxy
+contract WalletProxy is WalletState, Proxy {
+ modifier ifSupa() {
+ if (msg.sender == address(supa)) {
+ _;
+ } else {
+ _fallback();
+ }
+ }
+
+ constructor(
+ address _supa
+ ) WalletState(_supa) {
+ // solhint-disable-next-line no-empty-blocks
+ }
+
+ /// @dev Allow ETH transfers
+ receive() external payable override {}
+
+ // Allow Supa to make arbitrary calls in lieu of this wallet
+ function executeBatch(Execution[] calldata calls) external payable ifSupa {
+ // Function is payable to allow for ETH transfers to the logic
+ // contract, but supa should never send eth (supa contract should
+ // never contain eth / other than what's self-destructed into it)
+ FsUtils.Assert(msg.value == 0);
+ ExecutionLib.executeBatch(calls);
+ }
+
+ // The implementation of the delegate is controlled by Supa
+ function _implementation() internal view override returns (address) {
+ return supa.getImplementation(address(this));
+ }
+}
+
diff --git a/script/AddOperator.s.sol b/script/AddOperator.s.sol
index 31ff13c..6afa46a 100644
--- a/script/AddOperator.s.sol
+++ b/script/AddOperator.s.sol
@@ -4,7 +4,7 @@ pragma solidity ^0.8.19;
import {Script} from "forge-std/Script.sol";
import {GelatoOperator} from "src/periphery/GelatoOperator.sol";
import {WalletLogic} from "src/wallet/WalletLogic.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {Supa} from "src/supa/Supa.sol";
contract AddOperator is Script {
@@ -16,8 +16,12 @@ contract AddOperator is Script {
address operator = 0x8654202c6F3Ee519808488571D16398aF608f041;
vm.startBroadcast(deployerPrivateKey);
- Call[] memory calls = new Call[](1);
- calls[0] = Call({to: supa, callData: abi.encodeWithSelector(Supa.addOperator.selector, operator), value: 0});
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: supa,
+ value: 0,
+ callData: abi.encodeWithSelector(Supa.addOperator.selector, operator)
+ });
wallet.executeBatch(calls);
vm.stopBroadcast();
}
diff --git a/script/CreateGovernanceSafeCalls.s.sol b/script/CreateGovernanceSafeCalls.s.sol
index 0031995..4733f68 100644
--- a/script/CreateGovernanceSafeCalls.s.sol
+++ b/script/CreateGovernanceSafeCalls.s.sol
@@ -8,7 +8,7 @@ import {SupaState} from "src/supa/SupaState.sol";
import { GovernanceProxy } from "src/governance/GovernanceProxy.sol";
import { OffchainEntityProxy } from "src/governance/OffchainEntityProxy.sol";
-import { CallWithoutValue, Call } from "src/lib/Call.sol";
+import { CallWithoutValue, Call, Execution } from "src/lib/Call.sol";
contract CreateGovernanceSafeCalls is Script {
function run() external {
@@ -16,7 +16,7 @@ contract CreateGovernanceSafeCalls is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -25,7 +25,7 @@ contract CreateGovernanceSafeCalls is Script {
address governanceProxyAddress = vm.envAddress("GOVERNANCE_PROXY_ADDRESS");
address offchainEntityProxyAddress = vm.envAddress("OFFCHAIN_ENTITY_PROXY_ADDRESS");
- address newWalletLogicAddress = 0xA05f94DD5968DDCd1Dc89B942AeB3545341B8701;
+ address newWalletLogicAddress = 0xc8BA72D981EB73920c0fE3ba186C27b313B17B3A;
WalletLogic walletLogic = WalletLogic(newWalletLogicAddress);
@@ -52,9 +52,9 @@ contract CreateGovernanceSafeCalls is Script {
)
});
- Call[] memory offchainEntityCalls = new Call[](1);
- offchainEntityCalls[0] = Call({
- to: governanceProxyAddress,
+ Execution[] memory offchainEntityCalls = new Execution[](1);
+ offchainEntityCalls[0] = Execution({
+ target: governanceProxyAddress,
callData: abi.encodeWithSelector(
governanceProxy.executeBatch.selector,
governanceCalls
@@ -62,10 +62,19 @@ contract CreateGovernanceSafeCalls is Script {
value: 0
});
+ console.logBytes(abi.encodeWithSelector(
+ governanceProxy.executeBatch.selector,
+ governanceCalls
+ ));
+
console.logBytes(abi.encodeWithSelector(offchainEntityProxy.executeBatch.selector, offchainEntityCalls));
+ vm.startBroadcast(deployer);
+ offchainEntityProxy.executeBatch(offchainEntityCalls);
+ vm.stopBroadcast();
}
}
// forge script script/CreateGovernanceSafeCalls.s.sol:CreateGovernanceSafeCalls --rpc-url $GOERLI_RPC_URL -vvvv
-// forge script script/CreateGovernanceSafeCalls.s.sol:CreateGovernanceSafeCalls --rpc-url $ARBITRUM_RPC_URL -vvvv
\ No newline at end of file
+// forge script script/CreateGovernanceSafeCalls.s.sol:CreateGovernanceSafeCalls --rpc-url $ARBITRUM_RPC_URL -vvvv
+// forge script script/CreateGovernanceSafeCalls.s.sol:CreateGovernanceSafeCalls --rpc-url $BASE_RPC_URL -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/CreateWallet.s.sol b/script/CreateWallet.s.sol
new file mode 100644
index 0000000..7df019a
--- /dev/null
+++ b/script/CreateWallet.s.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+import {Script} from "forge-std/Script.sol";
+import {GelatoOperator} from "src/periphery/GelatoOperator.sol";
+import {WalletLogic} from "src/wallet/WalletLogic.sol";
+import {Execution} from "src/lib/Call.sol";
+import {SupaConfig} from "src/supa/SupaConfig.sol";
+
+contract CreateWallet is Script {
+ function run() external {
+ address deployer = vm.envAddress("DEPLOYER");
+
+ address payable supaAddress = payable(vm.envAddress("SUPA_ADDRESS"));
+ SupaConfig supa = SupaConfig(supaAddress);
+
+ vm.startBroadcast(deployer);
+ uint256 nonce = 1_000_000_000_000;
+ supa.createWallet(nonce);
+ vm.stopBroadcast();
+ }
+}
+
+// forge script script/CreateWallet.s.sol:CreateWallet --rpc-url $BASE_RPC_URL --broadcast -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
diff --git a/script/PayGasNative.s.sol b/script/PayGasNative.s.sol
index 440dddb..ee0e802 100644
--- a/script/PayGasNative.s.sol
+++ b/script/PayGasNative.s.sol
@@ -5,7 +5,7 @@ import {Script, console} from "forge-std/Script.sol";
import {TaskCreator, ITaskCreator} from "src/gelato/TaskCreator.sol";
import {TaskCreatorProxy} from "src/gelato/TaskCreatorProxy.sol";
-import {WalletProxy, Call} from "src/wallet/WalletProxy.sol";
+import {WalletProxy, Execution} from "src/wallet/WalletProxy.sol";
contract PayGasNative is Script {
function run() public virtual {
@@ -16,12 +16,12 @@ contract PayGasNative is Script {
vm.startBroadcast(supaWalletOwner);
TaskCreator taskCreator = TaskCreator(taskCreatorProxyAddress);
WalletProxy supaWallet = WalletProxy(payable(supaWalletAddress));
- Call[] memory calls = new Call[](1);
+ Execution[] memory calls = new Execution[](1);
uint256 gasAmount = 5733810;
- calls[0] = Call({
- to: taskCreatorProxyAddress,
- callData: abi.encodeWithSelector(taskCreator.payGasNative.selector, gasAmount),
- value: gasAmount
+ calls[0] = Execution({
+ target: taskCreatorProxyAddress,
+ value: gasAmount,
+ callData: abi.encodeWithSelector(taskCreator.payGasNative.selector, gasAmount)
});
supaWallet.executeBatch(calls);
vm.stopBroadcast();
diff --git a/script/data/GetTokenBalance.s.sol b/script/data/GetTokenBalance.s.sol
index 7274485..76b91af 100644
--- a/script/data/GetTokenBalance.s.sol
+++ b/script/data/GetTokenBalance.s.sol
@@ -7,14 +7,14 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract GetTokenBalance is Script {
function run() external {
- address walletAddress = 0x67B369866E376e532952F587D5ab84ad5033bB5E;
+ address walletAddress = 0x1f250e67A8D12D30E7605EeBC8bFdF7019D38cE0;
- IERC20 tokenAddress = IERC20(0x18e526F710B8d504A735927f5Eb8BdF2F4386811);
+ IERC20 tokenAddress = IERC20(0xB0057C0DeAB7eBCf45B520de7645c93A547d6A37);
uint256 balance = tokenAddress.balanceOf(walletAddress);
console.log('balance:', balance);
}
}
-// forge script script/data/GetTokenBalance.s.sol:GetTokenBalance --rpc-url $GOERLI_RPC_URL --broadcast -vvvv
+// forge script script/data/GetTokenBalance.s.sol:GetTokenBalance --rpc-url $BASE_RPC_URL --broadcast -vvvv
diff --git a/script/deploy/gelato/DeployTaskCreatorProxy.s.sol b/script/deploy/gelato/DeployTaskCreatorProxy.s.sol
index 9bb879b..aca867a 100644
--- a/script/deploy/gelato/DeployTaskCreatorProxy.s.sol
+++ b/script/deploy/gelato/DeployTaskCreatorProxy.s.sol
@@ -25,6 +25,9 @@ contract DeployTaskCreatorProxy is BaseScript {
} else if (chainId == 137) {
usdc = vm.envAddress("USDC_POLYGON");
deployer = vm.envAddress("DEPLOYER");
+ } else if (chainId == 8453) {
+ usdc = vm.envAddress("USDC_BASE");
+ deployer = vm.envAddress("DEPLOYER");
} else {
revert("DeployTaskCreatorProxy: unsupported chain");
}
@@ -46,3 +49,4 @@ contract DeployTaskCreatorProxy is BaseScript {
// forge script script/deploy/gelato/DeployTaskCreatorProxy.s.sol:DeployTaskCreatorProxy --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
// forge script script/deploy/gelato/DeployTaskCreatorProxy.s.sol:DeployTaskCreatorProxy --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
+// forge script script/deploy/gelato/DeployTaskCreatorProxy.s.sol:DeployTaskCreatorProxy --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
diff --git a/script/deploy/gelato/SetupTaskCreator.s.sol b/script/deploy/gelato/SetupTaskCreator.s.sol
index 265c2ec..c6371e9 100644
--- a/script/deploy/gelato/SetupTaskCreator.s.sol
+++ b/script/deploy/gelato/SetupTaskCreator.s.sol
@@ -33,6 +33,13 @@ contract SetupTaskCreator is BaseScript {
gasPriceFeed = vm.envAddress("GAS_PRICE_FEED_ARBITRUM");
powerCreditRate = 1e6; // 1 usdc
depositAmount = 5 ether; // 5 power credits
+ } else if (chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ usdc = vm.envAddress("USDC_BASE");
+ feeCollector = vm.envAddress("AUTOMATION_FEE_COLLECTOR_BASE");
+ gasPriceFeed = vm.envAddress("GAS_PRICE_FEED_BASE");
+ powerCreditRate = 1e6; // 1 usdc
+ depositAmount = 5 ether; // 5 power credits
} else {
revert("unsupported chain");
}
@@ -42,25 +49,23 @@ contract SetupTaskCreator is BaseScript {
address payable taskCreatorProxyAddress = payable(vm.envAddress("TASK_CREATOR_PROXY_ADDRESS"));
address allowlistServer = vm.envAddress("GELATO_SERVER");
vm.startBroadcast(deployer);
-// TaskCreator taskCreator = new TaskCreator(supa, automate, taskCreatorProxyAddress, usdc);
- TaskCreator taskCreator = TaskCreator(0x276c4e2D4B575Ff7A53A2d8922255434ec2363C4);
- TaskCreatorProxy taskCreatorProxy = TaskCreatorProxy(taskCreatorProxyAddress);
- taskCreatorProxy.upgrade(address(taskCreator));
+ TaskCreator taskCreator = TaskCreator(taskCreatorProxyAddress);
- TaskCreator(payable(address(taskCreatorProxy))).addAllowlistRole(allowlistServer);
- TaskCreator(payable(address(taskCreatorProxy))).setFeeCollector(feeCollector);
- TaskCreator(payable(address(taskCreatorProxy))).setGasPriceFeed(gasPriceFeed);
+ taskCreator.addAllowlistRole(allowlistServer);
+ taskCreator.setFeeCollector(feeCollector);
+ taskCreator.setGasPriceFeed(gasPriceFeed);
ITaskCreator.Tier[] memory tiers = new ITaskCreator.Tier[](1);
tiers[0] = ITaskCreator.Tier({
limit: 0,
rate: powerCreditRate
});
- TaskCreator(payable(address(taskCreatorProxy))).setTiers(tiers);
- TaskCreator(payable(address(taskCreatorProxy))).setDepositAmount(depositAmount);
- TaskCreator(payable(address(taskCreatorProxy))).setPowerPerExecution(powerPerExecution);
+ taskCreator.setTiers(tiers);
+ taskCreator.setDepositAmount(depositAmount);
+ taskCreator.setPowerPerExecution(powerPerExecution);
vm.stopBroadcast();
}
}
-// forge script script/deploy/gelato/SetupTaskCreator.s.sol:SetupTaskCreator --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/gelato/SetupTaskCreator.s.sol:SetupTaskCreator --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer -g 100
+// forge script script/deploy/gelato/SetupTaskCreator.s.sol:SetupTaskCreator --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer --etherscan-api-key $ETHERSCAN_API_KEY
+// forge script script/deploy/gelato/SetupTaskCreator.s.sol:SetupTaskCreator --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer -g 100 --etherscan-api-key $ARBISCAN_API_KEY
+// forge script script/deploy/gelato/SetupTaskCreator.s.sol:SetupTaskCreator --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
diff --git a/script/deploy/gelato/UpgradeTaskCreator.s.sol b/script/deploy/gelato/UpgradeTaskCreator.s.sol
index 3b22205..9f4db88 100644
--- a/script/deploy/gelato/UpgradeTaskCreator.s.sol
+++ b/script/deploy/gelato/UpgradeTaskCreator.s.sol
@@ -36,4 +36,4 @@ contract UpgradeTaskCreator is BaseScript {
}
// forge script script/deploy/gelato/UpgradeTaskCreator.s.sol:UpgradeTaskCreator --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/gelato/UpgradeTaskCreator.s.sol:UpgradeTaskCreator --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer -g 100
+// forge script script/deploy/gelato/UpgradeTaskCreator.s.sol:UpgradeTaskCreator --rpc-url $ARBITRUM_RPC_URL --broadcast --verify --etherscan-api-key $ARBISCAN_API_KEY -vvvv --account supa_deployer -g 100
diff --git a/script/deploy/governance/GovernanceProxy.s.sol b/script/deploy/governance/GovernanceProxy.s.sol
index f26b4fc..396b34e 100644
--- a/script/deploy/governance/GovernanceProxy.s.sol
+++ b/script/deploy/governance/GovernanceProxy.s.sol
@@ -10,7 +10,7 @@ contract DeployGovernanceProxy is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -28,4 +28,6 @@ contract DeployGovernanceProxy is Script {
// forge script script/deploy/governance/GovernanceProxy.s.sol:DeployGovernanceProxy --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/governance/GovernanceProxy.s.sol:DeployGovernanceProxy --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer -g 100
+// forge script script/deploy/governance/GovernanceProxy.s.sol:DeployGovernanceProxy --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY -g 100
+
+// forge script script/deploy/governance/GovernanceProxy.s.sol:DeployGovernanceProxy --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/deploy/governance/OffchainEntityProxy.s.sol b/script/deploy/governance/OffchainEntityProxy.s.sol
index 72aebcf..a4e8ffe 100644
--- a/script/deploy/governance/OffchainEntityProxy.s.sol
+++ b/script/deploy/governance/OffchainEntityProxy.s.sol
@@ -10,7 +10,7 @@ contract DeployOffchainEntityProxy is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -29,4 +29,6 @@ contract DeployOffchainEntityProxy is Script {
// forge script script/deploy/governance/OffchainEntityProxy.s.sol:DeployOffchainEntityProxy --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer --verify
-// forge script script/deploy/governance/OffchainEntityProxy.s.sol:DeployOffchainEntityProxy --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer --verify -g 100
+// forge script script/deploy/governance/OffchainEntityProxy.s.sol:DeployOffchainEntityProxy --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer --verify --etherscan-api-key $ARBISCAN_API_KEY -g 100
+
+// forge script script/deploy/governance/OffchainEntityProxy.s.sol:DeployOffchainEntityProxy --rpc-url $BASE_RPC_URL --broadcast -vvvv --account supa_deployer --verify --etherscan-api-key $BASESCAN_API_KEY
diff --git a/script/deploy/oracles/UniV3Oracle.s.sol b/script/deploy/oracles/UniV3Oracle.s.sol
index 2480e7a..25f95cf 100644
--- a/script/deploy/oracles/UniV3Oracle.s.sol
+++ b/script/deploy/oracles/UniV3Oracle.s.sol
@@ -9,25 +9,34 @@ contract DeployUniV3Oracle is Script {
function run() external {
uint256 chainId = block.chainid;
address deployer;
+ address manager;
+ address factory;
+ address owner;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
+ address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
+ address factory = vm.envAddress("UNISWAP_V3_FACTORY");
} else if (chainId == 42161) {
deployer = vm.envAddress("DEPLOYER");
+ address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
+ address factory = vm.envAddress("UNISWAP_V3_FACTORY");
+ } else if (chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER_BASE");
+ factory = vm.envAddress("UNISWAP_V3_FACTORY_BASE");
} else {
revert("unsupported chain");
}
- address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
- address factory = vm.envAddress("UNISWAP_V3_FACTORY");
- address owner = vm.envAddress("DEPLOYER");
bytes32 salt = 0x1234567890098765432112345678900987654321123456789009876543211234;
vm.startBroadcast(deployer);
// new UniV3Oracle(factory, manager, owner);
- new UniV3Oracle{salt: salt}(factory, manager, owner);
+ new UniV3Oracle{salt: salt}(factory, manager, deployer);
vm.stopBroadcast();
}
}
// forge script script/deploy/oracles/UniV3Oracle.s.sol:DeployUniV3Oracle --rpc-url $GOERLI_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/oracles/UniV3Oracle.s.sol:DeployUniV3Oracle --rpc-url $ARBITRUM_RPC_URL --broadcast --etherscan-api-key $ARBISCAN_API_KEY --verify -vvvv --account supa_deployer
\ No newline at end of file
+// forge script script/deploy/oracles/UniV3Oracle.s.sol:DeployUniV3Oracle --rpc-url $ARBITRUM_RPC_URL --broadcast --etherscan-api-key $ARBISCAN_API_KEY --verify -vvvv --account supa_deployer
+// forge script script/deploy/oracles/UniV3Oracle.s.sol:DeployUniV3Oracle --rpc-url $BASE_RPC_URL --broadcast --etherscan-api-key $BASESCAN_API_KEY --verify -vvvv --account supa_deployer --with-gas-price 1000000
\ No newline at end of file
diff --git a/script/deploy/oracles/UniswapV3PositionUtility.s.sol b/script/deploy/oracles/UniswapV3PositionUtility.s.sol
index bcfadb3..8557011 100644
--- a/script/deploy/oracles/UniswapV3PositionUtility.s.sol
+++ b/script/deploy/oracles/UniswapV3PositionUtility.s.sol
@@ -1,29 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {Script} from "forge-std/Script.sol";
+import {Script, console} from "forge-std/Script.sol";
import {Supa} from "src/supa/Supa.sol";
import {UniswapV3PositionUtility} from "src/oracles/UniswapV3PositionUtility.sol";
contract DeployUniswapV3PositionUtility is Script {
function run() external {
uint256 chainId = block.chainid;
+ console.logUint(chainId);
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
}
- bytes32 salt = 0x1234567890098765432112345678900987654321123456789009876543211234;
+ console.logAddress(deployer);
+
+ bytes32 salt = vm.envBytes32("SUPA_SALT");
vm.startBroadcast(deployer);
- new UniswapV3PositionUtility{salt: salt}();
+ UniswapV3PositionUtility uniswapV3PositionUtility = new UniswapV3PositionUtility{salt: salt}();
+ console.log("UniswapV3PositionUtility deployed at:", address(uniswapV3PositionUtility));
vm.stopBroadcast();
}
}
// forge script script/deploy/oracles/UniswapV3PositionUtility.s.sol:DeployUniswapV3PositionUtility --rpc-url $GOERLI_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/oracles/UniswapV3PositionUtility.s.sol:DeployUniswapV3PositionUtility --rpc-url $ARBITRUM_RPC_URL --broadcast --etherscan-api-key $ARBISCAN_API_KEY --verify -vvvv --account supa_deployer
\ No newline at end of file
+// forge script script/deploy/oracles/UniswapV3PositionUtility.s.sol:DeployUniswapV3PositionUtility --rpc-url $ARBITRUM_RPC_URL --broadcast --etherscan-api-key $ARBISCAN_API_KEY --verify -vvvv --account supa_deployer
+// forge script script/deploy/oracles/UniswapV3PositionUtility.s.sol:DeployUniswapV3PositionUtility --rpc-url $BASE_RPC_URL --broadcast --etherscan-api-key $BASESCAN_API_KEY --verify -vvvv --account supa_deployer --with-gas-price 1000000
\ No newline at end of file
diff --git a/script/deploy/periphery/gelatoOperator.s.sol b/script/deploy/periphery/gelatoOperator.s.sol
index 166b547..f6edc27 100644
--- a/script/deploy/periphery/gelatoOperator.s.sol
+++ b/script/deploy/periphery/gelatoOperator.s.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {Script} from "forge-std/Script.sol";
+import {Script, console} from "forge-std/Script.sol";
import {GelatoOperator} from "src/periphery/GelatoOperator.sol";
contract DeployGelatoOperator is Script {
@@ -11,7 +11,7 @@ contract DeployGelatoOperator is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -20,10 +20,15 @@ contract DeployGelatoOperator is Script {
vm.startBroadcast(deployer);
GelatoOperator gelatoOperator = new GelatoOperator{salt: salt}(dedicatedSender);
vm.stopBroadcast();
+ console.log("GelatoOperator deployed at:", address(gelatoOperator));
assert(address(gelatoOperator) == vm.envAddress("GELATO_OPERATOR_ADDRESS"));
}
}
-// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer
+// cast create2 --init-code-hash $GELATO_OPERATOR_INIT_CODE_HASH --starts-with 0x00000000
-// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer -g 100
+// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer --verify
+
+// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer -g 100 --verify --etherscan-api-key $ARBISCAN_API_KEY
+
+// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $BASE_RPC_URL --broadcast -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY --verify
diff --git a/script/deploy/periphery/proxiedOperator.s.sol b/script/deploy/periphery/proxiedOperator.s.sol
new file mode 100644
index 0000000..6105930
--- /dev/null
+++ b/script/deploy/periphery/proxiedOperator.s.sol
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+import {Script} from "forge-std/Script.sol";
+import {ProxiedOperator} from "src/periphery/ProxiedOperator.sol";
+
+contract DeployProxiedOperator is Script {
+ function run() external {
+ uint256 chainId = block.chainid;
+ address deployer;
+ address dedicatedSender;
+ address supaAdmin;
+ if (chainId == 5) {
+ deployer = vm.envAddress("DEPLOYER_GOERLI");
+ revert("Add deployer and dedicatedSender");
+ } else if (chainId == 42161) {
+ deployer = vm.envAddress("DEPLOYER");
+ dedicatedSender = 0xFB850ffad5349F4c8457EA8909F12BA3d63578F8;
+ supaAdmin = vm.envAddress("SUPA_ADMIN_ARBITRUM");
+ } else if (chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ dedicatedSender = 0xFB850ffad5349F4c8457EA8909F12BA3d63578F8;
+ supaAdmin = vm.envAddress("SUPA_ADMIN_BASE");
+ } else {
+ revert("unsupported chain");
+ }
+
+ vm.startBroadcast(deployer);
+ new ProxiedOperator(dedicatedSender, supaAdmin);
+ vm.stopBroadcast();
+ }
+}
+
+// cast create2 --init-code-hash $PROXIED_OPERATOR_INIT_CODE_HASH --starts-with 0x00000000
+
+// forge script script/deploy/periphery/proxiedOperator.s.sol:DeployProxiedOperator --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer --verify
+
+// forge script script/deploy/periphery/proxiedOperator.s.sol:DeployProxiedOperator --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer -g 100 --etherscan-api-key $ARBISCAN_API_KEY --verify
+
+// forge script script/deploy/periphery/proxiedOperator.s.sol:DeployProxiedOperator --rpc-url $BASE_RPC_URL --broadcast -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY --verify
diff --git a/script/deploy/periphery/uniV3LPHelper.s.sol b/script/deploy/periphery/uniV3LPHelper.s.sol
index b511f0d..1b6ed70 100644
--- a/script/deploy/periphery/uniV3LPHelper.s.sol
+++ b/script/deploy/periphery/uniV3LPHelper.s.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {Script} from "forge-std/Script.sol";
+import {Script, console} from "forge-std/Script.sol";
import {Supa} from "src/supa/Supa.sol";
import {UniV3LPHelper} from "src/periphery/UniV3LPHelper.sol";
@@ -9,23 +9,56 @@ contract DeployUniV3LPHelper is Script {
function run() external {
uint256 chainId = block.chainid;
address deployer;
+ address manager;
+ address factory;
+ address swapRouter;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
+ address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
+ address factory = vm.envAddress("UNISWAP_V3_FACTORY");
+ address swapRouter = vm.envAddress("SWAP_ROUTER");
} else if (chainId == 42161) {
deployer = vm.envAddress("DEPLOYER");
+ address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
+ address factory = vm.envAddress("UNISWAP_V3_FACTORY");
+ address swapRouter = vm.envAddress("SWAP_ROUTER");
+ } else if (chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER_BASE");
+ factory = vm.envAddress("UNISWAP_V3_FACTORY_BASE");
+ swapRouter = vm.envAddress("SWAP_ROUTER_BASE");
} else {
revert("unsupported chain");
}
- address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
- address factory = vm.envAddress("UNISWAP_V3_FACTORY");
- address swapRouter = vm.envAddress("SWAP_ROUTER");
- bytes32 salt = vm.envBytes32("UNI_V3_LP_HELPER_SALT");
+// bytes32 salt = vm.envBytes32("UNI_V3_LP_HELPER_SALT");
+ bytes32 salt = 0xaac462e10f7324d89705c8590b850551de1d0e8091dddd90ac8ee5a86edcd9d8;
+ console.log(chainId);
+ console.logBytes32(salt);
vm.startBroadcast(deployer);
+ console.logAddress(manager);
+ console.logAddress(factory);
+ console.logAddress(swapRouter);
+ // Encode the constructor arguments
+ bytes memory encodedArgs = abi.encode(manager, factory, swapRouter);
+
+ // Append the encoded arguments to the bytecode
+ bytes memory bytecode = abi.encodePacked(type(UniV3LPHelper).creationCode, encodedArgs);
+
+ // Calculate the hash
+ bytes32 hash = keccak256(bytecode);
+ console.logBytes32(hash);
+
UniV3LPHelper uniV3LpHelper = new UniV3LPHelper{salt: salt}(manager, factory, swapRouter);
+ console.logAddress(address(uniV3LpHelper));
+ console.logAddress(vm.envAddress("UNI_V3_LP_HELPER_ADDRESS"));
assert(address(uniV3LpHelper) == vm.envAddress("UNI_V3_LP_HELPER_ADDRESS"));
vm.stopBroadcast();
}
}
+// cast create2 --init-code-hash $UNI_V3_LP_HELPER_INIT_CODE_HASH --starts-with 0x00000000
+// cast create2 --init-code-hash 0xace5ed67e4f3bf57d127da893a1695d6132151f7bae028058cdc82893d90bfb8 --starts-with 0x00000000
+
// forge script script/deploy/periphery/uniV3LPHelper.s.sol:DeployUniV3LPHelper --rpc-url $GOERLI_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY -vvvv --account supa_test_deployer
// forge script script/deploy/periphery/uniV3LPHelper.s.sol:DeployUniV3LPHelper --rpc-url $ARBITRUM_RPC_URL --broadcast --etherscan-api-key $ARBISCAN_API_KEY -vvvv --account supa_deployer
+// forge script script/deploy/periphery/uniV3LPHelper.s.sol:DeployUniV3LPHelper --rpc-url $BASE_RPC_URL --broadcast --etherscan-api-key $BASESCAN_API_KEY -vvvv --account supa_deployer --verify --with-gas-price 1000000
diff --git a/script/deploy/supa/Supa.s.sol b/script/deploy/supa/Supa.s.sol
index 06b29af..992d1e5 100644
--- a/script/deploy/supa/Supa.s.sol
+++ b/script/deploy/supa/Supa.s.sol
@@ -10,7 +10,7 @@ contract DeploySupa is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -25,8 +25,14 @@ contract DeploySupa is Script {
}
}
-// cast create2 --init-code-hash $SUPA_CONFIG_INIT_CODE_HASH --starts-with 0xB0057ED0 --case-sensitive
+// cast create2 --init-code-hash $SUPA_INIT_CODE_HASH --starts-with 0xB0057ED0 --case-sensitive
// forge script script/deploy/supa/Supa.s.sol:DeploySupa --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/supa/Supa.s.sol:DeploySupa --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
+// forge script script/deploy/supa/Supa.s.sol:DeploySupa --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY
+
+// forge script script/deploy/supa/Supa.s.sol:DeploySupa --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
+
+// forge verify-contract 0xB0057ED0100643b4B2852799A3c3fed33947D47C Supa --constructor-args 0x00000000000000000000000000000000057d45faed7f49ba69472321b7e0901d000000000000000000000000000000009b648aa9453e3bbd236adb2982aa65b1 --chain 8453 --etherscan-api-key $BASESCAN_API_KEY --verifier etherscan
+
+// forge verify-contract 0xB0057ED0100643b4B2852799A3c3fed33947D47C Supa --constructor-args 0x00000000000000000000000000000000057d45faed7f49ba69472321b7e0901d000000000000000000000000000000009b648aa9453e3bbd236adb2982aa65b1 --chain 42161 --etherscan-api-key $ARBISCAN_API_KEY --verifier etherscan
\ No newline at end of file
diff --git a/script/deploy/supa/SupaConfig.s.sol b/script/deploy/supa/SupaConfig.s.sol
index 833ee82..e57312d 100644
--- a/script/deploy/supa/SupaConfig.s.sol
+++ b/script/deploy/supa/SupaConfig.s.sol
@@ -11,7 +11,7 @@ contract DeploySupaConfig is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -25,8 +25,13 @@ contract DeploySupaConfig is Script {
}
}
-// cast create2 --init-code-hash $SUPA_CONFIG_INIT_CODE_HASH --starts-with 0x000000000
+// cast create2 --init-code-hash $SUPA_CONFIG_INIT_CODE_HASH --starts-with 0x00000000
// forge script script/deploy/supa/SupaConfig.s.sol:DeploySupaConfig --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/supa/SupaConfig.s.sol:DeploySupaConfig --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
+// forge script script/deploy/supa/SupaConfig.s.sol:DeploySupaConfig --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY
+
+// forge script script/deploy/supa/SupaConfig.s.sol:DeploySupaConfig --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
+
+// forge verify-contract 0x00000000057D45fAed7F49ba69472321b7E0901d SupaConfig --constructor-args 0x000000000000000000000000dec1dee9deb6962f8f2493cbd7c5be6588c93c44 --chain 8453 --etherscan-api-key $BASESCAN_API_KEY --verifier etherscan
+// forge verify-contract 0x00000000057D45fAed7F49ba69472321b7E0901d SupaConfig --constructor-args 0x000000000000000000000000dec1dee9deb6962f8f2493cbd7c5be6588c93c44 --chain 42161 --etherscan-api-key $ARBISCAN_API_KEY --verifier etherscan
\ No newline at end of file
diff --git a/script/deploy/supa/VersionManager.s.sol b/script/deploy/supa/VersionManager.s.sol
index cac4846..e66c418 100644
--- a/script/deploy/supa/VersionManager.s.sol
+++ b/script/deploy/supa/VersionManager.s.sol
@@ -10,7 +10,7 @@ contract DeployVersionManager is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -29,4 +29,6 @@ contract DeployVersionManager is Script {
// forge script script/deploy/supa/VersionManager.s.sol:DeployVersionManager --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/deploy/supa/VersionManager.s.sol:DeployVersionManager --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer -g 100
\ No newline at end of file
+// forge script script/deploy/supa/VersionManager.s.sol:DeployVersionManager --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY -g 100
+
+// forge script script/deploy/supa/VersionManager.s.sol:DeployVersionManager --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/deploy/wallet/WalletLogic.s.sol b/script/deploy/wallet/WalletLogic.s.sol
index b88cc87..ee7edd2 100644
--- a/script/deploy/wallet/WalletLogic.s.sol
+++ b/script/deploy/wallet/WalletLogic.s.sol
@@ -12,7 +12,7 @@ contract DeployWalletLogic is Script {
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -29,4 +29,5 @@ contract DeployWalletLogic is Script {
}
// forge script script/deploy/wallet/WalletLogic.s.sol:DeployWalletLogic --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer
-// forge script script/deploy/wallet/WalletLogic.s.sol:DeployWalletLogic --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY
\ No newline at end of file
+// forge script script/deploy/wallet/WalletLogic.s.sol:DeployWalletLogic --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY
+// forge script script/deploy/wallet/WalletLogic.s.sol:DeployWalletLogic --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/initCode/Governance.sol b/script/initCode/governance/Governance.sol
similarity index 100%
rename from script/initCode/Governance.sol
rename to script/initCode/governance/Governance.sol
diff --git a/script/initCode/GovernanceProxy.s.sol b/script/initCode/governance/GovernanceProxy.s.sol
similarity index 88%
rename from script/initCode/GovernanceProxy.s.sol
rename to script/initCode/governance/GovernanceProxy.s.sol
index daa0d67..b40d27a 100644
--- a/script/initCode/GovernanceProxy.s.sol
+++ b/script/initCode/governance/GovernanceProxy.s.sol
@@ -20,4 +20,4 @@ contract InitCodeHashGovernanceProxy is Script {
}
}
-// forge script script/initCode/GovernanceProxy.s.sol:InitCodeHashGovernanceProxy -vvvv
+// forge script script/initCode/governance/GovernanceProxy.s.sol:InitCodeHashGovernanceProxy -vvvv
diff --git a/script/initCode/OffchainEntityProxy.s.sol b/script/initCode/governance/OffchainEntityProxy.s.sol
similarity index 89%
rename from script/initCode/OffchainEntityProxy.s.sol
rename to script/initCode/governance/OffchainEntityProxy.s.sol
index d1805d1..ac7cea6 100644
--- a/script/initCode/OffchainEntityProxy.s.sol
+++ b/script/initCode/governance/OffchainEntityProxy.s.sol
@@ -22,5 +22,5 @@ contract InitCodeHashOffchainEntityProxy is Script {
}
}
-// forge script script/initCode/OffchainEntityProxy.s.sol:InitCodeHashOffchainEntityProxy -vvvv
+// forge script script/initCode/governance/OffchainEntityProxy.s.sol:InitCodeHashOffchainEntityProxy -vvvv
diff --git a/script/initCode/periphery/ProxiedOperator.s.sol b/script/initCode/periphery/ProxiedOperator.s.sol
new file mode 100644
index 0000000..4a4310a
--- /dev/null
+++ b/script/initCode/periphery/ProxiedOperator.s.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+import {Script, console} from "forge-std/Script.sol";
+import {ProxiedOperator} from "src/periphery/ProxiedOperator.sol";
+
+contract InitCodeHashProxiedOperator is Script {
+ function run() external {
+ uint256 chainId = block.chainid;
+
+ // Append the encoded arguments to the bytecode
+ bytes memory bytecode = abi.encodePacked(type(ProxiedOperator).creationCode);
+
+ // Calculate the hash
+ bytes32 hash = keccak256(bytecode);
+ console.logBytes32(hash);
+ }
+}
+
+// forge script script/initCode/periphery/ProxiedOperator.s.sol:InitCodeHashProxiedOperator -vvvv
+
diff --git a/script/initCode/periphery/UniV3LPHelper.s.sol b/script/initCode/periphery/UniV3LPHelper.s.sol
index f6a4abc..49a5679 100644
--- a/script/initCode/periphery/UniV3LPHelper.s.sol
+++ b/script/initCode/periphery/UniV3LPHelper.s.sol
@@ -6,9 +6,27 @@ import {UniV3LPHelper} from "src/periphery/UniV3LPHelper.sol";
contract InitCodeHashUniV3LPHelper is Script {
function run() external {
- address manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
- address factory = vm.envAddress("UNISWAP_V3_FACTORY");
- address swapRouter = vm.envAddress("SWAP_ROUTER");
+ address manager;
+ address factory;
+ address swapRouter;
+
+ uint256 chainId = block.chainid;
+ console.logUint(chainId);
+ if (chainId == 8453) {
+ manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER_BASE");
+ factory = vm.envAddress("UNISWAP_V3_FACTORY_BASE");
+ swapRouter = vm.envAddress("SWAP_ROUTER_BASE");
+ } else if (chainId == 1 || chainId == 5 || chainId == 42161) {
+ manager = vm.envAddress("NONFUNGIBLE_POSITION_MANAGER");
+ factory = vm.envAddress("UNISWAP_V3_FACTORY");
+ swapRouter = vm.envAddress("SWAP_ROUTER");
+ } else {
+ revert("unsupported chain");
+ }
+
+ console.logAddress(manager);
+ console.logAddress(factory);
+ console.logAddress(swapRouter);
// Encode the constructor arguments
bytes memory encodedArgs = abi.encode(manager, factory, swapRouter);
@@ -22,5 +40,5 @@ contract InitCodeHashUniV3LPHelper is Script {
}
}
-// forge script script/initCode/periphery/UniV3LPHelper.s.sol:InitCodeHashUniV3LPHelper -vvvv
+// forge script script/initCode/periphery/UniV3LPHelper.s.sol:InitCodeHashUniV3LPHelper -vvvv --rpc-url $BASE_RPC_URL
diff --git a/script/setup/AddAdmin.s.sol b/script/setup/AddAdmin.s.sol
index 201c882..073eb7f 100644
--- a/script/setup/AddAdmin.s.sol
+++ b/script/setup/AddAdmin.s.sol
@@ -9,27 +9,28 @@ contract AddAdmin is Script {
function run() public virtual {
uint256 chainId = block.chainid;
address payable taskCreatorProxyAddress = payable(vm.envAddress("TASK_CREATOR_PROXY_ADDRESS"));
- address supaBetaProxyAddress = vm.envAddress("SUPA_BETA_PROXY_ADDRESS");
+// address supaBetaProxyAddress = vm.envAddress("SUPA_BETA_PROXY_ADDRESS");
address deployer;
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
}
- address user = 0x6a48800cDA5cf661fE7C5E081Fd3831f3C1Ac8E6;
+ address user = 0xDf048196C83A83eFE5A56fEd1A577b65388e09d0;
- SupaBeta supaBeta = SupaBeta(supaBetaProxyAddress);
+// SupaBeta supaBeta = SupaBeta(supaBetaProxyAddress);
TaskCreator taskCreator = TaskCreator(taskCreatorProxyAddress);
vm.startBroadcast(deployer);
- supaBeta.setMinter(user, true);
+// supaBeta.setMinter(user, true);
taskCreator.addAllowlistRole(user);
vm.stopBroadcast();
}
}
// forge script script/setup/AddBetaUser.s.sol:AddBetaUser --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/setup/AddAdmin.s.sol:AddAdmin --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
\ No newline at end of file
+// forge script script/setup/AddAdmin.s.sol:AddAdmin --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
+// forge script script/setup/AddAdmin.s.sol:AddAdmin --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/setup/gelato/SetDepositAmount.s.sol b/script/setup/gelato/SetDepositAmount.s.sol
index 1483a21..726e2df 100644
--- a/script/setup/gelato/SetDepositAmount.s.sol
+++ b/script/setup/gelato/SetDepositAmount.s.sol
@@ -14,7 +14,7 @@ contract SetDepositAmount is Script {
if (chainId == 5) {
deployer = vm.envAddress("DEPLOYER_GOERLI");
depositAmount = 0.001 ether * 60;
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
deployer = vm.envAddress("DEPLOYER");
depositAmount = 0.001 ether * 60;
} else {
@@ -28,4 +28,6 @@ contract SetDepositAmount is Script {
}
}
-// forge script script/setup/gelato/SetDepositAmount.s.sol:SetDepositAmount --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
+// forge script script/setup/gelato/SetDepositAmount.s.sol:SetDepositAmount --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer --etherscan-api-key $GOERLISCAN_API_KEY
+// forge script script/setup/gelato/SetDepositAmount.s.sol:SetDepositAmount --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $ARBISCAN_API_KEY
+// forge script script/setup/gelato/SetDepositAmount.s.sol:SetDepositAmount --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
diff --git a/script/setup/gelato/SetGasPriceFeed.s.sol b/script/setup/gelato/SetGasPriceFeed.s.sol
index 4d59147..1a1a1e0 100644
--- a/script/setup/gelato/SetGasPriceFeed.s.sol
+++ b/script/setup/gelato/SetGasPriceFeed.s.sol
@@ -17,6 +17,9 @@ contract SetFeeCollector is Script {
} else if (chainId == 42161) {
deployer = vm.envAddress("DEPLOYER");
gasPriceFeed = vm.envAddress("AUTOMATION_FEE_COLLECTOR_ARBITRUM");
+ } else if (chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ gasPriceFeed = vm.envAddress("AUTOMATION_FEE_COLLECTOR_BASE");
} else {
revert("unsupported chain");
}
diff --git a/script/setup/governance/OffchainEntityProxy.transferOwnership.s.sol b/script/setup/governance/OffchainEntityProxy.transferOwnership.s.sol
index c0536c7..a94a6de 100644
--- a/script/setup/governance/OffchainEntityProxy.transferOwnership.s.sol
+++ b/script/setup/governance/OffchainEntityProxy.transferOwnership.s.sol
@@ -7,7 +7,14 @@ import {OffchainEntityProxy} from "src/governance/OffchainEntityProxy.sol";
contract TransferOwnership is Script {
function run() external {
address deployer = vm.envAddress("DEPLOYER");
- address newOwner = vm.envAddress("SUPA_ADMIN");
+ address newOwner;
+ if (block.chainid == 5) {
+ newOwner = vm.envAddress("SUPA_ADMIN_GOERLI");
+ } else if (block.chainid == 8453) {
+ newOwner = vm.envAddress("SUPA_ADMIN_BASE");
+ } else {
+ revert("unsupported chain");
+ }
vm.startBroadcast(deployer);
OffchainEntityProxy offchainEntityProxy = OffchainEntityProxy(vm.envAddress("OFFCHAIN_ENTITY_PROXY_ADDRESS"));
diff --git a/script/setup/increasePowerCredits.s.sol b/script/setup/increasePowerCredits.s.sol
index 3f42076..a07f555 100644
--- a/script/setup/increasePowerCredits.s.sol
+++ b/script/setup/increasePowerCredits.s.sol
@@ -7,11 +7,23 @@ import {TaskCreator} from "src/gelato/TaskCreator.sol";
contract IncreasePowerCredits is Script {
function run() public virtual {
address payable taskCreatorProxyAddress = payable(vm.envAddress("TASK_CREATOR_PROXY_ADDRESS"));
- address owner = 0xc9B6088732E83ef013873e2f04d032F1a7a2E42D;
+ uint256 chainId = block.chainid;
+ address deployer;
+ if (chainId == 5) {
+ deployer = vm.envAddress("DEPLOYER_GOERLI");
+ } else if (chainId == 42161 || chainId == 8453) {
+ deployer = vm.envAddress("DEPLOYER");
+ } else {
+ revert("unsupported chain");
+ }
// address user = 0x4141EC9F8Acfd636E7b037EB3171f4452656dA35; // Parker
- address user = 0x8E292FE20ee2BDf29B4BC7c104641b59eAEFf457; // Derek
+// address user = 0x8E292FE20ee2BDf29B4BC7c104641b59eAEFf457; // Derek
+ address user = 0x0F4eab37086338bE99a7C895191F31c8960Eb1CB;
- vm.startBroadcast(owner);
+// address user = 0xFB850ffad5349F4c8457EA8909F12BA3d63578F8; // base frame deployer
+
+// address user = 0xa9cE598b9286ACECF2E495D663FaA611256910F1;
+ vm.startBroadcast(deployer);
TaskCreator taskCreator = TaskCreator(taskCreatorProxyAddress);
taskCreator.adminIncreasePower(user, 50 ether);
vm.stopBroadcast();
@@ -19,4 +31,5 @@ contract IncreasePowerCredits is Script {
}
// forge script script/setup/increasePowerCredits.s.sol:IncreasePowerCredits --rpc-url $GOERLI_RPC_URL --broadcast --verify -vvvv --account supa_test_deployer
-// forge script script/setup/increasePowerCredits.s.sol:IncreasePowerCredits --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
\ No newline at end of file
+// forge script script/setup/increasePowerCredits.s.sol:IncreasePowerCredits --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -vvvv --account supa_deployer
+// forge script script/setup/increasePowerCredits.s.sol:IncreasePowerCredits --rpc-url $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY
\ No newline at end of file
diff --git a/script/setupSupa.s.sol b/script/setupSupa.s.sol
index 8f4ae92..8e258b2 100644
--- a/script/setupSupa.s.sol
+++ b/script/setupSupa.s.sol
@@ -13,7 +13,7 @@ import { WalletLogic } from "src/wallet/WalletLogic.sol";
import {MockERC20Oracle } from "src/testing/MockERC20Oracle.sol";
import {UniV3Oracle} from "src/oracles/UniV3Oracle.sol";
-import {Call, CallWithoutValue} from "src/lib/Call.sol";
+import {Execution, CallWithoutValue} from "src/lib/Call.sol";
contract SetupSupa is Script {
function run() external {
@@ -23,7 +23,7 @@ contract SetupSupa is Script {
address owner;
if (chainId == 5) {
owner = vm.envAddress("OWNER_GOERLI");
- } else if (chainId == 42161) {
+ } else if (chainId == 42161 || chainId == 8453) {
owner = vm.envAddress("DEPLOYER");
} else {
revert("unsupported chain");
@@ -60,20 +60,20 @@ contract SetupSupa is Script {
erc721Multiplier: 5
});
- CallWithoutValue[] memory governanceCalls = new CallWithoutValue[](4);
+ CallWithoutValue[] memory governanceCalls = new CallWithoutValue[](2);
+// governanceCalls[0] = CallWithoutValue({
+// to: address(versionManager),
+// callData: abi.encodeWithSelector(VersionManager.addVersion.selector, IVersionManager.Status.PRODUCTION, address(walletLogic))
+// });
+// governanceCalls[1] = CallWithoutValue({
+// to: address(versionManager),
+// callData: abi.encodeWithSelector(VersionManager.markRecommendedVersion.selector, walletLogic.VERSION())
+// });
governanceCalls[0] = CallWithoutValue({
- to: address(versionManager),
- callData: abi.encodeWithSelector(VersionManager.addVersion.selector, IVersionManager.Status.PRODUCTION, address(walletLogic))
- });
- governanceCalls[1] = CallWithoutValue({
- to: address(versionManager),
- callData: abi.encodeWithSelector(VersionManager.markRecommendedVersion.selector, walletLogic.VERSION())
- });
- governanceCalls[2] = CallWithoutValue({
to: address(supa),
callData: abi.encodeWithSelector(SupaConfig.setConfig.selector, config)
});
- governanceCalls[3] = CallWithoutValue({
+ governanceCalls[1] = CallWithoutValue({
to: address(supa),
callData: abi.encodeWithSelector(SupaConfig.setTokenStorageConfig.selector, tokenStorageConfig)
});
@@ -81,9 +81,9 @@ contract SetupSupa is Script {
OffchainEntityProxy offchainEntityProxy = OffchainEntityProxy(offchainEntityProxyAddress);
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(governanceProxy),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(governanceProxy),
callData: abi.encodeWithSelector(GovernanceProxy.executeBatch.selector, governanceCalls),
value: 0
});
@@ -97,3 +97,5 @@ contract SetupSupa is Script {
// forge script script/SetupSupa.s.sol:SetupSupa --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer
+// forge script script/SetupSupa.s.sol:SetupSupa --rpc-url $BASE_RPC_URL --broadcast -vvvv --account supa_deployer
+
diff --git a/src/gelato/TaskCreator.sol b/src/gelato/TaskCreator.sol
index b159e17..4072e17 100644
--- a/src/gelato/TaskCreator.sol
+++ b/src/gelato/TaskCreator.sol
@@ -19,9 +19,6 @@ contract TaskCreator is ITaskCreator, AutomateTaskCreator, Ownable, ERC20 {
using GelatoBytes for bytes;
using SafeERC20 for IERC20;
-// /// @dev This makes sure we don't override the implementation address on the proxy
-// address public implementation = address(this);
-
/// @notice The address of the fee collector
address public feeCollector;
diff --git a/src/governance/Governance.sol b/src/governance/Governance.sol
index 0c793a4..b107c9f 100644
--- a/src/governance/Governance.sol
+++ b/src/governance/Governance.sol
@@ -6,7 +6,7 @@ import {GovernanceProxy} from "./GovernanceProxy.sol";
import {FsUtils} from "../lib/FsUtils.sol";
import {AccessControl} from "../lib/AccessControl.sol";
import {HashNFT} from "../tokens/HashNFT.sol";
-import {CallLib, CallWithoutValue} from "../lib/Call.sol";
+import {ExecutionLib, CallWithoutValue} from "../lib/Call.sol";
contract Governance is AccessControl, ERC1155Receiver {
address public voting;
@@ -33,7 +33,7 @@ contract Governance is AccessControl, ERC1155Receiver {
}
function executeBatch(CallWithoutValue[] memory calls) external {
- uint256 tokenId = hashNFT.toTokenId(voting, CallLib.hashCallWithoutValueArray(calls));
+ uint256 tokenId = hashNFT.toTokenId(voting, ExecutionLib.hashCallWithoutValueArray(calls));
hashNFT.burn(address(this), tokenId, 1); // reverts if tokenId isn't owned.
// For governance calls we do not want them to revert and be in limbo. Thus if the batch
diff --git a/src/governance/GovernanceProxy.sol b/src/governance/GovernanceProxy.sol
index 2b90ae6..3be290e 100644
--- a/src/governance/GovernanceProxy.sol
+++ b/src/governance/GovernanceProxy.sol
@@ -4,7 +4,7 @@ pragma solidity ^0.8.19;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {FsUtils} from "../lib/FsUtils.sol";
import {ImmutableGovernance} from "../lib/ImmutableGovernance.sol";
-import {CallLib, CallWithoutValue} from "../lib/Call.sol";
+import {ExecutionLib, CallWithoutValue} from "../lib/Call.sol";
// This is a proxy contract representing governance. This allows a fixed
// ethereum address to be the indefinite owner of the system. This works
@@ -56,7 +56,7 @@ contract GovernanceProxy {
// simpler approach where we just emit an event for each batch of
// privileged calls.
emit BatchExecuted(calls);
- CallLib.executeBatchWithoutValue(calls);
+ ExecutionLib.executeBatchWithoutValue(calls);
}
/// @notice Propose a new account as governance account. Note that this can
diff --git a/src/governance/OffchainEntityProxy.sol b/src/governance/OffchainEntityProxy.sol
index d3f4a8c..ad49fc5 100644
--- a/src/governance/OffchainEntityProxy.sol
+++ b/src/governance/OffchainEntityProxy.sol
@@ -4,7 +4,7 @@ pragma solidity ^0.8.19;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
-import {CallLib, Call} from "../lib/Call.sol";
+import {ExecutionLib, Execution} from "../lib/Call.sol";
import {FsUtils} from "../lib/FsUtils.sol";
// Signers (EOAs) are the only things that cross EVM chains as they have the same address on all chains.
@@ -58,8 +58,8 @@ contract OffchainEntityProxy is Ownable, EIP712 {
/// @dev Allow the owner to execute arbitrary calls on behalf of the entity through this proxy
/// @dev contract.
/// @param calls An array of calls to execute.
- function executeBatch(Call[] memory calls) external payable onlyOwner {
- CallLib.executeBatch(calls);
+ function executeBatch(Execution[] memory calls) external payable onlyOwner {
+ ExecutionLib.executeBatch(calls);
}
/// @notice Get the name of the entity.
diff --git a/src/governance/Voting.sol b/src/governance/Voting.sol
index 5fe1475..8ce15b3 100644
--- a/src/governance/Voting.sol
+++ b/src/governance/Voting.sol
@@ -7,7 +7,7 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {HashNFT} from "../tokens/HashNFT.sol";
import {TrieLib} from "../lib/Proofs.sol";
-import {CallLib, CallWithoutValue} from "../lib/Call.sol";
+import {ExecutionLib, CallWithoutValue} from "../lib/Call.sol";
import {FsUtils} from "../lib/FsUtils.sol";
import {NonceMapLib, NonceMap} from "../lib/NonceMap.sol";
@@ -112,7 +112,7 @@ contract Voting is EIP712 {
// proof storageHash is correct for blockhash(blockNumber) governanceTokenAddress
Proposal storage proposal = proposals.push();
- proposal.digest = CallLib.hashCallWithoutValueArray(calls);
+ proposal.digest = ExecutionLib.hashCallWithoutValueArray(calls);
proposal.deadline = block.timestamp + 2 days;
proposal.storageHash = storageHash;
proposal.totalSupply = TrieLib.proofStorageAt(
diff --git a/src/interfaces/IERC1363-extended.sol b/src/interfaces/IERC1363-extended.sol
index e646ee6..b617a9c 100644
--- a/src/interfaces/IERC1363-extended.sol
+++ b/src/interfaces/IERC1363-extended.sol
@@ -1,13 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {Call} from "../lib/Call.sol";
+import {Execution} from "../lib/Call.sol";
interface IERC1363SpenderExtended {
function onApprovalReceived(
address owner,
uint256 value,
- Call calldata call
+ Execution calldata call
) external returns (bytes4);
}
diff --git a/src/interfaces/ISupa.sol b/src/interfaces/ISupa.sol
index 81edaed..d0e9d90 100644
--- a/src/interfaces/ISupa.sol
+++ b/src/interfaces/ISupa.sol
@@ -2,7 +2,7 @@
pragma solidity ^0.8.19;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import {Call} from "../lib/Call.sol";
+import {Execution} from "../lib/Call.sol";
import {IERC20ValueOracle} from "./IERC20ValueOracle.sol";
import {INFTValueOracle} from "./INFTValueOracle.sol";
@@ -462,7 +462,7 @@ interface ISupaCore {
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
/// and Supa reserve/debt must be sufficient
/// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external;
+ function executeBatch(Execution[] memory calls) external;
/// @notice Returns the approved address for a token, or zero if no address set
/// @param collection The address of the ERC721 token
diff --git a/src/interfaces/IWallet.sol b/src/interfaces/IWallet.sol
index f6782bb..80cb729 100644
--- a/src/interfaces/IWallet.sol
+++ b/src/interfaces/IWallet.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
-import {Call, Execution} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
interface IWallet {
event TokensApproved(address sender, uint256 amount, bytes data);
@@ -12,9 +12,9 @@ interface IWallet {
/// creditAccount and wallet and Supa reserve/debt must be sufficient
/// @dev - this goes to supa.executeBatch that would immediately call WalletProxy.executeBatch
/// from above of this file
- /// @param calls {address to, bytes callData, uint256 value}[], where
+ /// @param calls {address target, uint256 value, bytes callData}[], where
/// * to - is the address of the contract whose function should be called
/// * callData - encoded function name and it's arguments
/// * value - the amount of ETH to sent with the call
- function executeBatch(Call[] memory calls) external payable;
+ function executeBatch(Execution[] memory calls) external payable;
}
diff --git a/src/interfaces/IWalletLogic.sol b/src/interfaces/IWalletLogic.sol
new file mode 100644
index 0000000..1b4450d
--- /dev/null
+++ b/src/interfaces/IWalletLogic.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.13;
+
+import {Execution,ReturnDataLink} from "src/lib/Call.sol";
+
+ struct DynamicExecution {
+ Execution execution;
+ ReturnDataLink[] dynamicData;
+ uint8 operation; // 0 = staticcall, 1 = delegatecall
+ }
+
+interface IWalletLogic {
+ event TokensApproved(address sender, uint256 amount, bytes data);
+ event TokensReceived(address spender, address sender, uint256 amount, bytes data);
+
+ /// @notice makes a batch of different calls from the name of wallet owner. Eventual state of
+ /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral on
+ /// creditAccount and wallet and Supa reserve/debt must be sufficient
+ /// @dev - this goes to supa.executeBatch that would immediately call WalletProxy.executeBatch
+ /// from above of this file
+ /// @param calls {address target, uint256 value, bytes callData}[], where
+ /// * to - is the address of the contract whose function should be called
+ /// * callData - encoded function name and it's arguments
+ /// * value - the amount of ETH to sent with the call
+ function executeBatch(Execution[] memory calls) external payable;
+
+ function executeBatch(DynamicExecution[] memory dynamicCalls) external payable;
+}
diff --git a/src/lib/Call.sol b/src/lib/Call.sol
index b8daff9..b388d7a 100644
--- a/src/lib/Call.sol
+++ b/src/lib/Call.sol
@@ -48,15 +48,15 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
/// @notice Specify a batch of calls to be executed in sequence,
/// @notice with the return values of some calls being passed as arguments to later calls.
- struct LinkedCall {
- Call call;
+ struct LinkedExecution {
+ Execution execution;
ReturnDataLink[] links;
}
-library CallLib {
+library ExecutionLib {
using Address for address;
- bytes internal constant CALL_TYPESTRING = "Call(address to,bytes callData,uint256 value)";
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
bytes32 constant CALL_TYPEHASH = keccak256(CALL_TYPESTRING);
bytes internal constant CALLWITHOUTVALUE_TYPESTRING =
"CallWithoutValue(address to,bytes callData)";
@@ -89,16 +89,16 @@ library CallLib {
return call.target.functionCallWithValue(call.callData, call.value);
}
- /**
- * @notice Execute a batch of calls.
- *
- * @param calls The calls to execute.
- */
- function executeBatch(Call[] memory calls) internal {
- for (uint256 i = 0; i < calls.length; i++) {
- execute(calls[i]);
- }
- }
+// /**
+// * @notice Execute a batch of calls.
+// *
+// * @param calls The calls to execute.
+// */
+// function executeBatch(Call[] memory calls) internal {
+// for (uint256 i = 0; i < calls.length; i++) {
+// execute(calls[i]);
+// }
+// }
/**
* @notice Execute a batch of calls.
@@ -122,11 +122,11 @@ library CallLib {
}
}
- function hashCall(Call memory call) internal pure returns (bytes32) {
- return keccak256(abi.encode(CALL_TYPEHASH, call.to, keccak256(call.callData), call.value));
+ function hashCall(Execution memory call) internal pure returns (bytes32) {
+ return keccak256(abi.encode(CALL_TYPEHASH, call.target, keccak256(call.callData), call.value));
}
- function hashCallArray(Call[] memory calls) internal pure returns (bytes32) {
+ function hashCallArray(Execution[] memory calls) internal pure returns (bytes32) {
bytes32[] memory hashes = new bytes32[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
hashes[i] = hashCall(calls[i]);
diff --git a/src/periphery/GelatoOperator.sol b/src/periphery/GelatoOperator.sol
index 7a3acf0..da49ed0 100644
--- a/src/periphery/GelatoOperator.sol
+++ b/src/periphery/GelatoOperator.sol
@@ -1,9 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {Call, LinkedCall} from "src/lib/Call.sol";
-import {WalletProxy} from "src/wallet/WalletProxy.sol";
-import {WalletLogic} from "src/wallet/WalletLogic.sol";
+import {Execution, LinkedExecution} from "src/lib/Call.sol";
+import {IWalletLogic, DynamicExecution} from "src/interfaces/IWalletLogic.sol";
/// @title Gelato Operator
/// @notice This contract acts as the operator for Gelato automated tasks
@@ -27,15 +26,15 @@ contract GelatoOperator {
/// @dev This contract must be set as an operator on the target Wallet
/// @param _target The target Supa wallet
/// @param _calls The calls to execute
- function execute(WalletProxy _target, Call[] calldata _calls) external onlyDedicatedSender {
+ function execute(IWalletLogic _target, Execution[] calldata _calls) external onlyDedicatedSender {
_target.executeBatch(_calls);
}
- /// @notice Executes a batch of calls on a target contract
+ /// @notice Executes a batch of dynamic calls on a target contract
/// @dev This contract must be set as an operator on the target Wallet
/// @param _target The target Supa wallet
/// @param _calls The calls to execute
- function executeLink(WalletLogic _target, LinkedCall[] calldata _calls) external onlyDedicatedSender {
- _target.executeBatchLink(_calls);
+ function execute(IWalletLogic _target, DynamicExecution[] calldata _calls) external onlyDedicatedSender {
+ _target.executeBatch(_calls);
}
}
diff --git a/src/periphery/ProxiedOperator.sol b/src/periphery/ProxiedOperator.sol
new file mode 100644
index 0000000..ec84918
--- /dev/null
+++ b/src/periphery/ProxiedOperator.sol
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+
+import {Execution, LinkedExecution} from "src/lib/Call.sol";
+import {IWalletLogic, DynamicExecution} from "src/interfaces/IWalletLogic.sol";
+
+/// @title Proxied Operator
+/// @notice This contract acts as an operator for automated tasks
+/// @dev This contract must be set as an operator on the target Wallet
+/// @dev Owner should be set to a multisig or governance contract
+contract ProxiedOperator is Ownable {
+ /// @notice Only the dedicated sender can call this function
+ error OnlyDedicatedSender();
+
+ address public dedicatedSender;
+
+ constructor(address _dedicatedSender, address owner) {
+ dedicatedSender = _dedicatedSender;
+ _transferOwnership(owner);
+ }
+
+ modifier onlyDedicatedSender() {
+ if (msg.sender != dedicatedSender) revert OnlyDedicatedSender();
+ _;
+ }
+
+ /// @notice Executes a batch of calls on a target contract
+ /// @dev This contract must be set as an operator on the target Wallet
+ /// @param _target The target Supa wallet
+ /// @param _calls The calls to execute
+ function execute(IWalletLogic _target, Execution[] calldata _calls) external onlyDedicatedSender {
+ _target.executeBatch(_calls);
+ }
+
+ /// @notice Executes a batch of dynamic calls on a target contract
+ /// @dev This contract must be set as an operator on the target Wallet
+ /// @param _target The target Supa wallet
+ /// @param _calls The calls to execute
+ function execute(IWalletLogic _target, DynamicExecution[] calldata _calls) external onlyDedicatedSender {
+ _target.executeBatch(_calls);
+ }
+
+ function setDedicatedSender(address _dedicatedSender) external onlyOwner {
+ dedicatedSender = _dedicatedSender;
+ }
+}
diff --git a/src/periphery/UniHelper.sol b/src/periphery/UniHelper.sol
index 21303fc..62be23c 100644
--- a/src/periphery/UniHelper.sol
+++ b/src/periphery/UniHelper.sol
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
-import {console} from "forge-std/console.sol";
-
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {Supa} from "src/supa/Supa.sol";
@@ -10,7 +8,7 @@ import {ISupa} from "src/interfaces/ISupa.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import {INonfungiblePositionManager} from "src/external/interfaces/INonfungiblePositionManager.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {WalletLogic} from "src/wallet/WalletLogic.sol";
/// @title Supa UniswapV3 Helper
@@ -44,32 +42,26 @@ contract UniHelper is IERC721Receiver {
/// @dev Must be approved as an operator on the sender
function borrowTokens(address[] calldata erc20s, uint256[] calldata amounts) external {
- console.log("enter borrowTokens");
- Call[] memory calls = new Call[](erc20s.length);
- console.log("after calls initialization");
+ Execution[] memory calls = new Execution[](erc20s.length);
for (uint256 i = 0; i < erc20s.length; i++) {
- console.log("i:", i);
- console.log("erc20s[i]:", erc20s[i]);
- console.log("amounts[i]:", amounts[i]);
calls[i] = (_borrow(erc20s[i], amounts[i]));
}
- console.log("after for loop");
WalletLogic(msg.sender).executeBatch(calls);
}
/// @dev Must be approved as an operator on the sender
function swap(ISwapRouter.ExactInputSingleParams memory params) external payable {
- Call[] memory calls = new Call[](2);
+ Execution[] memory calls = new Execution[](2);
// calls[0] is the token approval
- calls[0] = Call({
- to: params.tokenIn,
+ calls[0] = Execution({
+ target: params.tokenIn,
callData: abi.encodeWithSelector(IERC20.approve.selector, swapRouter, params.amountIn),
value: 0
});
// calls[1] is the swap
- calls[1] = Call({
- to: swapRouter,
+ calls[1] = Execution({
+ target: swapRouter,
callData: abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector, params),
value: 0
});
@@ -79,24 +71,24 @@ contract UniHelper is IERC721Receiver {
/// @dev Must be approved as an operator on the sender
function swapAndDeposit(ISwapRouter.ExactInputSingleParams memory params) external payable {
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// calls[0] is the token approval
- calls[0] = Call({
- to: params.tokenIn,
+ calls[0] = Execution({
+ target: params.tokenIn,
callData: abi.encodeWithSelector(IERC20.approve.selector, swapRouter, params.amountIn),
value: 0
});
// calls[1] is the swap
- calls[1] = Call({
- to: swapRouter,
+ calls[1] = Execution({
+ target: swapRouter,
callData: abi.encodeWithSelector(ISwapRouter.exactInputSingle.selector, params),
value: 0
});
// calls[2] is the deposit
- calls[2] = Call({
- to: address(supa),
+ calls[2] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.depositERC20.selector, params.tokenOut, params.amountOutMinimum),
value: 0
});
@@ -106,24 +98,24 @@ contract UniHelper is IERC721Receiver {
/// @dev Must be approved as an operator on the sender
function mint(INonfungiblePositionManager.MintParams memory params) external payable returns (uint256 tokenId) {
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// calls[0] is the token0 approval
- calls[0] = Call({
- to: params.token0,
+ calls[0] = Execution({
+ target: params.token0,
callData: abi.encodeWithSelector(IERC20.approve.selector, manager, params.amount0Desired),
value: 0
});
// calls[1] is the token1 approval
- calls[1] = Call({
- to: params.token1,
+ calls[1] = Execution({
+ target: params.token1,
callData: abi.encodeWithSelector(IERC20.approve.selector, manager, params.amount1Desired),
value: 0
});
// calls[2] is the mint
- calls[2] = Call({
- to: manager,
+ calls[2] = Execution({
+ target: manager,
callData: abi.encodeWithSelector(INonfungiblePositionManager.mint.selector, params),
value: 0
});
@@ -138,28 +130,31 @@ contract UniHelper is IERC721Receiver {
payable
returns (uint256 tokenId)
{
- Call[] memory calls = new Call[](4);
+ Execution[] memory calls = new Execution[](4);
// calls[0] is to forwardNFTs
- calls[0] =
- Call({to: msg.sender, callData: abi.encodeWithSelector(WalletLogic.forwardNFTs.selector, true), value: 0});
+ calls[0] = Execution({
+ target: msg.sender,
+ callData: abi.encodeWithSelector(WalletLogic.forwardNFTs.selector, true),
+ value: 0
+ });
// calls[1] is the token0 approval
- calls[1] = Call({
- to: params.token0,
+ calls[1] = Execution({
+ target: params.token0,
callData: abi.encodeWithSelector(IERC20.approve.selector, manager, params.amount0Desired),
value: 0
});
// calls[2] is the token1 approval
- calls[2] = Call({
- to: params.token1,
+ calls[2] = Execution({
+ target: params.token1,
callData: abi.encodeWithSelector(IERC20.approve.selector, manager, params.amount1Desired),
value: 0
});
// calls[3] is the mint
- calls[3] = Call({
- to: manager,
+ calls[3] = Execution({
+ target: manager,
callData: abi.encodeWithSelector(INonfungiblePositionManager.mint.selector, params),
value: 0
});
@@ -198,11 +193,11 @@ contract UniHelper is IERC721Receiver {
return this.onERC721Received.selector;
}
- function _removeLiquidity(uint256 tokenId, uint128 amountToRemove) internal returns (Call[] memory calls) {
- calls = new Call[](2);
+ function _removeLiquidity(uint256 tokenId, uint128 amountToRemove) internal returns (Execution[] memory calls) {
+ calls = new Execution[](2);
// calls[0] removes liquidity
- calls[0] = Call({
- to: manager,
+ calls[0] = Execution({
+ target: manager,
value: 0,
callData: abi.encodeWithSelector(
INonfungiblePositionManager(manager).decreaseLiquidity.selector,
@@ -217,8 +212,8 @@ contract UniHelper is IERC721Receiver {
});
// calls[1] collect tokens
- calls[1] = Call({
- to: manager,
+ calls[1] = Execution({
+ target: manager,
value: 0,
callData: abi.encodeWithSelector(
INonfungiblePositionManager(manager).collect.selector,
@@ -232,9 +227,9 @@ contract UniHelper is IERC721Receiver {
});
}
- function _borrow(address erc20, uint256 amount) internal returns (Call memory) {
- return Call({
- to: address(supa),
+ function _borrow(address erc20, uint256 amount) internal returns (Execution memory) {
+ return Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(supa.withdrawERC20.selector, erc20, amount),
value: 0
});
diff --git a/src/periphery/UniV3LPHelper.sol b/src/periphery/UniV3LPHelper.sol
index 1a7cde7..5bb823a 100644
--- a/src/periphery/UniV3LPHelper.sol
+++ b/src/periphery/UniV3LPHelper.sol
@@ -6,13 +6,26 @@ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IUniswapV3Factory} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
-import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import {INonfungiblePositionManager} from "src/external/interfaces/INonfungiblePositionManager.sol";
import {Call} from "src/lib/Call.sol";
import {FixedPoint96} from "@uniswap/v3-core/contracts/libraries/FixedPoint96.sol";
import {SafeCast} from "src/lib/SafeCast.sol";
import {Path} from "src/lib/Path.sol";
+interface ISwapRouter {
+ function exactInputSingle(ExactInputSingleParams calldata params) external returns (uint256 amountOut);
+}
+
+ struct ExactInputSingleParams {
+ address tokenIn;
+ address tokenOut;
+ uint24 fee;
+ address recipient;
+ uint256 amountIn;
+ uint256 amountOutMinimum;
+ uint160 sqrtPriceLimitX96;
+ }
+
/// @title Supa UniswapV3 LP Position Helper
contract UniV3LPHelper is IERC721Receiver {
using Path for bytes;
@@ -100,6 +113,18 @@ contract UniV3LPHelper is IERC721Receiver {
IERC721(address(manager)).transferFrom(address(this), msg.sender, tokenId);
}
+ /// @notice Remove liquidity and collect fees
+ /// @param tokenId LP token ID
+ function quickWithdraw(uint256 tokenId, address user) external {
+ // transfer LP token to this contract
+ IERC721(address(manager)).transferFrom(msg.sender, address(this), tokenId);
+
+ _quickWithdraw(tokenId, user, 100);
+
+ // transfer lp token to msg.sender
+ IERC721(address(manager)).transferFrom(address(this), msg.sender, tokenId);
+ }
+
/// @notice Remove liquidity and collect fees
/// @param tokenId LP token ID
/// @param percentage The percentage of liquidity to withdraw
@@ -194,27 +219,25 @@ contract UniV3LPHelper is IERC721Receiver {
(uint256 amount0Desired, uint256 amount1Desired) =
LiquidityAmounts.getAmountsForLiquidity(sqrtPriceX96, sqrtRatioAX96, sqrtRatioBX96, liquidity);
- ISwapRouter.ExactInputSingleParams memory params;
+ ExactInputSingleParams memory params;
if (amount0 > amount0Desired) {
// swap token0 for token1
- params = ISwapRouter.ExactInputSingleParams({
+ params = ExactInputSingleParams({
tokenIn: token0,
tokenOut: token1,
fee: fee,
recipient: address(this),
- deadline: block.timestamp,
amountIn: amount0 - amount0Desired,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
} else if (amount1 > amount1Desired) {
// swap token1 for token0
- params = ISwapRouter.ExactInputSingleParams({
+ params = ExactInputSingleParams({
tokenIn: token1,
tokenOut: token0,
fee: fee,
recipient: address(this),
- deadline: block.timestamp,
amountIn: amount1 - amount1Desired,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
@@ -434,15 +457,14 @@ contract UniV3LPHelper is IERC721Receiver {
(uint256 amount0Desired, uint256 amount1Desired) =
LiquidityAmounts.getAmountsForLiquidity(sqrtPriceX96, sqrtRatioAX96, sqrtRatioBX96, liquidity);
- ISwapRouter.ExactInputSingleParams memory params;
+ ExactInputSingleParams memory params;
if (amount0 > amount0Desired) {
// swap token0 for token1
- params = ISwapRouter.ExactInputSingleParams({
+ params = ExactInputSingleParams({
tokenIn: token0,
tokenOut: token1,
fee: fee,
recipient: address(this),
- deadline: block.timestamp,
amountIn: amount0 - amount0Desired,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
@@ -452,12 +474,11 @@ contract UniV3LPHelper is IERC721Receiver {
}
} else if (amount1 > amount1Desired) {
// swap token1 for token0
- params = ISwapRouter.ExactInputSingleParams({
+ params = ExactInputSingleParams({
tokenIn: token1,
tokenOut: token0,
fee: fee,
recipient: address(this),
- deadline: block.timestamp,
amountIn: amount1 - amount1Desired,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
diff --git a/src/supa/Liquifier.sol b/src/supa/Liquifier.sol
index f461a2e..40d948a 100644
--- a/src/supa/Liquifier.sol
+++ b/src/supa/Liquifier.sol
@@ -7,7 +7,7 @@ import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRoute
import {WalletState} from "../wallet/WalletState.sol";
import {ISupa} from "../interfaces/ISupa.sol";
import {INonfungiblePositionManager} from "../external/interfaces/INonfungiblePositionManager.sol";
-import {Call} from "../lib/Call.sol";
+import {Execution} from "../lib/Call.sol";
struct SqrtPricePriceRangeX96 {
uint160 minSell;
@@ -131,9 +131,9 @@ abstract contract Liquifier is WalletState {
IERC20[] calldata erc20s,
SqrtPricePriceRangeX96[] calldata erc20sAllowedPriceRanges
) private {
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(this),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(this),
callData: abi.encodeWithSelector(
this.liquify.selector,
wallet,
diff --git a/src/supa/Supa.sol b/src/supa/Supa.sol
index 1463c54..1fdf00c 100644
--- a/src/supa/Supa.sol
+++ b/src/supa/Supa.sol
@@ -22,7 +22,7 @@ import {IVersionManager} from "src/interfaces/IVersionManager.sol";
import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
import {WalletLib} from "src/lib/WalletLib.sol";
import {ERC20PoolLib} from "src/lib/ERC20PoolLib.sol";
-import {Call, Execution} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {FsUtils} from "src/lib/FsUtils.sol";
import {FsMath} from "src/lib/FsMath.sol";
@@ -294,13 +294,6 @@ contract Supa is SupaState, ISupaCore, IERC721Receiver, Proxy {
}
/// @inheritdoc ISupaCore
- function executeBatch(Call[] memory calls) external override onlyWallet whenNotPaused {
- WalletProxy(payable(msg.sender)).executeBatch(calls);
- if (!isSolvent(msg.sender)) {
- revert Errors.Insolvent();
- }
- }
-
function executeBatch(Execution[] memory calls) external onlyWallet whenNotPaused {
WalletProxy(payable(msg.sender)).executeBatch(calls);
if (!isSolvent(msg.sender)) {
@@ -530,7 +523,11 @@ contract Supa is SupaState, ISupaCore, IERC721Receiver, Proxy {
revert Errors.ReceiverNotContract();
}
- Call memory call = Call({to: target, callData: data, value: msg.value});
+ Execution memory call = Execution({
+ target: target,
+ callData: data,
+ value: msg.value
+ });
try IERC1363SpenderExtended(spender).onApprovalReceived(msg.sender, amount, call) returns (bytes4 retval) {
return retval == IERC1363SpenderExtended.onApprovalReceived.selector;
diff --git a/src/testing/MigrationSupa.sol b/src/testing/MigrationSupa.sol
index b09dda2..3c83764 100644
--- a/src/testing/MigrationSupa.sol
+++ b/src/testing/MigrationSupa.sol
@@ -26,7 +26,7 @@ import {IVersionManager} from "src/interfaces/IVersionManager.sol";
import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
import {WalletLib} from "src/lib/WalletLib.sol";
import {ERC20PoolLib} from "src/lib/ERC20PoolLib.sol";
-import {Call, Execution} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {FsUtils} from "src/lib/FsUtils.sol";
import {FsMath} from "src/lib/FsMath.sol";
@@ -385,18 +385,6 @@ contract MigrationSupa is SupaState, ISupaCore, IERC721Receiver, Proxy {
walletLogic[wallet] = implementation;
}
- /// @notice Execute a batch of calls
- /// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
- /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
- /// and Supa reserve/debt must be sufficient
- /// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external override onlyWallet whenNotPaused {
- WalletProxy(payable(msg.sender)).executeBatch(calls);
- if (!isSolvent(msg.sender)) {
- revert Insolvent();
- }
- }
-
/// @notice Execute a batch of calls
/// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
@@ -667,7 +655,7 @@ contract MigrationSupa is SupaState, ISupaCore, IERC721Receiver, Proxy {
revert ReceiverNotContract();
}
- Call memory call = Call({to: target, callData: data, value: msg.value});
+ Execution memory call = Execution({target: target, callData: data, value: msg.value});
try IERC1363SpenderExtended(spender).onApprovalReceived(msg.sender, amount, call) returns (bytes4 retval) {
return retval == IERC1363SpenderExtended.onApprovalReceived.selector;
diff --git a/src/testing/SimulationSupa.sol b/src/testing/SimulationSupa.sol
index 898fbb1..0272893 100644
--- a/src/testing/SimulationSupa.sol
+++ b/src/testing/SimulationSupa.sol
@@ -26,7 +26,7 @@ import {IVersionManager} from "src/interfaces/IVersionManager.sol";
import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
import {WalletLib} from "src/lib/WalletLib.sol";
import {ERC20PoolLib} from "src/lib/ERC20PoolLib.sol";
-import {Call, Execution} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {FsUtils} from "src/lib/FsUtils.sol";
import {FsMath} from "src/lib/FsMath.sol";
@@ -379,18 +379,6 @@ contract SimulationSupa is SupaState, ISupaCore, IERC721Receiver, Proxy {
revert("Not implemented");
}
- /// @notice Execute a batch of calls
- /// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
- /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
- /// and Supa reserve/debt must be sufficient
- /// @param calls An array of transaction calls
- function executeBatch(Call[] memory calls) external override onlyWallet whenNotPaused {
- WalletProxy(payable(msg.sender)).executeBatch(calls);
- if (!isSolvent(msg.sender)) {
- revert Insolvent();
- }
- }
-
/// @notice Execute a batch of calls
/// @dev execute a batch of commands on Supa from the name of wallet owner. Eventual state of
/// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral
@@ -646,7 +634,7 @@ contract SimulationSupa is SupaState, ISupaCore, IERC721Receiver, Proxy {
revert ReceiverNotContract();
}
- Call memory call = Call({to: target, callData: data, value: msg.value});
+ Execution memory call = Execution({target: target, callData: data, value: msg.value});
try IERC1363SpenderExtended(spender).onApprovalReceived(msg.sender, amount, call) returns (bytes4 retval) {
return retval == IERC1363SpenderExtended.onApprovalReceived.selector;
diff --git a/src/wallet/WalletLogic.sol b/src/wallet/WalletLogic.sol
index f7f1e7c..a0ace1a 100644
--- a/src/wallet/WalletLogic.sol
+++ b/src/wallet/WalletLogic.sol
@@ -13,10 +13,10 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {IVersionManager} from "src/interfaces/IVersionManager.sol";
import {ITransferReceiver2} from "src/interfaces/ITransferReceiver2.sol";
import {ISupa} from "src/interfaces/ISupa.sol";
-import {IWallet} from "src/interfaces/IWallet.sol";
+import {IWalletLogic, DynamicExecution} from "src/interfaces/IWalletLogic.sol";
import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
-import {CallLib, Call, Execution, LinkedCall, ReturnDataLink} from "src/lib/Call.sol";
+import {ExecutionLib, Execution, LinkedExecution, ReturnDataLink} from "src/lib/Call.sol";
import {NonceMapLib, NonceMap} from "src/lib/NonceMap.sol";
import {ImmutableVersion} from "src/lib/ImmutableVersion.sol";
import {BytesLib} from "src/lib/BytesLib.sol";
@@ -34,7 +34,7 @@ contract WalletLogic is
IERC1271,
ITransferReceiver2,
EIP712,
- IWallet,
+ IWalletLogic,
IERC1363SpenderExtended
{
using Address for address;
@@ -42,19 +42,19 @@ contract WalletLogic is
using BytesLib for bytes;
bytes private constant EXECUTEBATCH_TYPESTRING =
- "ExecuteBatch(Call[] calls,uint256 nonce,uint256 deadline)";
+ "ExecuteBatch(Execution[] calls,uint256 nonce,uint256 deadline)";
bytes private constant TRANSFER_TYPESTRING = "Transfer(address token,uint256 amount)";
bytes private constant ONTRANSFERRECEIVED2CALL_TYPESTRING =
"OnTransferReceived2Call(address operator,address from,Transfer[] transfers,Call[] calls,uint256 nonce,uint256 deadline)";
bytes32 private constant EXECUTEBATCH_TYPEHASH =
- keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, CallLib.CALL_TYPESTRING));
+ keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, ExecutionLib.CALL_TYPESTRING));
bytes32 private constant TRANSFER_TYPEHASH = keccak256(TRANSFER_TYPESTRING);
bytes32 private constant ONTRANSFERRECEIVED2CALL_TYPEHASH =
keccak256(
abi.encodePacked(
ONTRANSFERRECEIVED2CALL_TYPESTRING,
- CallLib.CALL_TYPESTRING,
+ ExecutionLib.CALL_TYPESTRING,
TRANSFER_TYPESTRING
)
);
@@ -64,12 +64,6 @@ contract WalletLogic is
bool internal forwardNFT;
NonceMap private nonceMap;
- struct DynamicCall {
- Call call;
- ReturnDataLink[] dynamicData;
- uint8 operation; // 0 = call, 1 = delegatecall
- }
-
modifier onlyOwner() {
if (_supa().getWalletOwner(address(this)) != msg.sender) {
revert Errors.OnlyOwner();
@@ -116,31 +110,11 @@ contract WalletLogic is
}
}
- /// @inheritdoc IWallet
- function executeBatch(Call[] calldata calls) external payable onlyOwnerOrOperator {
- bool saveForwardNFT = forwardNFT;
- forwardNFT = false;
- CallLib.executeBatch(calls);
- forwardNFT = saveForwardNFT;
-
- if (!_supa().isSolvent(address(this))) {
- revert Errors.Insolvent();
- }
- }
-
- /// @notice makes a batch of different calls from the name of wallet owner. Eventual state of
- /// creditAccount and Supa must be solvent, i.e. debt on creditAccount cannot exceed collateral on
- /// creditAccount and wallet and Supa reserve/debt must be sufficient
- /// @dev - this goes to supa.executeBatch that would immediately call WalletProxy.executeBatch
- /// from above of this file
- /// @param calls {address target, uint256 value, bytes callData}[], where
- /// * to - is the address of the contract whose function should be called
- /// * callData - encoded function name and it's arguments
- /// * value - the amount of ETH to sent with the call
+ /// @inheritdoc IWalletLogic
function executeBatch(Execution[] calldata calls) external payable onlyOwnerOrOperator {
bool saveForwardNFT = forwardNFT;
forwardNFT = false;
- CallLib.executeBatch(calls);
+ ExecutionLib.executeBatch(calls);
forwardNFT = saveForwardNFT;
if (!_supa().isSolvent(address(this))) {
@@ -149,7 +123,7 @@ contract WalletLogic is
}
function executeSignedBatch(
- Call[] memory calls,
+ Execution[] memory calls,
uint256 nonce,
uint256 deadline,
bytes calldata signature
@@ -158,7 +132,7 @@ contract WalletLogic is
nonceMap.validateAndUseNonce(nonce);
bytes32 digest = _hashTypedDataV4(
keccak256(
- abi.encode(EXECUTEBATCH_TYPEHASH, CallLib.hashCallArray(calls), nonce, deadline)
+ abi.encode(EXECUTEBATCH_TYPEHASH, ExecutionLib.hashCallArray(calls), nonce, deadline)
)
);
if (
@@ -245,7 +219,7 @@ contract WalletLogic is
if (msg.sender != _supa().getWalletOwner(address(this))) {
revert Errors.OnlyOwner();
}
- Call[] memory calls = abi.decode(data[1:], (Call[]));
+ Execution[] memory calls = abi.decode(data[1:], (Execution[]));
_supa().executeBatch(calls);
} else if (data[0] == 0x01) {
if (data.length != 1) revert Errors.InvalidData();
@@ -258,8 +232,8 @@ contract WalletLogic is
// execute signed batch
// Verify signature matches
- (Call[] memory calls, uint256 nonce, uint256 deadline, bytes memory signature) = abi
- .decode(data[1:], (Call[], uint256, uint256, bytes));
+ (Execution[] memory calls, uint256 nonce, uint256 deadline, bytes memory signature) = abi
+ .decode(data[1:], (Execution[], uint256, uint256, bytes));
if (deadline < block.timestamp) revert Errors.DeadlineExpired();
nonceMap.validateAndUseNonce(nonce);
@@ -277,7 +251,7 @@ contract WalletLogic is
operator,
from,
keccak256(abi.encodePacked(transferDigests)),
- CallLib.hashCallArray(calls),
+ ExecutionLib.hashCallArray(calls),
nonce,
deadline
)
@@ -301,14 +275,14 @@ contract WalletLogic is
function onApprovalReceived(
address sender,
uint256 amount,
- Call memory call
+ Execution memory call
) external onlySupa returns (bytes4) {
if (call.callData.length == 0) {
revert Errors.InvalidData();
}
emit TokensApproved(sender, amount, call.callData);
- Call[] memory calls = new Call[](1);
+ Execution[] memory calls = new Execution[](1);
calls[0] = call;
_supa().executeBatch(calls);
@@ -316,7 +290,7 @@ contract WalletLogic is
return this.onApprovalReceived.selector;
}
- function executeBatch(DynamicCall[] memory dynamicCalls) external payable onlyOwnerOrOperator {
+ function executeBatch(DynamicExecution[] memory dynamicCalls) external payable onlyOwnerOrOperator {
bool saveForwardNFT = forwardNFT;
forwardNFT = false;
@@ -329,7 +303,7 @@ contract WalletLogic is
for (uint256 i = 0; i < len;) {
// store the call to execute
- Call memory call = dynamicCalls[i].call;
+ Execution memory call = dynamicCalls[i].execution;
// loop through the offsets (the number of return values to be passed in the next call)
uint256 linksLength = dynamicCalls[i].dynamicData.length;
@@ -372,7 +346,7 @@ contract WalletLogic is
}
// execute the call and store the return data
- bytes memory returnData = dynamicCalls[i].operation == 0 ? call.to.functionStaticCall(call.callData) : call.to.functionCallWithValue(call.callData, call.value);
+ bytes memory returnData = dynamicCalls[i].operation == 0 ? call.target.functionStaticCall(call.callData) : call.target.functionCallWithValue(call.callData, call.value);
// add the return data to the array
returnDataArray[i] = returnData;
@@ -392,12 +366,12 @@ contract WalletLogic is
/// @notice Execute a batch of calls with linked return values.
/// @dev Deprecated, use executeBatchCalls instead.
/// @param linkedCalls The calls to execute.
- function executeBatchLink(LinkedCall[] memory linkedCalls) external payable onlyOwnerOrOperator {
+ function executeBatchLink(LinkedExecution[] memory linkedCalls) external payable onlyOwnerOrOperator {
bool saveForwardNFT = forwardNFT;
forwardNFT = false;
// get the first call
- Call memory call;
+ Execution memory call;
// create a bytes array with length equal to the number of calls
bytes[] memory returnDataArray = new bytes[](linkedCalls.length);
@@ -407,7 +381,7 @@ contract WalletLogic is
for (uint256 i = 0; i < l;) {
// get the next call to execute
- call = linkedCalls[i].call;
+ call = linkedCalls[i].execution;
// loop through the offsets (the number of return values to be passed in the next call)
uint256 linksLength = linkedCalls[i].links.length;
@@ -453,7 +427,7 @@ contract WalletLogic is
}
// execute the call and store the return data
- bytes memory returnData = CallLib.execute(call);
+ bytes memory returnData = ExecutionLib.execute(call);
// add the return data to the array
returnDataArray[i] = returnData;
diff --git a/src/wallet/WalletProxy.sol b/src/wallet/WalletProxy.sol
index c813afb..b130ffb 100644
--- a/src/wallet/WalletProxy.sol
+++ b/src/wallet/WalletProxy.sol
@@ -9,7 +9,7 @@ import {WalletState} from "./WalletState.sol";
import {ITransferReceiver2, TRANSFER_AND_CALL2} from "src/interfaces/ITransferReceiver2.sol";
import {PERMIT2} from "src/external/interfaces/IPermit2.sol";
import {FsUtils} from "src/lib/FsUtils.sol";
-import {CallLib, Call, Execution} from "src/lib/Call.sol";
+import {ExecutionLib, Execution} from "src/lib/Call.sol";
/// @title Wallet Proxy
/// @notice Proxy contract for Supa Wallets
@@ -32,22 +32,13 @@ contract WalletProxy is WalletState, Proxy {
/// @dev Allow ETH transfers
receive() external payable override {}
- // Allow Supa to make arbitrary calls in lieu of this wallet
- function executeBatch(Call[] calldata calls) external payable ifSupa {
- // Function is payable to allow for ETH transfers to the logic
- // contract, but supa should never send eth (supa contract should
- // never contain eth / other than what's self-destructed into it)
- FsUtils.Assert(msg.value == 0);
- CallLib.executeBatch(calls);
- }
-
// Allow Supa to make arbitrary calls in lieu of this wallet
function executeBatch(Execution[] calldata calls) external payable ifSupa {
// Function is payable to allow for ETH transfers to the logic
// contract, but supa should never send eth (supa contract should
// never contain eth / other than what's self-destructed into it)
FsUtils.Assert(msg.value == 0);
- CallLib.executeBatch(calls);
+ ExecutionLib.executeBatch(calls);
}
// The implementation of the delegate is controlled by Supa
diff --git a/src/wallet/v1.0.0/WalletLogic.sol b/src/wallet/v1.0.0/WalletLogic.sol
deleted file mode 100644
index 0a03035..0000000
--- a/src/wallet/v1.0.0/WalletLogic.sol
+++ /dev/null
@@ -1,381 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
-
-import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
-import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
-import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
-import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
-import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
-
-import {Liquifier} from "src/supa/Liquifier.sol";
-import {IVersionManager} from "src/interfaces/IVersionManager.sol";
-import {ITransferReceiver2} from "src/interfaces/ITransferReceiver2.sol";
-import {ISupa} from "src/interfaces/ISupa.sol";
-import {IWallet} from "src/interfaces/IWallet.sol";
-import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
-
-import {CallLib, Call, LinkedCall, ReturnDataLink} from "src/lib/Call.sol";
-import {NonceMapLib, NonceMap} from "src/lib/NonceMap.sol";
-import {ImmutableVersion} from "src/lib/ImmutableVersion.sol";
-import {BytesLib} from "src/lib/BytesLib.sol";
-
-import {WalletState} from "src/wallet/WalletState.sol";
-import {WalletProxy} from "src/wallet/WalletProxy.sol";
-
-import {Errors} from "src/libraries/Errors.sol";
-
-// Calls to the contract not coming from Supa itself are routed to this logic
-// contract. This allows for flexible extra addition to your wallet.
-contract WalletLogic is
-// WalletState,
- ImmutableVersion,
- IERC721Receiver,
- IERC1271,
- ITransferReceiver2,
- EIP712,
- IWallet,
-// Liquifier,
- IERC1363SpenderExtended
-{
- using NonceMapLib for NonceMap;
- using BytesLib for bytes;
-
- bytes private constant EXECUTEBATCH_TYPESTRING =
- "ExecuteBatch(Call[] calls,uint256 nonce,uint256 deadline)";
- bytes private constant TRANSFER_TYPESTRING = "Transfer(address token,uint256 amount)";
- bytes private constant ONTRANSFERRECEIVED2CALL_TYPESTRING =
- "OnTransferReceived2Call(address operator,address from,Transfer[] transfers,Call[] calls,uint256 nonce,uint256 deadline)";
-
- bytes32 private constant EXECUTEBATCH_TYPEHASH =
- keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, CallLib.CALL_TYPESTRING));
- bytes32 private constant TRANSFER_TYPEHASH = keccak256(TRANSFER_TYPESTRING);
- bytes32 private constant ONTRANSFERRECEIVED2CALL_TYPEHASH =
- keccak256(
- abi.encodePacked(
- ONTRANSFERRECEIVED2CALL_TYPESTRING,
- CallLib.CALL_TYPESTRING,
- TRANSFER_TYPESTRING
- )
- );
-
- string public constant VERSION = "1.0.0";
-
- bool internal forwardNFT;
- NonceMap private nonceMap;
-
- modifier onlyOwner() {
- if (_supa().getWalletOwner(address(this)) != msg.sender) {
- revert Errors.OnlyOwner();
- }
- _;
- }
-
- modifier onlyOwnerOrOperator() {
- if (
- _supa().getWalletOwner(address(this)) != msg.sender &&
- !_supa().isOperator(address(this), msg.sender)
- ) {
- revert Errors.NotOwnerOrOperator();
- }
- _;
- }
-
- modifier onlyThisAddress() {
- if (msg.sender != address(this)) {
- revert Errors.OnlyThisAddress();
- }
- _;
- }
-
- modifier onlySupa() {
- if (msg.sender != address(_supa())) {
- revert Errors.OnlySupa();
- }
- _;
- }
-
- // Note EIP712 is implemented with immutable variables and is not using
- // storage and thus can be used in a proxy contract constructor.
- // Version number should be in sync with VersionManager version.
- constructor(
- ) EIP712("Supa wallet", VERSION) ImmutableVersion(VERSION) {
- }
-
- /// @notice Transfer ETH
- function transfer(address to, uint256 value) external payable onlyThisAddress {
- (bool success, ) = to.call{value: value}("");
- if (!success) {
- revert Errors.TransferFailed();
- }
- }
-
- /// @inheritdoc IWallet
- function executeBatch(Call[] calldata calls) external payable onlyOwnerOrOperator {
- bool saveForwardNFT = forwardNFT;
- forwardNFT = false;
- CallLib.executeBatch(calls);
- forwardNFT = saveForwardNFT;
-
- if (!_supa().isSolvent(address(this))) {
- revert Errors.Insolvent();
- }
- }
-
- function executeSignedBatch(
- Call[] memory calls,
- uint256 nonce,
- uint256 deadline,
- bytes calldata signature
- ) external payable {
- if (deadline < block.timestamp) revert Errors.DeadlineExpired();
- nonceMap.validateAndUseNonce(nonce);
- bytes32 digest = _hashTypedDataV4(
- keccak256(
- abi.encode(EXECUTEBATCH_TYPEHASH, CallLib.hashCallArray(calls), nonce, deadline)
- )
- );
- if (
- !SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- digest,
- signature
- )
- ) revert Errors.InvalidSignature();
-
- _supa().executeBatch(calls);
- }
-
- function forwardNFTs(bool _forwardNFT) external {
- if (msg.sender != address(this)) {
- revert Errors.OnlyThisAddress();
- }
- forwardNFT = _forwardNFT;
- }
-
- /// @notice ERC721 transfer callback
- /// @dev it's a callback, required to be implemented by IERC721Receiver interface for the
- /// contract to be able to receive ERC721 NFTs.
- /// we are already using it to support "forwardNFT" of wallet.
- /// `return this.onERC721Received.selector;` is mandatory part for the NFT transfer to work -
- /// not a part of owr business logic
- /// @param - operator The address which called `safeTransferFrom` function
- /// @param - from The address which previously owned the token
- /// @param tokenId The NFT identifier which is being transferred
- /// @param data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- function onERC721Received(
- address /* operator */,
- address /* from */,
- uint256 tokenId,
- bytes memory data
- ) public virtual override returns (bytes4) {
- if (forwardNFT) {
- IERC721(msg.sender).safeTransferFrom(address(this), address(_supa()), tokenId, data);
- }
- return this.onERC721Received.selector;
- }
-
- function setNonce(uint256 nonce) external onlyOwner {
- nonceMap.validateAndUseNonce(nonce);
- }
-
- /// @inheritdoc ITransferReceiver2
- function onTransferReceived2(
- address operator,
- address from,
- ITransferReceiver2.Transfer[] calldata transfers,
- bytes calldata data
- ) external override onlyTransferAndCall2 returns (bytes4) {
- // options:
- // 1) just deposit into proxy, nothing to do
- // 2) execute a batch of calls (msg.sender is owner)
- // 3) directly deposit into supa contract
- // 3) execute a signed batch of tx's
- if (data.length == 0) {
- /* just deposit in the proxy, nothing to do */
- } else if (data[0] == 0x00) {
- // execute batch
- if (msg.sender != _supa().getWalletOwner(address(this))) {
- revert Errors.OnlyOwner();
- }
- Call[] memory calls = abi.decode(data[1:], (Call[]));
- _supa().executeBatch(calls);
- } else if (data[0] == 0x01) {
- if (data.length != 1) revert Errors.InvalidData();
- // deposit in the supa wallet
- for (uint256 i = 0; i < transfers.length; i++) {
- ITransferReceiver2.Transfer memory transfer_ = transfers[i];
- _supa().depositERC20(IERC20(transfer_.token), transfer_.amount);
- }
- } else if (data[0] == 0x02) {
- // execute signed batch
-
- // Verify signature matches
- (Call[] memory calls, uint256 nonce, uint256 deadline, bytes memory signature) = abi
- .decode(data[1:], (Call[], uint256, uint256, bytes));
-
- if (deadline < block.timestamp) revert Errors.DeadlineExpired();
- nonceMap.validateAndUseNonce(nonce);
-
- bytes32[] memory transferDigests = new bytes32[](transfers.length);
- for (uint256 i = 0; i < transfers.length; i++) {
- transferDigests[i] = keccak256(
- abi.encode(TRANSFER_TYPEHASH, transfers[i].token, transfers[i].amount)
- );
- }
- bytes32 digest = _hashTypedDataV4(
- keccak256(
- abi.encode(
- ONTRANSFERRECEIVED2CALL_TYPEHASH,
- operator,
- from,
- keccak256(abi.encodePacked(transferDigests)),
- CallLib.hashCallArray(calls),
- nonce,
- deadline
- )
- )
- );
- if (
- !SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- digest,
- signature
- )
- ) revert Errors.InvalidSignature();
-
- _supa().executeBatch(calls);
- } else {
- revert("Invalid data - allowed are '', '0x00...', '0x01' and '0x02...'");
- }
- return ITransferReceiver2.onTransferReceived2.selector;
- }
-
- function onApprovalReceived(
- address sender,
- uint256 amount,
- Call memory call
- ) external onlySupa returns (bytes4) {
- if (call.callData.length == 0) {
- revert Errors.InvalidData();
- }
- emit TokensApproved(sender, amount, call.callData);
-
- Call[] memory calls = new Call[](1);
- calls[0] = call;
-
- _supa().executeBatch(calls);
-
- return this.onApprovalReceived.selector;
- }
-
- function owner() external view returns (address) {
- return _supa().getWalletOwner(address(this));
- }
-
- /// @inheritdoc IERC1271
- function isValidSignature(
- bytes32 hash,
- bytes memory signature
- ) public view override returns (bytes4 magicValue) {
- magicValue = SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- hash,
- signature
- )
- ? this.isValidSignature.selector
- : bytes4(0);
- }
-
- function valueNonce(uint256 nonce) external view returns (bool) {
- return nonceMap.getNonce(nonce);
- }
-
- /// @notice Execute a batch of calls with linked return values.
- /// @param linkedCalls The calls to execute.
- function executeBatchLink(LinkedCall[] memory linkedCalls) external payable onlyOwnerOrOperator {
- bool saveForwardNFT = forwardNFT;
- forwardNFT = false;
-
- // todo: add checks for linkedCalls
- // 1. callIndex must be less than the current call
-
- // get the first call
- Call memory call;
-
- // create a bytes array with length equal to the number of calls
- bytes[] memory returnDataArray = new bytes[](linkedCalls.length);
-
- // loop through the calls
- uint256 l = linkedCalls.length;
- for (uint256 i = 0; i < l;) {
-
- // get the next call to execute
- call = linkedCalls[i].call;
-
- // loop through the offsets (the number of return values to be passed in the next call)
- uint256 linksLength = linkedCalls[i].links.length;
- for (uint256 j = 0; j < linksLength;) {
-
- ReturnDataLink memory link = linkedCalls[i].links[j];
-
- // get the call index, offset, and linked return value
- uint32 callIndex = link.callIndex;
- uint128 offset = link.offset;
- uint32 returnValueOffset = link.returnValueOffset;
- bool isStatic = link.isStatic;
-
- // revert if call has NOT already been executed
- if (callIndex > i) {
- revert Errors.InvalidData();
- }
-
- bytes memory spliceCalldata;
-
- if (isStatic) {
- // get the variable of interest from the return data
- spliceCalldata = returnDataArray[callIndex].slice(returnValueOffset, 32);
- } else {
- uint256 pointer = uint256(bytes32(returnDataArray[callIndex].slice(returnValueOffset, 32)));
- uint256 len = uint256(bytes32(returnDataArray[callIndex].slice(pointer, 32)));
- spliceCalldata = returnDataArray[callIndex].slice(pointer + 32, len);
- }
-
- bytes memory callData = call.callData;
-
- // splice the variable into the next call's calldata
- bytes memory prebytes = callData.slice(0, offset);
- bytes memory postbytes = callData.slice(offset + 32, callData.length - offset - 32);
- bytes memory newCallData = prebytes.concat(spliceCalldata.concat(postbytes));
-
- call.callData = newCallData;
-
- // increment the return value index
- unchecked {
- j++;
- }
- }
-
- // execute the call and store the return data
- bytes memory returnData = CallLib.execute(call);
- // add the return data to the array
- returnDataArray[i] = returnData;
-
- // increment the call index
- unchecked {
- i++;
- }
- }
-
- forwardNFT = saveForwardNFT;
-
- if (!_supa().isSolvent(address(this))) {
- revert Errors.Insolvent();
- }
- }
-
- function _supa() internal view returns (ISupa) {
- return WalletProxy(payable(address(this))).supa();
- }
-}
diff --git a/src/wallet/v1.0.1/WalletLogic.sol b/src/wallet/v1.0.1/WalletLogic.sol
deleted file mode 100644
index 7f7fc21..0000000
--- a/src/wallet/v1.0.1/WalletLogic.sol
+++ /dev/null
@@ -1,407 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
-
-import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
-import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
-import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
-import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
-import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
-import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
-
-import {IVersionManager} from "src/interfaces/IVersionManager.sol";
-import {ITransferReceiver2} from "src/interfaces/ITransferReceiver2.sol";
-import {ISupa} from "src/interfaces/ISupa.sol";
-import {IWallet} from "src/interfaces/IWallet.sol";
-import {IERC1363SpenderExtended} from "src/interfaces/IERC1363-extended.sol";
-
-import {CallLib, Call, LinkedCall, ReturnDataLink} from "src/lib/Call.sol";
-import {NonceMapLib, NonceMap} from "src/lib/NonceMap.sol";
-import {ImmutableVersion} from "src/lib/ImmutableVersion.sol";
-import {BytesLib} from "src/lib/BytesLib.sol";
-
-import {WalletProxy} from "src/wallet/WalletProxy.sol";
-
-import {Errors} from "src/libraries/Errors.sol";
-
-// Calls to the contract not coming from Supa itself are routed to this logic
-// contract. This allows for flexible extra addition to your wallet.
-contract WalletLogic is
- ImmutableVersion,
- IERC721Receiver,
- IERC1155Receiver,
- IERC1271,
- ITransferReceiver2,
- EIP712,
- IWallet,
- IERC1363SpenderExtended
-{
- using NonceMapLib for NonceMap;
- using BytesLib for bytes;
-
- bytes private constant EXECUTEBATCH_TYPESTRING =
- "ExecuteBatch(Call[] calls,uint256 nonce,uint256 deadline)";
- bytes private constant TRANSFER_TYPESTRING = "Transfer(address token,uint256 amount)";
- bytes private constant ONTRANSFERRECEIVED2CALL_TYPESTRING =
- "OnTransferReceived2Call(address operator,address from,Transfer[] transfers,Call[] calls,uint256 nonce,uint256 deadline)";
-
- bytes32 private constant EXECUTEBATCH_TYPEHASH =
- keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, CallLib.CALL_TYPESTRING));
- bytes32 private constant TRANSFER_TYPEHASH = keccak256(TRANSFER_TYPESTRING);
- bytes32 private constant ONTRANSFERRECEIVED2CALL_TYPEHASH =
- keccak256(
- abi.encodePacked(
- ONTRANSFERRECEIVED2CALL_TYPESTRING,
- CallLib.CALL_TYPESTRING,
- TRANSFER_TYPESTRING
- )
- );
-
- string public constant VERSION = "1.0.1";
-
- bool internal forwardNFT;
- NonceMap private nonceMap;
-
- modifier onlyOwner() {
- if (_supa().getWalletOwner(address(this)) != msg.sender) {
- revert Errors.OnlyOwner();
- }
- _;
- }
-
- modifier onlyOwnerOrOperator() {
- if (
- _supa().getWalletOwner(address(this)) != msg.sender &&
- !_supa().isOperator(address(this), msg.sender)
- ) {
- revert Errors.NotOwnerOrOperator();
- }
- _;
- }
-
- modifier onlyThisAddress() {
- if (msg.sender != address(this)) {
- revert Errors.OnlyThisAddress();
- }
- _;
- }
-
- modifier onlySupa() {
- if (msg.sender != address(_supa())) {
- revert Errors.OnlySupa();
- }
- _;
- }
-
- // Note EIP712 is implemented with immutable variables and is not using
- // storage and thus can be used in a proxy contract constructor.
- // Version number should be in sync with VersionManager version.
- constructor(
- ) EIP712("Supa wallet", VERSION) ImmutableVersion(VERSION) {
- }
-
- /// @notice Transfer ETH
- function transfer(address to, uint256 value) external payable onlyThisAddress {
- (bool success, ) = to.call{value: value}("");
- if (!success) {
- revert Errors.TransferFailed();
- }
- }
-
- /// @inheritdoc IWallet
- function executeBatch(Call[] calldata calls) external payable onlyOwnerOrOperator {
- bool saveForwardNFT = forwardNFT;
- forwardNFT = false;
- CallLib.executeBatch(calls);
- forwardNFT = saveForwardNFT;
-
- if (!_supa().isSolvent(address(this))) {
- revert Errors.Insolvent();
- }
- }
-
- function executeSignedBatch(
- Call[] memory calls,
- uint256 nonce,
- uint256 deadline,
- bytes calldata signature
- ) external payable {
- if (deadline < block.timestamp) revert Errors.DeadlineExpired();
- nonceMap.validateAndUseNonce(nonce);
- bytes32 digest = _hashTypedDataV4(
- keccak256(
- abi.encode(EXECUTEBATCH_TYPEHASH, CallLib.hashCallArray(calls), nonce, deadline)
- )
- );
- if (
- !SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- digest,
- signature
- )
- ) revert Errors.InvalidSignature();
-
- _supa().executeBatch(calls);
- }
-
- function forwardNFTs(bool _forwardNFT) external {
- if (msg.sender != address(this)) {
- revert Errors.OnlyThisAddress();
- }
- forwardNFT = _forwardNFT;
- }
-
- /// @notice ERC721 transfer callback
- /// @dev it's a callback, required to be implemented by IERC721Receiver interface for the
- /// contract to be able to receive ERC721 NFTs.
- /// we are already using it to support "forwardNFT" of wallet.
- /// `return this.onERC721Received.selector;` is mandatory part for the NFT transfer to work -
- /// not a part of owr business logic
- /// @param - operator The address which called `safeTransferFrom` function
- /// @param - from The address which previously owned the token
- /// @param tokenId The NFT identifier which is being transferred
- /// @param data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- function onERC721Received(
- address /* operator */,
- address /* from */,
- uint256 tokenId,
- bytes memory data
- ) public virtual override returns (bytes4) {
- if (forwardNFT) {
- IERC721(msg.sender).safeTransferFrom(address(this), address(_supa()), tokenId, data);
- }
- return this.onERC721Received.selector;
- }
-
- function onERC1155Received(
- address /* operator */,
- address /* from */,
- uint256 /* id */,
- uint256 /* value */,
- bytes calldata /* data */
- ) external override returns (bytes4) {
- return this.onERC1155Received.selector;
- }
-
- function onERC1155BatchReceived(
- address /* operator */,
- address /* from */,
- uint256[] calldata /* ids */,
- uint256[] calldata /* values */,
- bytes calldata /* data */
- ) external override returns (bytes4) {
- return this.onERC1155BatchReceived.selector;
- }
-
- function setNonce(uint256 nonce) external onlyOwner {
- nonceMap.validateAndUseNonce(nonce);
- }
-
- /// @inheritdoc ITransferReceiver2
- function onTransferReceived2(
- address operator,
- address from,
- ITransferReceiver2.Transfer[] calldata transfers,
- bytes calldata data
- ) external override onlyTransferAndCall2 returns (bytes4) {
- // options:
- // 1) just deposit into proxy, nothing to do
- // 2) execute a batch of calls (msg.sender is owner)
- // 3) directly deposit into supa contract
- // 3) execute a signed batch of tx's
- if (data.length == 0) {
- /* just deposit in the proxy, nothing to do */
- } else if (data[0] == 0x00) {
- // execute batch
- if (msg.sender != _supa().getWalletOwner(address(this))) {
- revert Errors.OnlyOwner();
- }
- Call[] memory calls = abi.decode(data[1:], (Call[]));
- _supa().executeBatch(calls);
- } else if (data[0] == 0x01) {
- if (data.length != 1) revert Errors.InvalidData();
- // deposit in the supa wallet
- for (uint256 i = 0; i < transfers.length; i++) {
- ITransferReceiver2.Transfer memory transfer_ = transfers[i];
- _supa().depositERC20(IERC20(transfer_.token), transfer_.amount);
- }
- } else if (data[0] == 0x02) {
- // execute signed batch
-
- // Verify signature matches
- (Call[] memory calls, uint256 nonce, uint256 deadline, bytes memory signature) = abi
- .decode(data[1:], (Call[], uint256, uint256, bytes));
-
- if (deadline < block.timestamp) revert Errors.DeadlineExpired();
- nonceMap.validateAndUseNonce(nonce);
-
- bytes32[] memory transferDigests = new bytes32[](transfers.length);
- for (uint256 i = 0; i < transfers.length; i++) {
- transferDigests[i] = keccak256(
- abi.encode(TRANSFER_TYPEHASH, transfers[i].token, transfers[i].amount)
- );
- }
- bytes32 digest = _hashTypedDataV4(
- keccak256(
- abi.encode(
- ONTRANSFERRECEIVED2CALL_TYPEHASH,
- operator,
- from,
- keccak256(abi.encodePacked(transferDigests)),
- CallLib.hashCallArray(calls),
- nonce,
- deadline
- )
- )
- );
- if (
- !SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- digest,
- signature
- )
- ) revert Errors.InvalidSignature();
-
- _supa().executeBatch(calls);
- } else {
- revert("Invalid data - allowed are '', '0x00...', '0x01' and '0x02...'");
- }
- return ITransferReceiver2.onTransferReceived2.selector;
- }
-
- function onApprovalReceived(
- address sender,
- uint256 amount,
- Call memory call
- ) external onlySupa returns (bytes4) {
- if (call.callData.length == 0) {
- revert Errors.InvalidData();
- }
- emit TokensApproved(sender, amount, call.callData);
-
- Call[] memory calls = new Call[](1);
- calls[0] = call;
-
- _supa().executeBatch(calls);
-
- return this.onApprovalReceived.selector;
- }
-
- function owner() external view returns (address) {
- return _supa().getWalletOwner(address(this));
- }
-
- /// @inheritdoc IERC1271
- function isValidSignature(
- bytes32 hash,
- bytes memory signature
- ) public view override returns (bytes4 magicValue) {
- magicValue = SignatureChecker.isValidSignatureNow(
- _supa().getWalletOwner(address(this)),
- hash,
- signature
- )
- ? this.isValidSignature.selector
- : bytes4(0);
- }
-
- function valueNonce(uint256 nonce) external view returns (bool) {
- return nonceMap.getNonce(nonce);
- }
-
- /// @notice Execute a batch of calls with linked return values.
- /// @param linkedCalls The calls to execute.
- function executeBatchLink(LinkedCall[] memory linkedCalls) external payable onlyOwnerOrOperator {
- bool saveForwardNFT = forwardNFT;
- forwardNFT = false;
-
- // todo: add checks for linkedCalls
- // 1. callIndex must be less than the current call
-
- // get the first call
- Call memory call;
-
- // create a bytes array with length equal to the number of calls
- bytes[] memory returnDataArray = new bytes[](linkedCalls.length);
-
- // loop through the calls
- uint256 l = linkedCalls.length;
- for (uint256 i = 0; i < l;) {
-
- // get the next call to execute
- call = linkedCalls[i].call;
-
- // loop through the offsets (the number of return values to be passed in the next call)
- uint256 linksLength = linkedCalls[i].links.length;
- for (uint256 j = 0; j < linksLength;) {
-
- ReturnDataLink memory link = linkedCalls[i].links[j];
-
- // get the call index, offset, and linked return value
- uint32 callIndex = link.callIndex;
- uint128 offset = link.offset;
- uint32 returnValueOffset = link.returnValueOffset;
- bool isStatic = link.isStatic;
-
- // revert if call has NOT already been executed
- if (callIndex > i) {
- revert Errors.InvalidData();
- }
-
- bytes memory spliceCalldata;
-
- if (isStatic) {
- // get the variable of interest from the return data
- spliceCalldata = returnDataArray[callIndex].slice(returnValueOffset, 32);
- } else {
- uint256 pointer = uint256(bytes32(returnDataArray[callIndex].slice(returnValueOffset, 32)));
- uint256 len = uint256(bytes32(returnDataArray[callIndex].slice(pointer, 32)));
- spliceCalldata = returnDataArray[callIndex].slice(pointer + 32, len);
- }
-
- bytes memory callData = call.callData;
-
- // splice the variable into the next call's calldata
- bytes memory prebytes = callData.slice(0, offset);
- bytes memory postbytes = callData.slice(offset + 32, callData.length - offset - 32);
- bytes memory newCallData = prebytes.concat(spliceCalldata.concat(postbytes));
-
- call.callData = newCallData;
-
- // increment the return value index
- unchecked {
- j++;
- }
- }
-
- // execute the call and store the return data
- bytes memory returnData = CallLib.execute(call);
- // add the return data to the array
- returnDataArray[i] = returnData;
-
- // increment the call index
- unchecked {
- i++;
- }
- }
-
- forwardNFT = saveForwardNFT;
-
- if (!_supa().isSolvent(address(this))) {
- revert Errors.Insolvent();
- }
- }
-
- function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
- return interfaceId == type(IERC721Receiver).interfaceId ||
- interfaceId == type(IERC1155Receiver).interfaceId ||
- interfaceId == type(IERC1271).interfaceId ||
- interfaceId == type(ITransferReceiver2).interfaceId ||
- interfaceId == type(IERC1363SpenderExtended).interfaceId;
- }
-
- function _supa() internal view returns (ISupa) {
- return WalletProxy(payable(address(this))).supa();
- }
-}
diff --git a/test/forkTesting/UniV3LPHelper.t.sol b/test/forkTesting/UniV3LPHelper.t.sol
index 9fe1f20..e63a36c 100644
--- a/test/forkTesting/UniV3LPHelper.t.sol
+++ b/test/forkTesting/UniV3LPHelper.t.sol
@@ -17,7 +17,7 @@ import {INonfungiblePositionManager} from "src/external/interfaces/INonfungibleP
import {WalletProxy} from "src/wallet/WalletProxy.sol";
import {WalletLogic} from "src/wallet/WalletLogic.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {MockERC20Oracle} from "src/testing/MockERC20Oracle.sol";
import {ERC20ChainlinkValueOracle} from "src/oracles/ERC20ChainlinkValueOracle.sol";
@@ -169,7 +169,7 @@ contract UniV3LPHelperTest is Test {
deal({token: address(usdc), to: address(userWallet), give: usdcAmount});
deal({token: address(weth), to: address(userWallet), give: wethAmount});
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// (1) mint and deposit LP token
@@ -187,18 +187,18 @@ contract UniV3LPHelperTest is Test {
deadline: block.timestamp + 1000
});
- calls[0] = Call({
- to: address(usdc),
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(weth),
+ calls[1] = Execution({
+ target: address(weth),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature(
"mintAndDeposit((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))",
params
@@ -233,22 +233,22 @@ contract UniV3LPHelperTest is Test {
deal({token: address(weth), to: address(uniV3LPHelper), give: 1 ether});
// Create calls to reinvest fees
- Call[] memory reinvestCalls = new Call[](3);
+ Execution[] memory reinvestCalls = new Execution[](3);
// (1) withdraw LP token to Wallet
- reinvestCalls[0] = Call({
- to: address(supa),
+ reinvestCalls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
// (2) approve LP token to uniV3LPHelper
- reinvestCalls[1] = Call({
- to: address(nonfungiblePositionManager),
+ reinvestCalls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
// (3) reinvest fees
- reinvestCalls[2] = Call({
- to: address(uniV3LPHelper),
+ reinvestCalls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("reinvest(uint256)", tokenId),
value: 0
});
@@ -283,16 +283,16 @@ contract UniV3LPHelperTest is Test {
deal({token: address(weth), to: address(uniV3LPHelper), give: 1 ether});
// Create calls to reinvest fees
- Call[] memory reinvestCalls = new Call[](2);
+ Execution[] memory reinvestCalls = new Execution[](2);
// (1) withdraw LP token to Wallet
- reinvestCalls[0] = Call({
- to: address(supa),
+ reinvestCalls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
// (2) reinvest fees
- reinvestCalls[1] = Call({
- to: address(nonfungiblePositionManager),
+ reinvestCalls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature(
"safeTransferFrom(address,address,uint256,bytes)",
address(userWallet),
@@ -322,7 +322,7 @@ contract UniV3LPHelperTest is Test {
deal({token: address(usdc), to: address(userWallet), give: usdcAmount});
deal({token: address(weth), to: address(userWallet), give: wethAmount});
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// (1) mint and deposit LP token
@@ -340,18 +340,18 @@ contract UniV3LPHelperTest is Test {
deadline: block.timestamp + 1000
});
- calls[0] = Call({
- to: address(usdc),
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(weth),
+ calls[1] = Execution({
+ target: address(weth),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature(
"mintAndDeposit((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))",
params
@@ -364,22 +364,22 @@ contract UniV3LPHelperTest is Test {
uint256 tokenId = nftData[0].tokenId;
- Call[] memory reinvestCalls = new Call[](3);
+ Execution[] memory reinvestCalls = new Execution[](3);
// (1) withdraw LP token to Wallet
- reinvestCalls[0] = Call({
- to: address(supa),
+ reinvestCalls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
// (2) approve LP token to uniV3LPHelper
- reinvestCalls[1] = Call({
- to: address(nonfungiblePositionManager),
+ reinvestCalls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
// (3) reinvest fees
- reinvestCalls[2] = Call({
- to: address(uniV3LPHelper),
+ reinvestCalls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("reinvest(uint256)", tokenId),
value: 0
});
@@ -397,19 +397,19 @@ contract UniV3LPHelperTest is Test {
uint256 tokenId = _mintAndDeposit();
// Quick withdraw
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("quickWithdraw(uint256)", tokenId),
value: 0
});
@@ -430,19 +430,19 @@ contract UniV3LPHelperTest is Test {
uint256 tokenId = _mintAndDeposit();
// Quick withdraw
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("quickWithdraw(uint256)", tokenId),
value: 0
});
@@ -450,14 +450,14 @@ contract UniV3LPHelperTest is Test {
userWallet.executeBatch(calls);
// Quick withdraw
- Call[] memory secondCalls = new Call[](2);
- secondCalls[0] = Call({
- to: address(nonfungiblePositionManager),
+ Execution[] memory secondCalls = new Execution[](2);
+ secondCalls[0] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
- secondCalls[1] = Call({
- to: address(uniV3LPHelper),
+ secondCalls[1] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("quickWithdraw(uint256)", tokenId),
value: 0
});
@@ -478,14 +478,14 @@ contract UniV3LPHelperTest is Test {
data[0] = 0x01;
// Quick withdraw
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature(
"safeTransferFrom(address,address,uint256,bytes)",
address(userWallet),
@@ -514,14 +514,14 @@ contract UniV3LPHelperTest is Test {
data[0] = 0x01;
// Quick withdraw
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature(
"safeTransferFrom(address,address,uint256,bytes)",
address(userWallet),
@@ -535,9 +535,9 @@ contract UniV3LPHelperTest is Test {
userWallet.executeBatch(calls);
// Quick withdraw
- Call[] memory secondCalls = new Call[](1);
- secondCalls[0] = Call({
- to: address(nonfungiblePositionManager),
+ Execution[] memory secondCalls = new Execution[](1);
+ secondCalls[0] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature(
"safeTransferFrom(address,address,uint256,bytes)",
address(userWallet),
@@ -577,19 +577,19 @@ contract UniV3LPHelperTest is Test {
swapRouter.exactInputSingle(params);
// Rebalance
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("rebalanceSameTickSizing(uint256)", tokenId),
value: 0
});
@@ -604,19 +604,19 @@ contract UniV3LPHelperTest is Test {
uint256 tokenId = _mintAndDeposit();
// Rebalance
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSelector(Supa.withdrawERC721.selector, address(nonfungiblePositionManager), tokenId),
value: 0
});
- calls[1] = Call({
- to: address(nonfungiblePositionManager),
+ calls[1] = Execution({
+ target: address(nonfungiblePositionManager),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), tokenId),
value: 0
});
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature("rebalanceSameTickSizing(uint256)", tokenId),
value: 0
});
@@ -635,7 +635,7 @@ contract UniV3LPHelperTest is Test {
deal({token: address(weth), to: address(userWallet), give: wethAmount});
// Create a position and deposit LP token to supa
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// get pool
IUniswapV3Pool pool =
@@ -667,20 +667,20 @@ contract UniV3LPHelperTest is Test {
});
// (1) approve usdc
- calls[0] = Call({
- to: address(usdc),
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
// (2) approve weth
- calls[1] = Call({
- to: address(weth),
+ calls[1] = Execution({
+ target: address(weth),
callData: abi.encodeWithSignature("approve(address,uint256)", address(uniV3LPHelper), type(uint256).max),
value: 0
});
// (3) mint and deposit LP token
- calls[2] = Call({
- to: address(uniV3LPHelper),
+ calls[2] = Execution({
+ target: address(uniV3LPHelper),
callData: abi.encodeWithSignature(
"mintAndDeposit((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))",
params
diff --git a/test/forkTesting/gelato.t.sol b/test/forkTesting/gelato.t.sol
index 14a8e6a..647535f 100644
--- a/test/forkTesting/gelato.t.sol
+++ b/test/forkTesting/gelato.t.sol
@@ -13,10 +13,10 @@ import {Supa, IERC20} from "src/supa/Supa.sol";
import {SupaConfig, ISupaConfig} from "src/supa/SupaConfig.sol";
import {VersionManager, IVersionManager} from "src/supa/VersionManager.sol";
-import {WalletLogic, LinkedCall, ReturnDataLink} from "src/wallet/WalletLogic.sol";
+import {WalletLogic, LinkedExecution, ReturnDataLink} from "src/wallet/WalletLogic.sol";
import {WalletProxy} from "src/wallet/WalletProxy.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
contract GelatoArbitrumTest is Test {
GelatoOperator public gelatoOperator;
@@ -225,9 +225,9 @@ contract GelatoArbitrumTest is Test {
string memory cid = "QmPtdg15JttHPzV592jy1AhjoByTAE8tCeTFRYjLMjAExk";
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(taskCreatorProxy),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -247,19 +247,19 @@ contract GelatoArbitrumTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether),
value: 0
});
- calls[2] = Call({
- to: address(taskCreatorProxy),
+ calls[2] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -295,19 +295,19 @@ contract GelatoArbitrumTest is Test {
string memory newCid = "QmPmKTEBA39PPVu8LVgAgXdj3rUUQv2WUZ92X6woDF154q";
bytes memory signature = hex"4fe283a2e7984beda941908f1ae4fee87556ee4669318d0226bc7202d9eda5d15ff308f053da8bd431ea059cfba0e8866942c69274a899e83f0aff572c5116e41c";
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether),
value: 0
});
- calls[2] = Call({
- to: address(taskCreatorProxy),
+ calls[2] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool,address,bytes)", 0, address(1), newCid, 1000, false, admin, signature),
value: 0
});
@@ -334,7 +334,7 @@ contract GelatoArbitrumTest is Test {
give: 1000 ether
});
- LinkedCall[] memory linkedCalls = new LinkedCall[](3);
+ LinkedExecution[] memory linkedCalls = new LinkedExecution[](3);
ReturnDataLink[] memory links = new ReturnDataLink[](1);
links[0] = ReturnDataLink({
returnValueOffset: 0,
@@ -342,25 +342,25 @@ contract GelatoArbitrumTest is Test {
callIndex: 1,
offset: 4
});
- linkedCalls[0] = LinkedCall({
- call: Call({
- to: address(usdc),
+ linkedCalls[0] = LinkedExecution({
+ execution: Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
}),
links: new ReturnDataLink[](0)
});
- linkedCalls[1] = LinkedCall({
- call: Call({
- to: address(taskCreatorProxy),
+ linkedCalls[1] = LinkedExecution({
+ execution: Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
}),
links: new ReturnDataLink[](0)
});
- linkedCalls[2] = LinkedCall({
- call: Call({
- to: address(taskCreatorProxy),
+ linkedCalls[2] = LinkedExecution({
+ execution: Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("cancelTask(bytes32)", 0),
value: 0
}),
@@ -383,14 +383,14 @@ contract GelatoArbitrumTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -419,14 +419,14 @@ contract GelatoArbitrumTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -456,14 +456,14 @@ contract GelatoArbitrumTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
diff --git a/test/gelato.t.sol b/test/gelato.t.sol
index d89b518..3501f8e 100644
--- a/test/gelato.t.sol
+++ b/test/gelato.t.sol
@@ -13,10 +13,10 @@ import {Supa, IERC20} from "src/supa/Supa.sol";
import {SupaConfig, ISupaConfig} from "src/supa/SupaConfig.sol";
import {VersionManager, IVersionManager} from "src/supa/VersionManager.sol";
-import {WalletLogic, LinkedCall, ReturnDataLink} from "src/wallet/WalletLogic.sol";
+import {WalletLogic, LinkedExecution, ReturnDataLink} from "src/wallet/WalletLogic.sol";
import {WalletProxy} from "src/wallet/WalletProxy.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
contract GelatoTest is Test {
GelatoOperator public gelatoOperator;
@@ -175,11 +175,11 @@ contract GelatoTest is Test {
string memory cid = "QmPtdg15JttHPzV592jy1AhjoByTAE8tCeTFRYjLMjAExk";
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
- value: 0
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false)
});
vm.expectRevert(abi.encodeWithSelector(TaskCreatorErrors.UnauthorizedCID.selector, cid));
userWallet.executeBatch(calls);
@@ -197,21 +197,22 @@ contract GelatoTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(usdc),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
- value: 0
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(usdc),
+ value: 0,
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max)
+
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether),
- value: 0
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether)
});
- calls[2] = Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
- value: 0
+ calls[2] = Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false)
});
userWallet.executeBatch(calls);
@@ -244,21 +245,21 @@ contract GelatoTest is Test {
string memory newCid = "QmPmKTEBA39PPVu8LVgAgXdj3rUUQv2WUZ92X6woDF154q";
bytes memory signature = hex"4fe283a2e7984beda941908f1ae4fee87556ee4669318d0226bc7202d9eda5d15ff308f053da8bd431ea059cfba0e8866942c69274a899e83f0aff572c5116e41c";
- Call[] memory calls = new Call[](3);
- calls[0] = Call({
- to: address(usdc),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
- value: 0
+ Execution[] memory calls = new Execution[](3);
+ calls[0] = Execution({
+ target: address(usdc),
+ value: 0,
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max)
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether),
- value: 0
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("purchasePowerExactUsdc(address,uint256)", msg.sender, 1 ether)
});
- calls[2] = Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool,address,bytes)", 0, address(1), newCid, 1000, false, admin, signature),
- value: 0
+ calls[2] = Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool,address,bytes)", 0, address(1), newCid, 1000, false, admin, signature)
});
userWallet.executeBatch(calls);
@@ -283,7 +284,7 @@ contract GelatoTest is Test {
give: 1000 ether
});
- LinkedCall[] memory linkedCalls = new LinkedCall[](3);
+ LinkedExecution[] memory linkedCalls = new LinkedExecution[](3);
ReturnDataLink[] memory links = new ReturnDataLink[](1);
links[0] = ReturnDataLink({
returnValueOffset: 0,
@@ -291,27 +292,27 @@ contract GelatoTest is Test {
callIndex: 1,
offset: 4
});
- linkedCalls[0] = LinkedCall({
- call: Call({
- to: address(usdc),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
- value: 0
+ linkedCalls[0] = LinkedExecution({
+ execution: Execution({
+ target: address(usdc),
+ value: 0,
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max)
}),
links: new ReturnDataLink[](0)
});
- linkedCalls[1] = LinkedCall({
- call: Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
- value: 0
+ linkedCalls[1] = LinkedExecution({
+ execution: Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false)
}),
links: new ReturnDataLink[](0)
});
- linkedCalls[2] = LinkedCall({
- call: Call({
- to: address(taskCreatorProxy),
- callData: abi.encodeWithSignature("cancelTask(bytes32)", 0),
- value: 0
+ linkedCalls[2] = LinkedExecution({
+ execution: Execution({
+ target: address(taskCreatorProxy),
+ value: 0,
+ callData: abi.encodeWithSignature("cancelTask(bytes32)", 0)
}),
links: links
});
@@ -332,14 +333,14 @@ contract GelatoTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -367,14 +368,14 @@ contract GelatoTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
@@ -404,14 +405,14 @@ contract GelatoTest is Test {
give: 1000 ether
});
- Call[] memory calls = new Call[](2);
- calls[0] = Call({
- to: address(usdc),
+ Execution[] memory calls = new Execution[](2);
+ calls[0] = Execution({
+ target: address(usdc),
callData: abi.encodeWithSignature("approve(address,uint256)", address(taskCreatorProxy), type(uint256).max),
value: 0
});
- calls[1] = Call({
- to: address(taskCreatorProxy),
+ calls[1] = Execution({
+ target: address(taskCreatorProxy),
callData: abi.encodeWithSignature("createTask(uint256,address,string,uint256,bool)", 0, address(1), cid, 1000, false),
value: 0
});
diff --git a/test/supa.t.sol b/test/supa.t.sol
index ea237f0..fcfb5ed 100644
--- a/test/supa.t.sol
+++ b/test/supa.t.sol
@@ -8,7 +8,7 @@ import {Supa, WalletLib, SupaState, ISupaCore} from "src/supa/Supa.sol";
import {ISupa} from "src/interfaces/ISupa.sol";
import {SupaConfig, ISupaConfig} from "src/supa/SupaConfig.sol";
-import {Call} from "src/lib/Call.sol";
+import {Execution} from "src/lib/Call.sol";
import {WalletProxy} from "src/wallet/WalletProxy.sol";
import {WalletLogic} from "src/wallet/WalletLogic.sol";
@@ -132,20 +132,20 @@ contract SupaTest is Test {
_mintTokens(address(userWallet), _amount0, _amount1);
// construct calls
- Call[] memory calls = new Call[](4);
+ Execution[] memory calls = new Execution[](4);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
+ Execution({
+ target: address(token0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), _amount0),
value: 0
})
);
calls[1] = (
- Call({
- to: address(token1),
+ Execution({
+ target: address(token1),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), _amount1),
value: 0
})
@@ -153,16 +153,16 @@ contract SupaTest is Test {
// deposit erc20 tokens
calls[2] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount0)),
value: 0
})
);
calls[3] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token1, uint256(_amount1)),
value: 0
})
@@ -198,28 +198,28 @@ contract SupaTest is Test {
token0.mint(address(userWallet), _amount0);
// construct calls
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
+ Execution({
+ target: address(token0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), uint256(_amount0)),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount0)),
value: 0
})
);
calls[2] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature(
"transferERC20(address,address,uint256)", token0, address(userWallet2), uint256(_amount0)
),
@@ -240,20 +240,20 @@ contract SupaTest is Test {
token0.mint(address(userWallet), _amount0);
// construct calls
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
+ Execution({
+ target: address(token0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), uint256(_amount0)),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature(
"transferERC20(address,address,uint256)", token0, address(userWallet2), uint256(_amount0)
),
@@ -262,8 +262,8 @@ contract SupaTest is Test {
);
calls[2] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount0)),
value: 0
})
@@ -284,28 +284,28 @@ contract SupaTest is Test {
token0.mint(address(userWallet), _amount);
// construct calls
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
+ Execution({
+ target: address(token0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), uint256(_amount)),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount)),
value: 0
})
);
calls[2] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature(
"transferERC20(address,address,uint256)",
token0,
@@ -332,28 +332,28 @@ contract SupaTest is Test {
token0.mint(address(userWallet), _amount);
// construct calls
- Call[] memory calls = new Call[](3);
+ Execution[] memory calls = new Execution[](3);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
+ Execution({
+ target: address(token0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), uint256(_amount)),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount)),
value: 0
})
);
calls[2] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature(
"transferERC20(address,address,uint256)",
token0,
@@ -420,10 +420,10 @@ contract SupaTest is Test {
assertEq(tokenCounter, 0);
} else {
assertEq(tokenCounter, 1);
- Call[] memory calls = new Call[](1);
+ Execution[] memory calls = new Execution[](1);
calls[0] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("withdrawERC20(address,uint256)", address(token0), amount),
value: 0
})
@@ -441,17 +441,17 @@ contract SupaTest is Test {
uint256 nftCounter = SupaConfig(address(supa)).getCreditAccountERC721Counter(address(userWallet));
assertEq(nftCounter, 0);
nft0.mint(address(userWallet));
- Call[] memory calls = new Call[](2);
+ Execution[] memory calls = new Execution[](2);
calls[0] = (
- Call({
- to: address(nft0),
+ Execution({
+ target: address(nft0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
value: 0
})
@@ -468,29 +468,29 @@ contract SupaTest is Test {
uint256 nftCounter = SupaConfig(address(supa)).getCreditAccountERC721Counter(address(userWallet));
assertEq(nftCounter, 0);
nft0.mint(address(userWallet));
- Call[] memory calls = new Call[](2);
+ Execution[] memory calls = new Execution[](2);
calls[0] = (
- Call({
- to: address(nft0),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
- value: 0
- })
+ Execution({
+ target: address(nft0),
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
+ value: 0
+ })
);
calls[1] = (
- Call({
- to: address(supa),
- callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
- value: 0
- })
+ Execution({
+ target: address(supa),
+ callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
+ value: 0
+ })
);
userWallet.executeBatch(calls);
nftCounter = SupaConfig(address(supa)).getCreditAccountERC721Counter(address(userWallet));
assertEq(nftCounter, 1);
- Call[] memory secondCalls = new Call[](1);
+ Execution[] memory secondCalls = new Execution[](1);
secondCalls[0] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("withdrawERC721(address,uint256)", address(nft0), 0),
value: 0
})
@@ -527,20 +527,20 @@ contract SupaTest is Test {
supa.depositERC20ForWallet(address(token0), address(userWallet), 100 * 1 ether);
nft0.mint(address(userWallet));
- Call[] memory calls = new Call[](2);
+ Execution[] memory calls = new Execution[](2);
calls[0] = (
- Call({
- to: address(nft0),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
- value: 0
- })
+ Execution({
+ target: address(nft0),
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
+ value: 0
+ })
);
calls[1] = (
- Call({
- to: address(supa),
- callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
- value: 0
- })
+ Execution({
+ target: address(supa),
+ callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
+ value: 0
+ })
);
vm.expectRevert(Errors.TokenStorageExceeded.selector);
@@ -582,17 +582,17 @@ contract SupaTest is Test {
ISupaConfig.TokenStorageConfig({maxTokenStorage: 10, erc20Multiplier: 10, erc721Multiplier: 1})
);
nft0.mint(address(userWallet));
- Call[] memory calls = new Call[](2);
+ Execution[] memory calls = new Execution[](2);
calls[0] = (
- Call({
- to: address(nft0),
+ Execution({
+ target: address(nft0),
callData: abi.encodeWithSignature("approve(address,uint256)", address(supa), 0),
value: 0
})
);
calls[1] = (
- Call({
- to: address(supa),
+ Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("depositERC721(address,uint256)", address(nft0), 0),
value: 0
})
diff --git a/test/utils/SigUtils.sol b/test/utils/SigUtils.sol
index b87c473..8784faf 100644
--- a/test/utils/SigUtils.sol
+++ b/test/utils/SigUtils.sol
@@ -5,7 +5,7 @@ import "forge-std/console.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
-import {Call, CallLib} from "src/lib/Call.sol";
+import {Execution, ExecutionLib} from "src/lib/Call.sol";
import {WalletLogic} from "src/wallet/WalletLogic.sol";
@@ -14,22 +14,22 @@ contract SigUtils {
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
- bytes internal constant CALL_TYPESTRING = "Call(address to,bytes callData,uint256 value)";
+ bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)";
bytes private constant EXECUTEBATCH_TYPESTRING =
- "ExecuteBatch(Call[] calls,uint256 nonce,uint256 deadline)";
+ "ExecuteBatch(Execution[] calls,uint256 nonce,uint256 deadline)";
bytes32 private constant EXECUTEBATCH_TYPEHASH =
- keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, CALL_TYPESTRING));
+ keccak256(abi.encodePacked(EXECUTEBATCH_TYPESTRING, ExecutionLib.CALL_TYPESTRING));
// computes the hash of a permit
function getStructHash(
- Call[] memory _calls,
+ Execution[] memory _calls,
uint256 _nonce,
uint256 _deadline
) internal pure returns (bytes32 structHash) {
structHash = keccak256(
- abi.encode(EXECUTEBATCH_TYPEHASH, CallLib.hashCallArray(_calls), _nonce, _deadline)
+ abi.encode(EXECUTEBATCH_TYPEHASH, ExecutionLib.hashCallArray(_calls), _nonce, _deadline)
);
return structHash;
}
@@ -37,7 +37,7 @@ contract SigUtils {
// computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer
function getTypedDataHash(
address wallet,
- Call[] memory _calls,
+ Execution[] memory _calls,
uint256 _nonce,
uint256 _deadline
) public view returns (bytes32) {
@@ -47,12 +47,10 @@ contract SigUtils {
function walletDomain(address wallet) internal view returns (bytes32) {
bytes32 _hashedName = keccak256(bytes("Supa wallet"));
- bytes32 _hashedVersion = keccak256(bytes("1.3.2"));
+ bytes32 _hashedVersion = keccak256(bytes(WalletLogic(wallet).VERSION()));
bytes32 _domainSeparatorV4 = keccak256(
abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, wallet)
);
- console.log("_domainSeparatorV4");
- console.logBytes32(_domainSeparatorV4);
return _domainSeparatorV4;
}
}
diff --git a/test/wallet.t.sol b/test/wallet.t.sol
index 7153770..a870edc 100644
--- a/test/wallet.t.sol
+++ b/test/wallet.t.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
-import {Test} from "forge-std/Test.sol";
+import {Test, console} from "forge-std/Test.sol";
import { Vm, VmSafe } from "forge-std/Vm.sol";
import {IPermit2} from "src/external/interfaces/IPermit2.sol";
@@ -14,35 +14,24 @@ import {Supa} from "src/supa/Supa.sol";
import {ISupa} from "src/interfaces/ISupa.sol";
import {SupaConfig, ISupaConfig} from "src/supa/SupaConfig.sol";
import {VersionManager, IVersionManager} from "src/supa/VersionManager.sol";
-import {WalletLogic, LinkedCall, ReturnDataLink} from "src/wallet/WalletLogic.sol";
+import {WalletLogic, LinkedExecution, ReturnDataLink} from "src/wallet/WalletLogic.sol";
import {WalletProxy} from "src/wallet/WalletProxy.sol";
-import {Call, CallLib} from "src/lib/Call.sol";
+import {Execution, ExecutionLib} from "src/lib/Call.sol";
import {ITransferReceiver2} from "src/interfaces/ITransferReceiver2.sol";
import {Errors} from "src/libraries/Errors.sol";
-//import { UniswapV3Factory } from "@uniswap/v3-core/contracts/UniswapV3Factory.sol";
-//import {SwapRouter} from "@uniswap/v3-periphery/contracts/SwapRouter.sol";
-//import { ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
-//import { Multicall } from "@uniswap/v3-periphery/contracts/base/Multicall.sol";
-
import {SigUtils, ECDSA} from "test/utils/SigUtils.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract WalletTest is Test {
- uint256 goerliFork;
IPermit2 public permit2;
TransferAndCall2 public transferAndCall2;
- IERC20 public usdc = IERC20(vm.envAddress("USDC_GOERLI"));
- IERC20 public weth = IERC20(vm.envAddress("WETH_GOERLI"));
TestNFT public nft;
TestNFT public unregisteredNFT;
- MockERC20Oracle public usdcChainlink;
- MockERC20Oracle public ethChainlink;
-
MockNFTOracle public nftOracle;
Supa public supa;
@@ -50,176 +39,70 @@ contract WalletTest is Test {
VersionManager public versionManager;
WalletLogic public proxyLogic;
+ address public user;
+ address public governance;
WalletProxy public treasuryWallet;
WalletProxy public userWallet;
- address public governance = vm.envAddress("OWNER");
+ // Create 2 tokens
+ TestERC20 public token0;
+ TestERC20 public token1;
-// UniswapV3Factory public factory;
-// SwapRouter public swapRouter;
+ MockERC20Oracle public token0Oracle;
+ MockERC20Oracle public token1Oracle;
bytes32 public constant FS_SALT = bytes32(0x1234567890123456789012345678901234567890123456789012345678901234);
function setUp() public {
- string memory GOERLI_RPC_URL = vm.envString("GOERLI_RPC_URL");
-
- goerliFork = vm.createFork(GOERLI_RPC_URL, 9_771_000);
- vm.selectFork(goerliFork);
-
- supa = Supa(payable(0x053553B8979B9FefF6e5764A294e2231D018B3A9));
-
-
-// address owner = address(this);
-//
-// usdc = new TestERC20("Circle USD", "USDC", 6);
-// weth = new TestERC20("Wrapped Ether", "WETH", 18);
-// nft = new TestNFT("Test NFT", "TNFT", 0);
-// unregisteredNFT = new TestNFT("Unregistered NFT", "UNFT", 0);
-//
-// usdcChainlink = new MockERC20Oracle(owner);
-// ethChainlink = new MockERC20Oracle(owner);
-//
-// nftOracle = new MockNFTOracle();
- versionManager = VersionManager(0xfE6939D2B10FDc83c756B1Ab3d6bF7D580dAd2B6);
-// versionManager = new VersionManager(owner);
-// supaConfig = new SupaConfig(owner);
-// supa = new Supa(address(supaConfig), address(versionManager));
+ address owner = address(this);
+ user = address(this);
+ governance = address(this);
+
+ // deploy Supa contracts
+ versionManager = new VersionManager(owner);
+ supaConfig = new SupaConfig(owner);
+ supa = new Supa(address(supaConfig), address(versionManager));
proxyLogic = new WalletLogic();
string memory VERSION = proxyLogic.VERSION();
- vm.startPrank(0xc9B6088732E83ef013873e2f04d032F1a7a2E42D);
+ versionManager.addVersion(IVersionManager.Status.PRODUCTION, address(proxyLogic));
+ versionManager.markRecommendedVersion(VERSION);
+
ISupaConfig(address(supa)).setConfig(
ISupaConfig.Config({
treasuryWallet: address(0),
treasuryInterestFraction: 0,
maxSolvencyCheckGasCost: 10_000_000,
- liqFraction: 8e17,
+ liqFraction: 0.8 ether,
fractionalReserveLeverage: 10
})
);
- versionManager.addVersion(IVersionManager.Status.PRODUCTION, address(proxyLogic));
- versionManager.markRecommendedVersion(VERSION);
- vm.stopPrank();
+ ISupaConfig(address(supa)).setTokenStorageConfig(
+ ISupaConfig.TokenStorageConfig({maxTokenStorage: 250, erc20Multiplier: 1, erc721Multiplier: 1})
+ );
-// factory = UniswapV3Factory(payable(0x1F98431c8aD98523631AE4a59f267346ea31F984));
-//
-// transferAndCall2 = TransferAndCall2(0x1554b484D2392672F0375C56d80e91c1d070a007);
-// vm.etch(address(transferAndCall2), type(TransferAndCall2).creationCode);
-// // transferAndCall2 = new TransferAndCall2{salt: FS_SALT}();
-// usdc.approve(address(transferAndCall2), type(uint256).max);
-// weth.approve(address(transferAndCall2), type(uint256).max);
- }
-// function testExecuteBatchLinkMulticall() public {
-// vm.selectFork(goerliFork);
-// userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
-//
-// address goerliWeth = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6;
-// address goerliUsdc = 0x18e526F710B8d504A735927f5Eb8BdF2F4386811;
-//
-// address pool = factory.getPool(address(goerliWeth), address(goerliUsdc), 3000);
-// console.log('pool:', pool);
-// if (pool == address(0)) {
-// factory.createPool(address(goerliWeth), address(goerliUsdc), 3000);
-// }
-//
-// swapRouter = new SwapRouter(address(factory), goerliWeth);
-//
-// deal({token: goerliWeth, to: address(this), give: 10 ether});
-// deal({token: goerliWeth, to: address(userWallet), give: 100 ether});
-//
-// uint256 wethBalance = IERC20(goerliWeth).balanceOf(address(userWallet));
-// console.log('wethBalance:', wethBalance);
-//
-// Call[] memory calls = new Call[](2);
-// calls[0] = Call({
-// to: goerliWeth,
-// callData: abi.encodeWithSelector(IERC20.approve.selector, address(swapRouter), type(uint256).max),
-// value: 0
-// });
-//
-// calls[1] = Call({
-// to: goerliUsdc,
-// callData: abi.encodeWithSelector(IERC20.approve.selector, address(swapRouter), type(uint256).max),
-// value: 0
-// });
-//
-// bytes[] memory multicallData = new bytes[](1);
-// ISwapRouter.ExactInputSingleParams memory exactInputSingle = ISwapRouter.ExactInputSingleParams({
-// tokenIn: goerliWeth,
-// tokenOut: goerliUsdc,
-// fee: 3000,
-// recipient: address(userWallet),
-// deadline: type(uint256).max,
-// amountIn: 0.1 ether,
-// amountOutMinimum: 0,
-// sqrtPriceLimitX96: 0
-// });
-// multicallData[0] = abi.encodeWithSelector(SwapRouter.exactInputSingle.selector, exactInputSingle);
-//
-//// calls[2] = Call({
-//// to: address(swapRouter),
-//// callData: abi.encodeWithSelector(Multicall.multicall.selector, multicallData),
-//// value: 0
-//// });
-//
-//// swapRouter.multicall(multicallData);
-//
-// WalletLogic(address(userWallet)).executeBatch(calls);
-//
-// // FIRST LINKED CALL
-// LinkedCall[] memory linkedCalls = new LinkedCall[](2); // todo: change to 2 for second call
-// ReturnDataLink[] memory links = new ReturnDataLink[](1);
-// linkedCalls[0] = LinkedCall({
-// call: Call({
-// to: address(swapRouter),
-// callData: abi.encodeWithSelector(Multicall.multicall.selector, multicallData),
-// value: 0
-// }),
-// links: new ReturnDataLink[](0)
-// });
-//
-//
-// // SECOND LINKED CALL
-// links[0] = ReturnDataLink({
-// returnValueOffset: 128,
-// isStatic: true,
-// callIndex: 0,
-// offset: 296
-// });
-// bytes[] memory multicallData2 = new bytes[](1);
-//// 15258789062500
-// ISwapRouter.ExactInputSingleParams memory exactInputSingle2 = ISwapRouter.ExactInputSingleParams({
-// tokenIn: goerliUsdc,
-// tokenOut: goerliWeth,
-// fee: 3000,
-// recipient: address(userWallet),
-// deadline: type(uint256).max,
-// amountIn: 1 ether,
-// amountOutMinimum: 0,
-// sqrtPriceLimitX96: 0
-// });
-// multicallData2[0] = abi.encodeWithSelector(SwapRouter.exactInputSingle.selector, exactInputSingle2);
-// linkedCalls[1] = LinkedCall({
-// call: Call({
-// to: address(swapRouter),
-// callData: abi.encodeWithSelector(Multicall.multicall.selector, multicallData2),
-// value: 0
-// }),
-// links: links
-// });
-//
-// WalletLogic(address(userWallet)).executeBatchLink(linkedCalls);
-// }
+ // setup tokens
+ token0 = new TestERC20("token0", "t0", 18);
+ token1 = new TestERC20("token1", "t1", 18);
+
+ token0Oracle = new MockERC20Oracle(owner);
+ token0Oracle.setPrice(1e18, 18, 18);
+ token0Oracle.setRiskFactors(9e17, 9e17);
+
+ token1Oracle = new MockERC20Oracle(owner);
+ token1Oracle.setPrice(1e18, 18, 18);
+ token1Oracle.setRiskFactors(9e17, 9e17);
+ }
function testExecuteBatchLinkTransfer() public {
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- deal({token: address(weth), to: address(this), give: 10 ether});
- deal({token: address(weth), to: address(userWallet), give: 10 ether});
+ deal({token: address(token0), to: address(this), give: 10 ether});
+ deal({token: address(token0), to: address(userWallet), give: 10 ether});
- LinkedCall[] memory linkedCalls = new LinkedCall[](2);
+ LinkedExecution[] memory linkedCalls = new LinkedExecution[](2);
ReturnDataLink[] memory links = new ReturnDataLink[](1);
links[0] = ReturnDataLink({
returnValueOffset: 0,
@@ -227,20 +110,20 @@ contract WalletTest is Test {
callIndex: 0,
offset: 4
});
- linkedCalls[0] = LinkedCall({
- call: Call({
- to: address(supa),
- callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)),
- value: 0
- }),
+ linkedCalls[0] = LinkedExecution({
+ execution: Execution({
+ target: address(supa),
+ value: 0,
+ callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet))
+ }),
links: new ReturnDataLink[](0)
});
- linkedCalls[1] = LinkedCall({
- call: Call({
- to: address(weth),
- callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether),
- value: 0
- }),
+ linkedCalls[1] = LinkedExecution({
+ execution: Execution({
+ target: address(token0),
+ value: 0,
+ callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether)
+ }),
links: links
});
@@ -254,11 +137,7 @@ contract WalletTest is Test {
vm.prank(wallet);
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- ISupa walletSupa = userWallet.supa();
-
- address walletOwner = supa.getWalletOwner(address(userWallet));
-
- Call[] memory calls = new Call[](0);
+ Execution[] memory calls = new Execution[](0);
uint256 nonce = 0;
uint256 deadline = type(uint256).max;
@@ -267,20 +146,18 @@ contract WalletTest is Test {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
bytes memory signature = abi.encodePacked(r, s, v);
- address recovered = ecrecover(digest, v, r, s);
-
WalletLogic(address(userWallet)).executeSignedBatch(calls, nonce, deadline, signature);
}
function testExecuteSignedBatchReplay() public {
SigUtils sigUtils = new SigUtils();
uint256 userPrivateKey = 0xB0B;
- address user = vm.addr(userPrivateKey);
- vm.prank(user);
+ address _user = vm.addr(userPrivateKey);
+ vm.startPrank(_user);
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
WalletProxy userWallet2 = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](0);
+ Execution[] memory calls = new Execution[](0);
uint256 nonce = 0;
uint256 deadline = type(uint256).max;
@@ -289,32 +166,14 @@ contract WalletTest is Test {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(userPrivateKey, digest);
bytes memory signature = abi.encodePacked(r, s, v);
- // address recovered = ecrecover(digest, v, r, s);
-
WalletLogic(address(userWallet)).executeSignedBatch(calls, nonce, deadline, signature);
vm.expectRevert(Errors.InvalidSignature.selector);
WalletLogic(address(userWallet2)).executeSignedBatch(calls, nonce, deadline, signature);
+ vm.stopPrank();
}
function testTransferAndCall2ToProxy() public {
// TODO
-
-// deal({token: address(usdc), to: address(this), give: 10_000 * 1e6});
-//
-// deal({token: address(weth), to: address(this), give: 1 * 1 ether});
-//
-// userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
-//
-// ITransferReceiver2.Transfer[] memory transfers = new ITransferReceiver2.Transfer[](2);
-//
-// transfers[0] = ITransferReceiver2.Transfer({token: address(usdc), amount: 10_000 * 1e6});
-//
-// transfers[1] = ITransferReceiver2.Transfer({token: address(weth), amount: 1 * 1 ether});
-//
-// _sortTransfers(transfers);
-//
-// bytes memory data = bytes("0x");
-// transferAndCall2.transferAndCall2(address(userWallet), transfers, data);
}
function testTransferAndCall2ToSupa() public {
@@ -388,9 +247,9 @@ contract WalletTest is Test {
function testProposeTransferWalletOwnership(address newOwner) public {
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("proposeTransferWalletOwnership(address)", newOwner),
value: 0
});
@@ -401,9 +260,9 @@ contract WalletTest is Test {
function testExecuteTransferWalletOwnership(address newOwner) public {
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("proposeTransferWalletOwnership(address)", newOwner),
value: 0
});
@@ -431,9 +290,9 @@ contract WalletTest is Test {
}
function _upgradeWalletImplementation(string memory versionName) internal {
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(supa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(supa),
callData: abi.encodeWithSignature("upgradeWalletImplementation(string)", versionName),
value: 0
});
diff --git a/test/walletMigration.t.sol b/test/walletMigration.t.sol
index d620a1f..bac4be1 100644
--- a/test/walletMigration.t.sol
+++ b/test/walletMigration.t.sol
@@ -16,9 +16,9 @@ import {MigrationSupa} from "src/testing/MigrationSupa.sol";
import {SupaConfig, ISupaConfig} from "src/supa/SupaConfig.sol";
import {SupaState} from "src/supa/SupaState.sol";
import {VersionManager, IVersionManager} from "src/supa/VersionManager.sol";
-import {WalletLogic, LinkedCall, ReturnDataLink} from "src/wallet/WalletLogic.sol";
+import {WalletLogic, LinkedExecution, ReturnDataLink} from "src/wallet/WalletLogic.sol";
import {WalletProxy} from "src/wallet/WalletProxy.sol";
-import {Call, CallLib} from "src/lib/Call.sol";
+import {Execution, ExecutionLib} from "src/lib/Call.sol";
import {ITransferReceiver2} from "src/interfaces/ITransferReceiver2.sol";
import {SigUtils, ECDSA} from "test/utils/SigUtils.sol";
@@ -31,14 +31,9 @@ contract WalletMigrationTest is Test {
IPermit2 public permit2;
TransferAndCall2 public transferAndCall2;
- TestERC20 public usdc;
- TestERC20 public weth;
TestNFT public nft;
TestNFT public unregisteredNFT;
- MockERC20Oracle public usdcChainlink;
- MockERC20Oracle public ethChainlink;
-
MockNFTOracle public nftOracle;
Supa public supa;
@@ -158,40 +153,40 @@ contract WalletMigrationTest is Test {
_mintTokens(address(userWallet), _amount0, _amount1);
// construct calls
- Call[] memory calls = new Call[](4);
+ Execution[] memory calls = new Execution[](4);
// set token allowances
calls[0] = (
- Call({
- to: address(token0),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(newSupa), _amount0),
- value: 0
- })
+ Execution({
+ target: address(token0),
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(newSupa), _amount0),
+ value: 0
+ })
);
calls[1] = (
- Call({
- to: address(token1),
- callData: abi.encodeWithSignature("approve(address,uint256)", address(newSupa), _amount1),
- value: 0
- })
+ Execution({
+ target: address(token1),
+ callData: abi.encodeWithSignature("approve(address,uint256)", address(newSupa), _amount1),
+ value: 0
+ })
);
// deposit erc20 tokens
calls[2] = (
- Call({
- to: address(newSupa),
- callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount0)),
- value: 0
- })
+ Execution({
+ target: address(newSupa),
+ callData: abi.encodeWithSignature("depositERC20(address,uint256)", token0, uint256(_amount0)),
+ value: 0
+ })
);
calls[3] = (
- Call({
- to: address(newSupa),
- callData: abi.encodeWithSignature("depositERC20(address,uint256)", token1, uint256(_amount1)),
- value: 0
- })
+ Execution({
+ target: address(newSupa),
+ callData: abi.encodeWithSignature("depositERC20(address,uint256)", token1, uint256(_amount1)),
+ value: 0
+ })
);
// execute batch
@@ -205,7 +200,7 @@ contract WalletMigrationTest is Test {
deal({token: address(token0), to: address(this), give: 10 ether});
deal({token: address(token0), to: address(userWallet), give: 10 ether});
- LinkedCall[] memory linkedCalls = new LinkedCall[](2);
+ LinkedExecution[] memory linkedCalls = new LinkedExecution[](2);
ReturnDataLink[] memory links = new ReturnDataLink[](1);
links[0] = ReturnDataLink({
returnValueOffset: 0,
@@ -213,20 +208,20 @@ contract WalletMigrationTest is Test {
callIndex: 0,
offset: 4
});
- linkedCalls[0] = LinkedCall({
- call: Call({
- to: address(newSupa),
- callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)),
- value: 0
- }),
+ linkedCalls[0] = LinkedExecution({
+ execution: Execution({
+ target: address(newSupa),
+ value: 0,
+ callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet))
+ }),
links: new ReturnDataLink[](0)
});
- linkedCalls[1] = LinkedCall({
- call: Call({
- to: address(token0),
- callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether),
- value: 0
- }),
+ linkedCalls[1] = LinkedExecution({
+ execution: Execution({
+ target: address(token0),
+ value: 0,
+ callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether)
+ }),
links: links
});
@@ -243,7 +238,7 @@ contract WalletMigrationTest is Test {
address walletOwner = supa.getWalletOwner(address(userWallet));
- Call[] memory calls = new Call[](0);
+ Execution[] memory calls = new Execution[](0);
uint256 nonce = 0;
uint256 deadline = type(uint256).max;
@@ -269,7 +264,7 @@ contract WalletMigrationTest is Test {
userWallet.updateSupa(address(newSupa));
WalletProxy userWallet2 = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
- Call[] memory calls = new Call[](0);
+ Execution[] memory calls = new Execution[](0);
uint256 nonce = 0;
uint256 deadline = type(uint256).max;
@@ -278,8 +273,6 @@ contract WalletMigrationTest is Test {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(userPrivateKey, digest);
bytes memory signature = abi.encodePacked(r, s, v);
- // address recovered = ecrecover(digest, v, r, s);
-
WalletLogic(address(userWallet)).executeSignedBatch(calls, nonce, deadline, signature);
vm.expectRevert(Errors.InvalidSignature.selector);
WalletLogic(address(userWallet2)).executeSignedBatch(calls, nonce, deadline, signature);
@@ -352,9 +345,9 @@ contract WalletMigrationTest is Test {
function testProposeTransferWalletOwnership(address newOwner) public {
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
userWallet.updateSupa(address(newSupa));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(newSupa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(newSupa),
callData: abi.encodeWithSignature("proposeTransferWalletOwnership(address)", newOwner),
value: 0
});
@@ -366,9 +359,9 @@ contract WalletMigrationTest is Test {
function testExecuteTransferWalletOwnership(address newOwner) public {
userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet()));
userWallet.updateSupa(address(newSupa));
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(newSupa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(newSupa),
callData: abi.encodeWithSignature("proposeTransferWalletOwnership(address)", newOwner),
value: 0
});
@@ -440,9 +433,9 @@ contract WalletMigrationTest is Test {
}
function _upgradeWalletImplementation(WalletProxy _userWallet, string memory versionName) internal {
- Call[] memory calls = new Call[](1);
- calls[0] = Call({
- to: address(newSupa),
+ Execution[] memory calls = new Execution[](1);
+ calls[0] = Execution({
+ target: address(newSupa),
callData: abi.encodeWithSignature("upgradeWalletImplementation(string)", versionName),
value: 0
});