From 0d63fcb06a41b42884949509dea28f778f3d9b97 Mon Sep 17 00:00:00 2001 From: SonOfMosiah Date: Fri, 2 Feb 2024 16:51:04 -0700 Subject: [PATCH 1/5] chore: migration Call -> Execution --- .idea/workspace.xml | 58 ++-- script/AddOperator.s.sol | 10 +- script/PayGasNative.s.sol | 12 +- script/setupSupa.s.sol | 8 +- src/governance/Governance.sol | 4 +- src/governance/GovernanceProxy.sol | 4 +- src/governance/OffchainEntityProxy.sol | 6 +- src/governance/Voting.sol | 4 +- src/interfaces/IERC1363-extended.sol | 4 +- src/interfaces/ISupa.sol | 4 +- src/interfaces/IWallet.sol | 6 +- src/lib/Call.sol | 34 +-- src/periphery/GelatoOperator.sol | 6 +- src/periphery/UniHelper.sol | 89 +++--- src/supa/Liquifier.sol | 8 +- src/supa/Supa.sol | 15 +- src/testing/MigrationSupa.sol | 16 +- src/testing/SimulationSupa.sol | 16 +- src/wallet/WalletLogic.sol | 64 ++-- src/wallet/WalletProxy.sol | 13 +- src/wallet/v1.0.0/WalletLogic.sol | 381 ----------------------- src/wallet/v1.0.1/WalletLogic.sol | 407 ------------------------- test/forkTesting/UniV3LPHelper.t.sol | 174 +++++------ test/forkTesting/gelato.t.sol | 88 +++--- test/gelato.t.sol | 129 ++++---- test/supa.t.sol | 152 ++++----- test/utils/SigUtils.sol | 12 +- test/wallet.t.sol | 52 ++-- test/walletMigration.t.sol | 94 +++--- 29 files changed, 523 insertions(+), 1347 deletions(-) delete mode 100644 src/wallet/v1.0.0/WalletLogic.sol delete mode 100644 src/wallet/v1.0.1/WalletLogic.sol 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 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + - { - "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/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/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/setupSupa.s.sol b/script/setupSupa.s.sol index 8f4ae92..b03bf97 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 { @@ -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 }); 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/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..7d8b40d 100644 --- a/src/periphery/GelatoOperator.sol +++ b/src/periphery/GelatoOperator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {Call, LinkedCall} from "src/lib/Call.sol"; +import {Execution, LinkedExecution} from "src/lib/Call.sol"; import {WalletProxy} from "src/wallet/WalletProxy.sol"; import {WalletLogic} from "src/wallet/WalletLogic.sol"; @@ -27,7 +27,7 @@ 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(WalletProxy _target, Execution[] calldata _calls) external onlyDedicatedSender { _target.executeBatch(_calls); } @@ -35,7 +35,7 @@ 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 executeLink(WalletLogic _target, LinkedCall[] calldata _calls) external onlyDedicatedSender { + function executeLink(WalletLogic _target, LinkedExecution[] calldata _calls) external onlyDedicatedSender { _target.executeBatchLink(_calls); } } 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/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..c227115 100644 --- a/src/wallet/WalletLogic.sol +++ b/src/wallet/WalletLogic.sol @@ -16,7 +16,7 @@ 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, 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"; @@ -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,8 +64,8 @@ contract WalletLogic is bool internal forwardNFT; NonceMap private nonceMap; - struct DynamicCall { - Call call; + struct DynamicExecution { + Execution execution; ReturnDataLink[] dynamicData; uint8 operation; // 0 = call, 1 = delegatecall } @@ -117,30 +117,10 @@ 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 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 +129,7 @@ contract WalletLogic is } function executeSignedBatch( - Call[] memory calls, + Execution[] memory calls, uint256 nonce, uint256 deadline, bytes calldata signature @@ -158,7 +138,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 +225,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 +238,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 +257,7 @@ contract WalletLogic is operator, from, keccak256(abi.encodePacked(transferDigests)), - CallLib.hashCallArray(calls), + ExecutionLib.hashCallArray(calls), nonce, deadline ) @@ -301,14 +281,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 +296,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 +309,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 +352,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 +372,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 +387,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 +433,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..687dc5d 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)); // 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) { diff --git a/test/wallet.t.sol b/test/wallet.t.sol index 7153770..94660d9 100644 --- a/test/wallet.t.sol +++ b/test/wallet.t.sol @@ -14,9 +14,9 @@ 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"; @@ -219,7 +219,7 @@ contract WalletTest is Test { deal({token: address(weth), to: address(this), give: 10 ether}); deal({token: address(weth), 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 +227,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), + callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)), + value: 0 + }), 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(weth), + callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether), + value: 0 + }), links: links }); @@ -258,7 +258,7 @@ contract WalletTest 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; @@ -280,7 +280,7 @@ contract WalletTest is Test { 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; @@ -388,9 +388,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 +401,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 +431,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..68c4a33 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"; @@ -158,40 +158,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 +205,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 +213,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), + callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)), + value: 0 + }), 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), + callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether), + value: 0 + }), links: links }); @@ -243,7 +243,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 +269,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; @@ -352,9 +352,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 +366,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 +440,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 }); From 696938c8aae6c95fe70791d48c733202bd022ebd Mon Sep 17 00:00:00 2001 From: SonOfMosiah Date: Fri, 2 Feb 2024 17:30:51 -0700 Subject: [PATCH 2/5] test: update wallet tests --- src/wallet/WalletLogic.sol | 2 +- test/utils/SigUtils.sol | 8 +- test/wallet.t.sol | 223 ++++++++----------------------------- test/walletMigration.t.sol | 15 +-- 4 files changed, 52 insertions(+), 196 deletions(-) diff --git a/src/wallet/WalletLogic.sol b/src/wallet/WalletLogic.sol index c227115..e4f6256 100644 --- a/src/wallet/WalletLogic.sol +++ b/src/wallet/WalletLogic.sol @@ -67,7 +67,7 @@ contract WalletLogic is struct DynamicExecution { Execution execution; ReturnDataLink[] dynamicData; - uint8 operation; // 0 = call, 1 = delegatecall + uint8 operation; // 0 = staticcall, 1 = delegatecall } modifier onlyOwner() { diff --git a/test/utils/SigUtils.sol b/test/utils/SigUtils.sol index 687dc5d..8784faf 100644 --- a/test/utils/SigUtils.sol +++ b/test/utils/SigUtils.sol @@ -17,10 +17,10 @@ contract SigUtils { bytes internal constant CALL_TYPESTRING = "Execution(address target,uint256 value,bytes callData)"; bytes private constant EXECUTEBATCH_TYPESTRING = - "ExecuteBatch(Execution[] 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( @@ -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 94660d9..ea5127c 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"; @@ -21,28 +21,17 @@ 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,174 +39,68 @@ 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}); LinkedExecution[] memory linkedCalls = new LinkedExecution[](2); ReturnDataLink[] memory links = new ReturnDataLink[](1); @@ -230,16 +113,16 @@ contract WalletTest is Test { linkedCalls[0] = LinkedExecution({ execution: Execution({ target: address(supa), - callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)), - value: 0 + value: 0, + callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)) }), links: new ReturnDataLink[](0) }); linkedCalls[1] = LinkedExecution({ execution: Execution({ - target: address(weth), - callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether), - value: 0 + target: address(token0), + value: 0, + callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether) }), links: links }); @@ -276,7 +159,7 @@ contract WalletTest is Test { SigUtils sigUtils = new SigUtils(); uint256 userPrivateKey = 0xB0B; address user = vm.addr(userPrivateKey); - vm.prank(user); + vm.startPrank(user); userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet())); WalletProxy userWallet2 = WalletProxy(payable(ISupaConfig(address(supa)).createWallet())); @@ -289,32 +172,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 { diff --git a/test/walletMigration.t.sol b/test/walletMigration.t.sol index 68c4a33..bac4be1 100644 --- a/test/walletMigration.t.sol +++ b/test/walletMigration.t.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; @@ -216,16 +211,16 @@ contract WalletMigrationTest is Test { linkedCalls[0] = LinkedExecution({ execution: Execution({ target: address(newSupa), - callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)), - value: 0 + value: 0, + callData: abi.encodeWithSignature("getWalletOwner(address)", address(userWallet)) }), links: new ReturnDataLink[](0) }); linkedCalls[1] = LinkedExecution({ execution: Execution({ target: address(token0), - callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether), - value: 0 + value: 0, + callData: abi.encodeWithSignature("transfer(address,uint256)", address(0), 1 ether) }), links: links }); @@ -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); From 62b05f86d255f4d9cd420e4f35a725292e705e4d Mon Sep 17 00:00:00 2001 From: SonOfMosiah Date: Fri, 2 Feb 2024 17:40:20 -0700 Subject: [PATCH 3/5] chore: save flattened contracts --- flat/gelato/TaskCreatorProxy.flat.sol | 305 ++ flat/governance/GovernanceProxy.flat.sol | 2091 ++++++++++ flat/governance/OffchainEntityProxy.flat.sol | 2889 ++++++++++++++ flat/supa/Liquifier.flat.sol | 3402 +++++++++++++++++ flat/supa/Supa.flat.sol | 70 +- flat/supa/SupaConfig.flat.sol | 80 +- flat/supa/SupaState.flat.sol | 56 +- flat/supa/TransferAndCall2.flat.sol | 3281 ++++++++++++++++ ...nager.flat.sol => VersionManager.flat.sol} | 2 + flat/wallet/WalletProxy.flat.sol | 3341 ++++++++++++++++ test/wallet.t.sol | 10 +- 11 files changed, 15485 insertions(+), 42 deletions(-) create mode 100644 flat/gelato/TaskCreatorProxy.flat.sol create mode 100644 flat/governance/GovernanceProxy.flat.sol create mode 100644 flat/governance/OffchainEntityProxy.flat.sol create mode 100644 flat/supa/Liquifier.flat.sol create mode 100644 flat/supa/TransferAndCall2.flat.sol rename flat/supa/{VersoinManager.flat.sol => VersionManager.flat.sol} (99%) create mode 100644 flat/wallet/WalletProxy.flat.sol 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/test/wallet.t.sol b/test/wallet.t.sol index ea5127c..a870edc 100644 --- a/test/wallet.t.sol +++ b/test/wallet.t.sol @@ -137,10 +137,6 @@ contract WalletTest is Test { vm.prank(wallet); userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet())); - ISupa walletSupa = userWallet.supa(); - - address walletOwner = supa.getWalletOwner(address(userWallet)); - Execution[] memory calls = new Execution[](0); uint256 nonce = 0; uint256 deadline = type(uint256).max; @@ -150,16 +146,14 @@ 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.startPrank(user); + address _user = vm.addr(userPrivateKey); + vm.startPrank(_user); userWallet = WalletProxy(payable(ISupaConfig(address(supa)).createWallet())); WalletProxy userWallet2 = WalletProxy(payable(ISupaConfig(address(supa)).createWallet())); From 1750ddf83292c8208a4b4319f89b92597f697d38 Mon Sep 17 00:00:00 2001 From: SonOfMosiah Date: Sat, 3 Feb 2024 18:35:08 -0700 Subject: [PATCH 4/5] update deploy scripts --- script/deploy/gelato/DeployTaskCreatorProxy.s.sol | 4 ++++ script/deploy/governance/GovernanceProxy.s.sol | 4 +++- script/deploy/governance/OffchainEntityProxy.s.sol | 4 +++- script/deploy/periphery/gelatoOperator.s.sol | 8 +++++--- script/deploy/periphery/uniV3LPHelper.s.sol | 5 ++++- script/deploy/supa/Supa.s.sol | 6 ++++-- script/deploy/supa/SupaConfig.s.sol | 6 ++++-- script/deploy/supa/VersionManager.s.sol | 6 ++++-- script/deploy/wallet/WalletLogic.s.sol | 5 +++-- script/initCode/{ => governance}/Governance.sol | 0 script/initCode/{ => governance}/GovernanceProxy.s.sol | 2 +- .../initCode/{ => governance}/OffchainEntityProxy.s.sol | 2 +- .../OffchainEntityProxy.transferOwnership.s.sol | 9 ++++++++- 13 files changed, 44 insertions(+), 17 deletions(-) rename script/initCode/{ => governance}/Governance.sol (100%) rename script/initCode/{ => governance}/GovernanceProxy.s.sol (88%) rename script/initCode/{ => governance}/OffchainEntityProxy.s.sol (89%) 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/governance/GovernanceProxy.s.sol b/script/deploy/governance/GovernanceProxy.s.sol index f26b4fc..b5b4da5 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"); @@ -29,3 +29,5 @@ 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 $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..6b51e38 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"); @@ -30,3 +30,5 @@ 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 $BASE_RPC_URL --broadcast -vvvv --account supa_deployer --verify --etherscan-api-key $BASESCAN_API_KEY diff --git a/script/deploy/periphery/gelatoOperator.s.sol b/script/deploy/periphery/gelatoOperator.s.sol index 166b547..9269c5a 100644 --- a/script/deploy/periphery/gelatoOperator.s.sol +++ b/script/deploy/periphery/gelatoOperator.s.sol @@ -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"); @@ -24,6 +24,8 @@ contract DeployGelatoOperator is Script { } } -// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $GOERLI_RPC_URL --broadcast -vvvv --account supa_test_deployer +// 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 +// forge script script/deploy/periphery/gelatoOperator.s.sol:DeployGelatoOperator --rpc-url $ARBITRUM_RPC_URL --broadcast -vvvv --account supa_deployer -g 100 --verify + +// 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/uniV3LPHelper.s.sol b/script/deploy/periphery/uniV3LPHelper.s.sol index b511f0d..e0057ec 100644 --- a/script/deploy/periphery/uniV3LPHelper.s.sol +++ b/script/deploy/periphery/uniV3LPHelper.s.sol @@ -11,7 +11,7 @@ contract DeployUniV3LPHelper 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"); @@ -27,5 +27,8 @@ contract DeployUniV3LPHelper is Script { } } +// cast create2 --init-code-hash $UNI_V3_LP_HELPER_INIT_CODE_HASH --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 diff --git a/script/deploy/supa/Supa.s.sol b/script/deploy/supa/Supa.s.sol index 06b29af..3bfb622 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,10 @@ 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 $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY diff --git a/script/deploy/supa/SupaConfig.s.sol b/script/deploy/supa/SupaConfig.s.sol index 833ee82..ed5d2cb 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,10 @@ 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 $BASE_RPC_URL --broadcast --verify -vvvv --account supa_deployer --etherscan-api-key $BASESCAN_API_KEY diff --git a/script/deploy/supa/VersionManager.s.sol b/script/deploy/supa/VersionManager.s.sol index cac4846..880b4f6 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 -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/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")); From 7f350b06d5e65cfbddf0b0f311cdc6bc1343a72d Mon Sep 17 00:00:00 2001 From: SonOfMosiah Date: Wed, 14 Feb 2024 10:54:37 -0700 Subject: [PATCH 5/5] Script updates --- script/CreateGovernanceSafeCalls.s.sol | 23 ++++++--- script/CreateWallet.s.sol | 24 ++++++++++ script/data/GetTokenBalance.s.sol | 6 +-- script/deploy/gelato/SetupTaskCreator.s.sol | 29 ++++++----- script/deploy/gelato/UpgradeTaskCreator.s.sol | 2 +- .../deploy/governance/GovernanceProxy.s.sol | 2 +- .../governance/OffchainEntityProxy.s.sol | 2 +- script/deploy/oracles/UniV3Oracle.s.sol | 19 ++++++-- .../oracles/UniswapV3PositionUtility.s.sol | 15 ++++-- script/deploy/periphery/gelatoOperator.s.sol | 7 ++- script/deploy/periphery/proxiedOperator.s.sol | 40 ++++++++++++++++ script/deploy/periphery/uniV3LPHelper.s.sol | 44 ++++++++++++++--- script/deploy/supa/Supa.s.sol | 6 ++- script/deploy/supa/SupaConfig.s.sol | 5 +- script/deploy/supa/VersionManager.s.sol | 2 +- .../initCode/periphery/ProxiedOperator.s.sol | 21 ++++++++ script/initCode/periphery/UniV3LPHelper.s.sol | 26 ++++++++-- script/setup/AddAdmin.s.sol | 13 ++--- script/setup/gelato/SetDepositAmount.s.sol | 6 ++- script/setup/gelato/SetGasPriceFeed.s.sol | 3 ++ script/setup/increasePowerCredits.s.sol | 21 ++++++-- script/setupSupa.s.sol | 24 +++++----- src/gelato/TaskCreator.sol | 3 -- src/interfaces/IWalletLogic.sol | 28 +++++++++++ src/periphery/GelatoOperator.sol | 11 ++--- src/periphery/ProxiedOperator.sol | 48 +++++++++++++++++++ src/periphery/UniV3LPHelper.sol | 43 ++++++++++++----- src/wallet/WalletLogic.sol | 12 ++--- 28 files changed, 382 insertions(+), 103 deletions(-) create mode 100644 script/CreateWallet.s.sol create mode 100644 script/deploy/periphery/proxiedOperator.s.sol create mode 100644 script/initCode/periphery/ProxiedOperator.s.sol create mode 100644 src/interfaces/IWalletLogic.sol create mode 100644 src/periphery/ProxiedOperator.sol 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/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/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 b5b4da5..396b34e 100644 --- a/script/deploy/governance/GovernanceProxy.s.sol +++ b/script/deploy/governance/GovernanceProxy.s.sol @@ -28,6 +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 6b51e38..a4e8ffe 100644 --- a/script/deploy/governance/OffchainEntityProxy.s.sol +++ b/script/deploy/governance/OffchainEntityProxy.s.sol @@ -29,6 +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 9269c5a..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 { @@ -20,12 +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")); } } +// cast create2 --init-code-hash $GELATO_OPERATOR_INIT_CODE_HASH --starts-with 0x00000000 + // 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 +// 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 e0057ec..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,26 +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"); - } else if (chainId == 42161 || chainId == 8453) { + 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 +// 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 3bfb622..992d1e5 100644 --- a/script/deploy/supa/Supa.s.sol +++ b/script/deploy/supa/Supa.s.sol @@ -29,6 +29,10 @@ contract DeploySupa is Script { // 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 ed5d2cb..e57312d 100644 --- a/script/deploy/supa/SupaConfig.s.sol +++ b/script/deploy/supa/SupaConfig.s.sol @@ -29,6 +29,9 @@ contract DeploySupaConfig is Script { // 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 880b4f6..e66c418 100644 --- a/script/deploy/supa/VersionManager.s.sol +++ b/script/deploy/supa/VersionManager.s.sol @@ -29,6 +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 +// 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/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/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 b03bf97..8e258b2 100644 --- a/script/setupSupa.s.sol +++ b/script/setupSupa.s.sol @@ -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) }); @@ -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/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/periphery/GelatoOperator.sol b/src/periphery/GelatoOperator.sol index 7d8b40d..da49ed0 100644 --- a/src/periphery/GelatoOperator.sol +++ b/src/periphery/GelatoOperator.sol @@ -2,8 +2,7 @@ pragma solidity ^0.8.19; import {Execution, LinkedExecution} from "src/lib/Call.sol"; -import {WalletProxy} from "src/wallet/WalletProxy.sol"; -import {WalletLogic} from "src/wallet/WalletLogic.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, Execution[] 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, LinkedExecution[] 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/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/wallet/WalletLogic.sol b/src/wallet/WalletLogic.sol index e4f6256..a0ace1a 100644 --- a/src/wallet/WalletLogic.sol +++ b/src/wallet/WalletLogic.sol @@ -13,7 +13,7 @@ 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 {ExecutionLib, Execution, LinkedExecution, ReturnDataLink} from "src/lib/Call.sol"; @@ -34,7 +34,7 @@ contract WalletLogic is IERC1271, ITransferReceiver2, EIP712, - IWallet, + IWalletLogic, IERC1363SpenderExtended { using Address for address; @@ -64,12 +64,6 @@ contract WalletLogic is bool internal forwardNFT; NonceMap private nonceMap; - struct DynamicExecution { - Execution execution; - ReturnDataLink[] dynamicData; - uint8 operation; // 0 = staticcall, 1 = delegatecall - } - modifier onlyOwner() { if (_supa().getWalletOwner(address(this)) != msg.sender) { revert Errors.OnlyOwner(); @@ -116,7 +110,7 @@ contract WalletLogic is } } - /// @inheritdoc IWallet + /// @inheritdoc IWalletLogic function executeBatch(Execution[] calldata calls) external payable onlyOwnerOrOperator { bool saveForwardNFT = forwardNFT; forwardNFT = false;