From c59d2dc57311fcf15f76fa1dcdd21f3715361f43 Mon Sep 17 00:00:00 2001 From: Utkir S Date: Mon, 23 Oct 2023 22:25:51 +0500 Subject: [PATCH] Scroll mainnet (#142) * deploy common contracts on scroll * bump version --- DEPLOYMENTS.md | 21 +-- deployments/scroll/.chainId | 1 + deployments/scroll/BalancesHelper.json | 81 +++++++++ deployments/scroll/BalancesHelperV2.json | 160 ++++++++++++++++++ .../563ec5ca6d970456eae054874235a0ad.json | 157 +++++++++++++++++ .../893c7c8579088197a1acbd2718e7b759.json | 97 +++++++++++ extensions/constants.ts | 7 + package.json | 2 +- 8 files changed, 515 insertions(+), 11 deletions(-) create mode 100644 deployments/scroll/.chainId create mode 100644 deployments/scroll/BalancesHelper.json create mode 100644 deployments/scroll/BalancesHelperV2.json create mode 100644 deployments/scroll/solcInputs/563ec5ca6d970456eae054874235a0ad.json create mode 100644 deployments/scroll/solcInputs/893c7c8579088197a1acbd2718e7b759.json diff --git a/DEPLOYMENTS.md b/DEPLOYMENTS.md index 9cd49071..2253f7a5 100644 --- a/DEPLOYMENTS.md +++ b/DEPLOYMENTS.md @@ -37,13 +37,13 @@ | `BalancesHelper` | `oktc` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://www.okx.com/en-in/explorer/oktc/address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0x3e6df48a272e00b4fb46c96f916906872c9e6e428b659fac648b5446c6906945](https://www.okx.com/en-in/explorer/oktc/tx/0x3e6df48a272e00b4fb46c96f916906872c9e6e428b659fac648b5446c6906945) | | `BalancesHelper` | `klaytnBaobab` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://baobab.scope.klaytn.com/address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0x6a52347478684dd75d355049d57a9c1085077d8aaec7c1e605a37fa82047c11d](https://baobab.scope.klaytn.com/tx/0x6a52347478684dd75d355049d57a9c1085077d8aaec7c1e605a37fa82047c11d) | | `BalancesHelper` | `klaytn` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://scope.klaytn.com/address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xa07181a89f664a6badb2cc5bd49e4142cb2c39ab37090e908333c2423cf7a0e7](https://scope.klaytn.com/tx/0xa07181a89f664a6badb2cc5bd49e4142cb2c39ab37090e908333c2423cf7a0e7) | -| `BalancesHelper` | `sepolia` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://sepolia.etherscan.io/address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xb6c0e111234e906c6273d43aeefc8e1538e7e55bf333860aa31d7dfe5b45faee](https://sepolia.etherscan.io/tx/0xb6c0e111234e906c6273d43aeefc8e1538e7e55bf333860aa31d7dfe5b45faee) | -| `BalancesHelper` | `mantle` | 0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b | 0xaffc514dbc5d185a52482b2af330dbb6248daa53e89b44067b9ce8566d5cd067 | -| `BalancesHelper` | `linea` | 0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b | 0xd3426b6b71892b9ca5a6527412bea246b50ec02e1e59d04eb1dd4a82dff6e6af | -| `BalancesHelper` | `base` | 0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b | 0xe070396dabb54b96938d864b29793266671a3ccd25ec6fd8c90208ddb5ed2111 | -| `BalancesHelper` | `coston2` | 0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b | 0x940c1ff781586e3f6d0b4143ec76cf8591fd0d0a78f8b91806dd1f6d21824b23 | +| `BalancesHelper` | `base` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://basescan.org//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xe070396dabb54b96938d864b29793266671a3ccd25ec6fd8c90208ddb5ed2111](https://basescan.org//tx/0xe070396dabb54b96938d864b29793266671a3ccd25ec6fd8c90208ddb5ed2111) | +| `BalancesHelper` | `mantle` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://explorer.mantle.xyz//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xaffc514dbc5d185a52482b2af330dbb6248daa53e89b44067b9ce8566d5cd067](https://explorer.mantle.xyz//tx/0xaffc514dbc5d185a52482b2af330dbb6248daa53e89b44067b9ce8566d5cd067) | +| `BalancesHelper` | `sepolia` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://sepolia.etherscan.io//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xb6c0e111234e906c6273d43aeefc8e1538e7e55bf333860aa31d7dfe5b45faee](https://sepolia.etherscan.io//tx/0xb6c0e111234e906c6273d43aeefc8e1538e7e55bf333860aa31d7dfe5b45faee) | +| `BalancesHelper` | `coston2` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://coston2-explorer.flare.network//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0x940c1ff781586e3f6d0b4143ec76cf8591fd0d0a78f8b91806dd1f6d21824b23](https://coston2-explorer.flare.network//tx/0x940c1ff781586e3f6d0b4143ec76cf8591fd0d0a78f8b91806dd1f6d21824b23) | | `BalancesHelper` | `etherspot` | 0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b | 0xac7270105c381ce52e137b815727c88f9f03a0005afa776154de199de41c1d33 | | `BalancesHelper` | `flare` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://flare-explorer.flare.network//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0x8c0166b58edafdc5c7c687e1305934c37b707bac8a2b9a8358a665b848727525](https://flare-explorer.flare.network//tx/0x8c0166b58edafdc5c7c687e1305934c37b707bac8a2b9a8358a665b848727525) | +| `BalancesHelper` | `scroll` | [0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b](https://scrollscan.com//address/0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b) | [0xeef293311c98b19b9a5f1995cb6a9e593482af569166fb981ffde343f7943cf8](https://scrollscan.com//tx/0xeef293311c98b19b9a5f1995cb6a9e593482af569166fb981ffde343f7943cf8) | | `BalancesHelperV2` | `mainnet` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://etherscan.io/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0xf6ea0fa211f992a6b409e3d9808abe1c3c6d9d3136969a5ee403ed9b26c9741f](https://etherscan.io/tx/0xf6ea0fa211f992a6b409e3d9808abe1c3c6d9d3136969a5ee403ed9b26c9741f) | | `BalancesHelperV2` | `ropsten` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://ropsten.etherscan.io/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x85a9b1e970b917b4af56111429d9424409e0527fec62079e6451a94de7a5c737](https://ropsten.etherscan.io/tx/0x85a9b1e970b917b4af56111429d9424409e0527fec62079e6451a94de7a5c737) | | `BalancesHelperV2` | `goerli` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://goerli.etherscan.io/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x730049031e4acf1595d7c01d6184b9fb1c6a2855753cd4b765f856a0da9fa6eb](https://goerli.etherscan.io/tx/0x730049031e4acf1595d7c01d6184b9fb1c6a2855753cd4b765f856a0da9fa6eb) | @@ -73,12 +73,13 @@ | `BalancesHelperV2` | `oktc` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://www.okx.com/en-in/explorer/oktc/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x9a94555e8d063165ef4bb26d72bba15b89ab320f46b17fd0ec6b0aa3143746ad](https://www.okx.com/en-in/explorer/oktc/tx/0x9a94555e8d063165ef4bb26d72bba15b89ab320f46b17fd0ec6b0aa3143746ad) | | `BalancesHelperV2` | `klaytnBaobab` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://baobab.scope.klaytn.com/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x77297cfc6128b621456bed32006d4f6b07ff7c3701afb1fadb86e8893cb4ca6f](https://baobab.scope.klaytn.com/tx/0x77297cfc6128b621456bed32006d4f6b07ff7c3701afb1fadb86e8893cb4ca6f) | | `BalancesHelperV2` | `klaytn` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://scope.klaytn.com/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x47e6db2109bb35ec36f5a14854d3df328f840238554527aff227cce0b0a3cd35](https://scope.klaytn.com/tx/0x47e6db2109bb35ec36f5a14854d3df328f840238554527aff227cce0b0a3cd35) | +| `BalancesHelperV2` | `base` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://basescan.org//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0xad34b9ac6208f50ff1542ce0bae65d4d5a61e8f3071e62cf14079b7994c284c6](https://basescan.org//tx/0xad34b9ac6208f50ff1542ce0bae65d4d5a61e8f3071e62cf14079b7994c284c6) | +| `BalancesHelperV2` | `mantle` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://explorer.mantle.xyz//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x17d9b8a2af44091014bff4808bf02feb804fc864184e29f7aaed9c9fd7186003](https://explorer.mantle.xyz//tx/0x17d9b8a2af44091014bff4808bf02feb804fc864184e29f7aaed9c9fd7186003) | +| `BalancesHelperV2` | `linea` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://lineascan.build//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x26f0bacb7f0883dba8878b9567e4dee1fd96d0b287e0741a7693e02ba4fbb177](https://lineascan.build//tx/0x26f0bacb7f0883dba8878b9567e4dee1fd96d0b287e0741a7693e02ba4fbb177) | +| `BalancesHelperV2` | `sepolia` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://sepolia.etherscan.io//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x7d157cb0e07f0fb7a32440f6289d4b0c56db4e783eb83530765b942fc93b20cd](https://sepolia.etherscan.io//tx/0x7d157cb0e07f0fb7a32440f6289d4b0c56db4e783eb83530765b942fc93b20cd) | +| `BalancesHelperV2` | `coston2` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://coston2-explorer.flare.network//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x6d8393ad5205c197341a76770bb9b30c58b600daa00ec01e4de842ee4abcf8d9](https://coston2-explorer.flare.network//tx/0x6d8393ad5205c197341a76770bb9b30c58b600daa00ec01e4de842ee4abcf8d9) | | `BalancesHelperV2` | `flare` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://flare-explorer.flare.network//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x6bf32f01e5704f7e7ae84f825a58151aa66de4cc4ba62bd4a7df7962979db0fd](https://flare-explorer.flare.network//tx/0x6bf32f01e5704f7e7ae84f825a58151aa66de4cc4ba62bd4a7df7962979db0fd) | -| `BalancesHelperV2` | `sepolia` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://sepolia.etherscan.io/address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x7d157cb0e07f0fb7a32440f6289d4b0c56db4e783eb83530765b942fc93b20cd](https://sepolia.etherscan.io/tx/0x7d157cb0e07f0fb7a32440f6289d4b0c56db4e783eb83530765b942fc93b20cd) | -| `BalancesHelperV2` | `mantle` | 0xe5A160F89f330cc933816E896a3F36376DE0a835 | 0x17d9b8a2af44091014bff4808bf02feb804fc864184e29f7aaed9c9fd7186003 | -| `BalancesHelperV2` | `linea` | 0xe5A160F89f330cc933816E896a3F36376DE0a835 | 0x26f0bacb7f0883dba8878b9567e4dee1fd96d0b287e0741a7693e02ba4fbb177 | -| `BalancesHelperV2` | `base` | 0xe5A160F89f330cc933816E896a3F36376DE0a835 | 0xad34b9ac6208f50ff1542ce0bae65d4d5a61e8f3071e62cf14079b7994c284c6 | -| `BalancesHelperV2` | `coston2` | 0xe5A160F89f330cc933816E896a3F36376DE0a835 | 0x6d8393ad5205c197341a76770bb9b30c58b600daa00ec01e4de842ee4abcf8d9 | +| `BalancesHelperV2` | `scroll` | [0xe5A160F89f330cc933816E896a3F36376DE0a835](https://scrollscan.com//address/0xe5A160F89f330cc933816E896a3F36376DE0a835) | [0x04238b9feb0412107cd9001648130862e94210456fe9c183e5acbe19ce619add](https://scrollscan.com//tx/0x04238b9feb0412107cd9001648130862e94210456fe9c183e5acbe19ce619add) | | `CBridgeFacet` | `goerli` | [0x9d70f5253949Eb67850C3f1e7371f15b955ee073](https://goerli.etherscan.io/address/0x9d70f5253949Eb67850C3f1e7371f15b955ee073) | [0x047d8e991a3dc6bac32e2ef5d08078ecbf10abe3f32c20a7d87b32a2647a2390](https://goerli.etherscan.io/tx/0x047d8e991a3dc6bac32e2ef5d08078ecbf10abe3f32c20a7d87b32a2647a2390) | | `CBridgeFacet` | `kovan` | [0x9d70f5253949Eb67850C3f1e7371f15b955ee073](https://kovan.etherscan.io/address/0x9d70f5253949Eb67850C3f1e7371f15b955ee073) | [0xf21e1a247dd0a72b5b59ec4556972b6fde6ba038adc000797f643fe71bf93855](https://kovan.etherscan.io/tx/0xf21e1a247dd0a72b5b59ec4556972b6fde6ba038adc000797f643fe71bf93855) | | `CBridgeFacet` | `bscTest` | [0x9d70f5253949Eb67850C3f1e7371f15b955ee073](https://testnet.bscscan.com/address/0x9d70f5253949Eb67850C3f1e7371f15b955ee073) | [0xd72b937134f4fc4d6168bf1dbbe495971df40e540d83e2293e333ca9c5a9567d](https://testnet.bscscan.com/tx/0xd72b937134f4fc4d6168bf1dbbe495971df40e540d83e2293e333ca9c5a9567d) | diff --git a/deployments/scroll/.chainId b/deployments/scroll/.chainId new file mode 100644 index 00000000..9ff67903 --- /dev/null +++ b/deployments/scroll/.chainId @@ -0,0 +1 @@ +534352 \ No newline at end of file diff --git a/deployments/scroll/BalancesHelper.json b/deployments/scroll/BalancesHelper.json new file mode 100644 index 00000000..371c223b --- /dev/null +++ b/deployments/scroll/BalancesHelper.json @@ -0,0 +1,81 @@ +{ + "address": "0xa6C165E3539A2bE6d55e2935EC9979D8C850A21b", + "abi": [ + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "getBalances", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xeef293311c98b19b9a5f1995cb6a9e593482af569166fb981ffde343f7943cf8", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0x09FD4F6088f2025427AB1e89257A44747081Ed59", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "420528", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcfe0641c99497639f5f2a530442fe0f5bda56a5b76c60d11691a8ea828d9a2ea", + "transactionHash": "0xeef293311c98b19b9a5f1995cb6a9e593482af569166fb981ffde343f7943cf8", + "logs": [], + "blockNumber": 237025, + "cumulativeGasUsed": "420528", + "status": 1, + "byzantium": true + }, + "args": [], + "solcInputHash": "563ec5ca6d970456eae054874235a0ad", + "metadata": "{\"compiler\":{\"version\":\"0.6.12+commit.27d51765\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getBalances\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Jegor Sidorenko Stanis\\u0142aw G\\u0142ogowski \",\"kind\":\"dev\",\"methods\":{\"getBalances(address[],address[])\":{\"details\":\"Pass 0x0 as a \\\"token\\\" address to get ETH balance. Possible error throws: - extremely large arrays for account and or tokens (gas cost too high)\",\"params\":{\"accounts\":\"array of accounts addresses\",\"tokens\":\"array of tokens addresses\"},\"returns\":{\"_0\":\"a one-dimensional that's user.length * tokens.length long. The array is ordered by all of the 0th accounts token balances, then the 1th user, and so on.\"}}},\"title\":\"Balances helper\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getBalances(address[],address[])\":{\"notice\":\"Checks the token balances of accounts for multiple tokens.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/common/helpers/BalancesHelper.sol\":\"BalancesHelper\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/common/helpers/BalancesHelper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.6.12;\\n\\nimport \\\"../token/ERC20Token.sol\\\";\\nimport \\\"../libs/SafeMathLib.sol\\\";\\n\\n\\n/**\\n * @title Balances helper\\n *\\n * @author Jegor Sidorenko \\n * @author Stanis\\u0142aw G\\u0142ogowski \\n */\\ncontract BalancesHelper {\\n using SafeMathLib for uint256;\\n\\n // external functions\\n\\n /**\\n * @notice Checks the token balances of accounts for multiple tokens.\\n * @dev Pass 0x0 as a \\\"token\\\" address to get ETH balance.\\n *\\n * Possible error throws:\\n * - extremely large arrays for account and or tokens (gas cost too high)\\n *\\n * @param accounts array of accounts addresses\\n * @param tokens array of tokens addresses\\n * @return a one-dimensional that's user.length * tokens.length long. The\\n * array is ordered by all of the 0th accounts token balances, then the 1th\\n * user, and so on.\\n */\\n function getBalances(\\n address[] calldata accounts,\\n address[] calldata tokens\\n )\\n external\\n view\\n returns (uint[] memory)\\n {\\n uint[] memory result = new uint[](accounts.length.mul(tokens.length));\\n\\n for (uint i = 0; i < accounts.length; i++) {\\n for (uint j = 0; j < tokens.length; j++) {\\n uint index = j.add(tokens.length.mul(i));\\n\\n if (tokens[j] != address(0x0)) {\\n result[index] = _getBalance(accounts[i], tokens[j]);\\n } else {\\n result[index] = accounts[i].balance;\\n }\\n }\\n }\\n\\n return result;\\n }\\n\\n // private functions\\n\\n function _getBalance(\\n address account,\\n address token\\n )\\n private\\n view\\n returns (uint256)\\n {\\n uint256 result = 0;\\n uint256 tokenCode;\\n\\n /// @dev check if token is actually a contract\\n // solhint-disable-next-line no-inline-assembly\\n assembly { tokenCode := extcodesize(token) } // contract code size\\n\\n if (tokenCode > 0) {\\n /// @dev is it a contract and does it implement balanceOf\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool methodExists,) = token.staticcall(abi.encodeWithSelector(\\n ERC20Token(token).balanceOf.selector,\\n account\\n ));\\n\\n if (methodExists) {\\n result = ERC20Token(token).balanceOf(account);\\n }\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0x76a5729807b8581731967ea74fc5e16a2c5c9067457c9059da97f089ffff68b9\",\"license\":\"MIT\"},\"src/common/libs/SafeMathLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.6.12;\\n\\n/**\\n * @title Safe math library\\n *\\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/math/SafeMath.sol\\n */\\nlibrary SafeMathLib {\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n\\n require(c >= a, \\\"SafeMathLib: addition overflow\\\");\\n\\n return c;\\n }\\n\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMathLib: subtraction overflow\\\");\\n }\\n\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n\\n return a - b;\\n }\\n\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n\\n require(c / a == b, \\\"SafeMathLib: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMathLib: division by zero\\\");\\n }\\n\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b > 0, errorMessage);\\n\\n return a / b;\\n }\\n\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMathLib: modulo by zero\\\");\\n }\\n\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x6089f354ca754d9c5dd9e800ee5ed86717dbf8f9af470604e0be691ac57c0107\",\"license\":\"MIT\"},\"src/common/token/ERC20Token.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.6.12;\\n\\nimport \\\"../libs/SafeMathLib.sol\\\";\\n\\n\\n/**\\n * @title ERC20 token\\n *\\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/token/ERC20/ERC20.sol\\n */\\ncontract ERC20Token {\\n using SafeMathLib for uint256;\\n\\n string public name;\\n string public symbol;\\n uint8 public decimals;\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) internal balances;\\n mapping(address => mapping(address => uint256)) internal allowances;\\n\\n // events\\n\\n event Transfer(\\n address indexed from,\\n address indexed to,\\n uint256 value\\n );\\n\\n event Approval(\\n address indexed owner,\\n address indexed spender,\\n uint256 value\\n );\\n\\n /**\\n * @dev internal constructor\\n */\\n constructor() internal {}\\n\\n // external functions\\n\\n function transfer(\\n address to,\\n uint256 value\\n )\\n external\\n returns (bool)\\n {\\n _transfer(_getSender(), to, value);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 value\\n )\\n virtual\\n external\\n returns (bool)\\n {\\n address sender = _getSender();\\n\\n _transfer(from, to, value);\\n _approve(from, sender, allowances[from][sender].sub(value));\\n\\n return true;\\n }\\n\\n function approve(\\n address spender,\\n uint256 value\\n )\\n virtual\\n external\\n returns (bool)\\n {\\n _approve(_getSender(), spender, value);\\n\\n return true;\\n }\\n\\n // external functions (views)\\n\\n function balanceOf(\\n address owner\\n )\\n virtual\\n external\\n view\\n returns (uint256)\\n {\\n return balances[owner];\\n }\\n\\n function allowance(\\n address owner,\\n address spender\\n )\\n virtual\\n external\\n view\\n returns (uint256)\\n {\\n return allowances[owner][spender];\\n }\\n\\n // internal functions\\n\\n function _transfer(\\n address from,\\n address to,\\n uint256 value\\n )\\n virtual\\n internal\\n {\\n require(\\n from != address(0),\\n \\\"ERC20Token: cannot transfer from 0x0 address\\\"\\n );\\n require(\\n to != address(0),\\n \\\"ERC20Token: cannot transfer to 0x0 address\\\"\\n );\\n\\n balances[from] = balances[from].sub(value);\\n balances[to] = balances[to].add(value);\\n\\n emit Transfer(from, to, value);\\n }\\n\\n function _approve(\\n address owner,\\n address spender,\\n uint256 value\\n )\\n virtual\\n internal\\n {\\n require(\\n owner != address(0),\\n \\\"ERC20Token: cannot approve from 0x0 address\\\"\\n );\\n require(\\n spender != address(0),\\n \\\"ERC20Token: cannot approve to 0x0 address\\\"\\n );\\n\\n allowances[owner][spender] = value;\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function _mint(\\n address owner,\\n uint256 value\\n )\\n virtual\\n internal\\n {\\n require(\\n owner != address(0),\\n \\\"ERC20Token: cannot mint to 0x0 address\\\"\\n );\\n require(\\n value > 0,\\n \\\"ERC20Token: cannot mint 0 value\\\"\\n );\\n\\n balances[owner] = balances[owner].add(value);\\n totalSupply = totalSupply.add(value);\\n\\n emit Transfer(address(0), owner, value);\\n }\\n\\n function _burn(\\n address owner,\\n uint256 value\\n )\\n virtual\\n internal\\n {\\n require(\\n owner != address(0),\\n \\\"ERC20Token: cannot burn from 0x0 address\\\"\\n );\\n\\n balances[owner] = balances[owner].sub(\\n value,\\n \\\"ERC20Token: burn value exceeds balance\\\"\\n );\\n\\n totalSupply = totalSupply.sub(value);\\n\\n emit Transfer(owner, address(0), value);\\n }\\n\\n // internal functions (views)\\n\\n function _getSender()\\n virtual\\n internal\\n view\\n returns (address)\\n {\\n return msg.sender;\\n }\\n}\\n\",\"keccak256\":\"0x6f2b0bd08da549c6c1f5ceee85766832d587dde62c56bebc3a14bd9ea407e03d\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506106a2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ef5bfc3714610030575b600080fd5b6100fc6004803603604081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184602083028401116401000000008311171561009757600080fd5b9091929391929390803590602001906401000000008111156100b857600080fd5b8201836020820111156100ca57600080fd5b803590602001918460208302840111640100000000831117156100ec57600080fd5b9091929391929390505050610153565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561013f578082015181840152602081019050610124565b505050509050019250505060405180910390f35b60608061016f848490508787905061035490919063ffffffff16565b67ffffffffffffffff8111801561018557600080fd5b506040519080825280602002602001820160405280156101b45781602001602082028036833780820191505090505b50905060005b868690508110156103475760005b858590508110156103395760006101fd6101ee848989905061035490919063ffffffff16565b836103da90919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff1687878481811061022357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146102d2576102b589898581811061026a57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1688888581811061029357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16610462565b8482815181106102c157fe5b60200260200101818152505061032b565b8888848181106102de57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163184828151811061031e57fe5b6020026020010181815250505b5080806001019150506101c8565b5080806001019150506101ba565b5080915050949350505050565b60008083141561036757600090506103d4565b600082840290508284828161037857fe5b04146103cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806106726024913960400191505060405180910390fd5b809150505b92915050565b600080828401905083811015610458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174684c69623a206164646974696f6e206f766572666c6f77000081525060200191505060405180910390fd5b8091505092915050565b600080600090506000833b905060008111156106665760008473ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b87604051602401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310610550578051825260208201915060208101905060208303925061052d565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b505090508015610664578473ffffffffffffffffffffffffffffffffffffffff166370a08231876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561062657600080fd5b505afa15801561063a573d6000803e3d6000fd5b505050506040513d602081101561065057600080fd5b810190808051906020019092919050505092505b505b81925050509291505056fe536166654d6174684c69623a206d756c7469706c69636174696f6e206f766572666c6f77a164736f6c634300060c000a", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ef5bfc3714610030575b600080fd5b6100fc6004803603604081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184602083028401116401000000008311171561009757600080fd5b9091929391929390803590602001906401000000008111156100b857600080fd5b8201836020820111156100ca57600080fd5b803590602001918460208302840111640100000000831117156100ec57600080fd5b9091929391929390505050610153565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561013f578082015181840152602081019050610124565b505050509050019250505060405180910390f35b60608061016f848490508787905061035490919063ffffffff16565b67ffffffffffffffff8111801561018557600080fd5b506040519080825280602002602001820160405280156101b45781602001602082028036833780820191505090505b50905060005b868690508110156103475760005b858590508110156103395760006101fd6101ee848989905061035490919063ffffffff16565b836103da90919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff1687878481811061022357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146102d2576102b589898581811061026a57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1688888581811061029357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16610462565b8482815181106102c157fe5b60200260200101818152505061032b565b8888848181106102de57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163184828151811061031e57fe5b6020026020010181815250505b5080806001019150506101c8565b5080806001019150506101ba565b5080915050949350505050565b60008083141561036757600090506103d4565b600082840290508284828161037857fe5b04146103cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806106726024913960400191505060405180910390fd5b809150505b92915050565b600080828401905083811015610458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174684c69623a206164646974696f6e206f766572666c6f77000081525060200191505060405180910390fd5b8091505092915050565b600080600090506000833b905060008111156106665760008473ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b87604051602401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310610550578051825260208201915060208101905060208303925061052d565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b505090508015610664578473ffffffffffffffffffffffffffffffffffffffff166370a08231876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561062657600080fd5b505afa15801561063a573d6000803e3d6000fd5b505050506040513d602081101561065057600080fd5b810190808051906020019092919050505092505b505b81925050509291505056fe536166654d6174684c69623a206d756c7469706c69636174696f6e206f766572666c6f77a164736f6c634300060c000a", + "devdoc": { + "author": "Jegor Sidorenko Stanisław Głogowski ", + "kind": "dev", + "methods": { + "getBalances(address[],address[])": { + "details": "Pass 0x0 as a \"token\" address to get ETH balance. Possible error throws: - extremely large arrays for account and or tokens (gas cost too high)", + "params": { + "accounts": "array of accounts addresses", + "tokens": "array of tokens addresses" + }, + "returns": { + "_0": "a one-dimensional that's user.length * tokens.length long. The array is ordered by all of the 0th accounts token balances, then the 1th user, and so on." + } + } + }, + "title": "Balances helper", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "getBalances(address[],address[])": { + "notice": "Checks the token balances of accounts for multiple tokens." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/deployments/scroll/BalancesHelperV2.json b/deployments/scroll/BalancesHelperV2.json new file mode 100644 index 00000000..6717f8a3 --- /dev/null +++ b/deployments/scroll/BalancesHelperV2.json @@ -0,0 +1,160 @@ +{ + "address": "0xe5A160F89f330cc933816E896a3F36376DE0a835", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "AccountZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "TokenZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "getBalances", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "getSuperfluidWrappedTokenBalances", + "outputs": [ + { + "internalType": "int256[]", + "name": "", + "type": "int256[]" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x04238b9feb0412107cd9001648130862e94210456fe9c183e5acbe19ce619add", + "receipt": { + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", + "from": "0x09FD4F6088f2025427AB1e89257A44747081Ed59", + "contractAddress": null, + "transactionIndex": 0, + "gasUsed": "964471", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x81549f3f5deebdfad2c981651116552168a3064f3f89dd5df161e0182c9d438f", + "transactionHash": "0x04238b9feb0412107cd9001648130862e94210456fe9c183e5acbe19ce619add", + "logs": [], + "blockNumber": 237028, + "cumulativeGasUsed": "964471", + "status": 1, + "byzantium": true + }, + "args": [], + "solcInputHash": "893c7c8579088197a1acbd2718e7b759", + "metadata": "{\"compiler\":{\"version\":\"0.8.4+commit.c7e474f2\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"AccountZeroAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenZeroAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getBalances\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getSuperfluidWrappedTokenBalances\",\"outputs\":[{\"internalType\":\"int256[]\",\"name\":\"\",\"type\":\"int256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getBalances(address[],address[])\":{\"details\":\"Error thrown if: account or token address is address(0), large arrays of accounts/tokens are passed in could cause gas block limit issue\",\"params\":{\"accounts\":\"= Array of accounts addresses\",\"tokens\":\"= Array of tokens addresses\"},\"returns\":{\"_0\":\"One-dimensional that's accounts.length * tokens.length long. The array is ordered by all of accounts[0] token balances, then accounts[1] etc.\"}},\"getSuperfluidWrappedTokenBalances(address[],address[])\":{\"details\":\"Error thrown if: account or token address is address(0), large arrays of accounts/tokens are passed in could cause gas block limit issue\",\"params\":{\"accounts\":\"= Array of accounts addresses\",\"tokens\":\"= Array of tokens addresses\"},\"returns\":{\"_0\":\"One-dimensional that's accounts.length * tokens.length long. The array is ordered by all of accounts[0] token balances, then accounts[1] etc.\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"AccountZeroAddress(address,address)\":[{\"notice\":\"Custom errors to handle address(0)\"}]},\"kind\":\"user\",\"methods\":{\"getBalances(address[],address[])\":{\"notice\":\"Returns balances of accounts for multiple ERC20 tokens.\"},\"getSuperfluidWrappedTokenBalances(address[],address[])\":{\"notice\":\"Returns balances of accounts for multiple Wrapped Super Tokens.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/common/helpers/BalancesHelperV2.sol\":\"BalancesHelperV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol\":{\"content\":\"// SPDX-License-Identifier: AGPLv3\\npragma solidity >= 0.8.0;\\n\\nimport { ISuperfluidToken } from \\\"./ISuperfluidToken.sol\\\";\\n\\n/**\\n * @title Super agreement interface\\n * @author Superfluid\\n */\\ninterface ISuperAgreement {\\n\\n /**\\n * @dev Get the type of the agreement class\\n */\\n function agreementType() external view returns (bytes32);\\n\\n /**\\n * @dev Calculate the real-time balance for the account of this agreement class\\n * @param account Account the state belongs to\\n * @param time Time used for the calculation\\n * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement\\n * @return deposit Account deposit amount of this agreement\\n * @return owedDeposit Account owed deposit amount of this agreement\\n */\\n function realtimeBalanceOf(\\n ISuperfluidToken token,\\n address account,\\n uint256 time\\n )\\n external\\n view\\n returns (\\n int256 dynamicBalance,\\n uint256 deposit,\\n uint256 owedDeposit\\n );\\n\\n}\\n\",\"keccak256\":\"0xc3a6a907245116bcecc70fe4b207454012e8ce4fa190228fb8bbe39e0b1bc5cf\",\"license\":\"AGPLv3\"},\"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol\":{\"content\":\"// SPDX-License-Identifier: AGPLv3\\npragma solidity >= 0.8.0;\\n\\nimport { ISuperAgreement } from \\\"./ISuperAgreement.sol\\\";\\n\\n\\n/**\\n * @title Superfluid token interface\\n * @author Superfluid\\n */\\ninterface ISuperfluidToken {\\n\\n /**************************************************************************\\n * Basic information\\n *************************************************************************/\\n\\n /**\\n * @dev Get superfluid host contract address\\n */\\n function getHost() external view returns(address host);\\n\\n /**\\n * @dev Encoded liquidation type data mainly used for handling stack to deep errors\\n *\\n * Note:\\n * - version: 1\\n * - liquidationType key:\\n * - 0 = reward account receives reward (PIC period)\\n * - 1 = liquidator account receives reward (Pleb period)\\n * - 2 = liquidator account receives reward (Pirate period/bailout)\\n */\\n struct LiquidationTypeData {\\n uint256 version;\\n uint8 liquidationType;\\n }\\n\\n /**************************************************************************\\n * Real-time balance functions\\n *************************************************************************/\\n\\n /**\\n * @dev Calculate the real balance of a user, taking in consideration all agreements of the account\\n * @param account for the query\\n * @param timestamp Time of balance\\n * @return availableBalance Real-time balance\\n * @return deposit Account deposit\\n * @return owedDeposit Account owed Deposit\\n */\\n function realtimeBalanceOf(\\n address account,\\n uint256 timestamp\\n )\\n external view\\n returns (\\n int256 availableBalance,\\n uint256 deposit,\\n uint256 owedDeposit);\\n\\n /**\\n * @notice Calculate the realtime balance given the current host.getNow() value\\n * @dev realtimeBalanceOf with timestamp equals to block timestamp\\n * @param account for the query\\n * @return availableBalance Real-time balance\\n * @return deposit Account deposit\\n * @return owedDeposit Account owed Deposit\\n */\\n function realtimeBalanceOfNow(\\n address account\\n )\\n external view\\n returns (\\n int256 availableBalance,\\n uint256 deposit,\\n uint256 owedDeposit,\\n uint256 timestamp);\\n\\n /**\\n * @notice Check if account is critical\\n * @dev A critical account is when availableBalance < 0\\n * @param account The account to check\\n * @param timestamp The time we'd like to check if the account is critical (should use future)\\n * @return isCritical Whether the account is critical\\n */\\n function isAccountCritical(\\n address account,\\n uint256 timestamp\\n )\\n external view\\n returns(bool isCritical);\\n\\n /**\\n * @notice Check if account is critical now (current host.getNow())\\n * @dev A critical account is when availableBalance < 0\\n * @param account The account to check\\n * @return isCritical Whether the account is critical\\n */\\n function isAccountCriticalNow(\\n address account\\n )\\n external view\\n returns(bool isCritical);\\n\\n /**\\n * @notice Check if account is solvent\\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\\n * @param account The account to check\\n * @param timestamp The time we'd like to check if the account is solvent (should use future)\\n * @return isSolvent\\n */\\n function isAccountSolvent(\\n address account,\\n uint256 timestamp\\n )\\n external view\\n returns(bool isSolvent);\\n\\n /**\\n * @notice Check if account is solvent now\\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\\n * @param account The account to check\\n * @return isSolvent\\n */\\n function isAccountSolventNow(\\n address account\\n )\\n external view\\n returns(bool isSolvent);\\n\\n /**\\n * @notice Get a list of agreements that is active for the account\\n * @dev An active agreement is one that has state for the account\\n * @param account Account to query\\n * @return activeAgreements List of accounts that have non-zero states for the account\\n */\\n function getAccountActiveAgreements(address account)\\n external view\\n returns(ISuperAgreement[] memory activeAgreements);\\n\\n\\n /**************************************************************************\\n * Super Agreement hosting functions\\n *************************************************************************/\\n\\n /**\\n * @dev Create a new agreement\\n * @param id Agreement ID\\n * @param data Agreement data\\n */\\n function createAgreement(\\n bytes32 id,\\n bytes32[] calldata data\\n )\\n external;\\n /**\\n * @dev Agreement created event\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @param data Agreement data\\n */\\n event AgreementCreated(\\n address indexed agreementClass,\\n bytes32 id,\\n bytes32[] data\\n );\\n\\n /**\\n * @dev Get data of the agreement\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @return data Data of the agreement\\n */\\n function getAgreementData(\\n address agreementClass,\\n bytes32 id,\\n uint dataLength\\n )\\n external view\\n returns(bytes32[] memory data);\\n\\n /**\\n * @dev Create a new agreement\\n * @param id Agreement ID\\n * @param data Agreement data\\n */\\n function updateAgreementData(\\n bytes32 id,\\n bytes32[] calldata data\\n )\\n external;\\n /**\\n * @dev Agreement updated event\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @param data Agreement data\\n */\\n event AgreementUpdated(\\n address indexed agreementClass,\\n bytes32 id,\\n bytes32[] data\\n );\\n\\n /**\\n * @dev Close the agreement\\n * @param id Agreement ID\\n */\\n function terminateAgreement(\\n bytes32 id,\\n uint dataLength\\n )\\n external;\\n /**\\n * @dev Agreement terminated event\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n */\\n event AgreementTerminated(\\n address indexed agreementClass,\\n bytes32 id\\n );\\n\\n /**\\n * @dev Update agreement state slot\\n * @param account Account to be updated\\n *\\n * NOTE\\n * - To clear the storage out, provide zero-ed array of intended length\\n */\\n function updateAgreementStateSlot(\\n address account,\\n uint256 slotId,\\n bytes32[] calldata slotData\\n )\\n external;\\n /**\\n * @dev Agreement account state updated event\\n * @param agreementClass Contract address of the agreement\\n * @param account Account updated\\n * @param slotId slot id of the agreement state\\n */\\n event AgreementStateUpdated(\\n address indexed agreementClass,\\n address indexed account,\\n uint256 slotId\\n );\\n\\n /**\\n * @dev Get data of the slot of the state of an agreement\\n * @param agreementClass Contract address of the agreement\\n * @param account Account to query\\n * @param slotId slot id of the state\\n * @param dataLength length of the state data\\n */\\n function getAgreementStateSlot(\\n address agreementClass,\\n address account,\\n uint256 slotId,\\n uint dataLength\\n )\\n external view\\n returns (bytes32[] memory slotData);\\n\\n /**\\n * @notice Settle balance from an account by the agreement\\n * @dev The agreement needs to make sure that the balance delta is balanced afterwards\\n * @param account Account to query.\\n * @param delta Amount of balance delta to be settled\\n *\\n * Modifiers:\\n * - onlyAgreement\\n */\\n function settleBalance(\\n address account,\\n int256 delta\\n )\\n external;\\n\\n /**\\n * @dev Make liquidation payouts (v2)\\n * @param id Agreement ID\\n * @param liquidationTypeData Data regarding the version of the liquidation schema and the type\\n * @param liquidatorAccount Address of the executor of the liquidation\\n * @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount\\n * @param targetAccount Account of the stream sender\\n * @param rewardAmount The amount the reward recepient account will receive\\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\\n *\\n * - If a bailout is required (bailoutAmount > 0)\\n * - the actual reward (single deposit) goes to the executor,\\n * - while the reward account becomes the bailout account\\n * - total bailout include: bailout amount + reward amount\\n * - the targetAccount will be bailed out\\n * - If a bailout is not required\\n * - the targetAccount will pay the rewardAmount\\n * - the liquidator (reward account in PIC period) will receive the rewardAmount\\n *\\n * Modifiers:\\n * - onlyAgreement\\n */\\n function makeLiquidationPayoutsV2\\n (\\n bytes32 id,\\n bytes memory liquidationTypeData,\\n address liquidatorAccount,\\n bool useDefaultRewardAccount,\\n address targetAccount,\\n uint256 rewardAmount,\\n int256 targetAccountBalanceDelta\\n ) external;\\n /**\\n * @dev Agreement liquidation event v2 (including agent account)\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @param liquidatorAccount Address of the executor of the liquidation\\n * @param targetAccount Account of the stream sender\\n * @param rewardAccount Account that collects the reward or bails out insolvent accounts\\n * @param rewardAmount The amount the reward recipient account balance should change by\\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\\n * @param liquidationTypeData The encoded liquidation type data including the version (how to decode)\\n *\\n * NOTE:\\n * Reward account rule:\\n * - if the agreement is liquidated during the PIC period\\n * - the rewardAccount will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount\\n * - the targetAccount will pay for the rewardAmount\\n * - if the agreement is liquidated after the PIC period AND the targetAccount is solvent\\n * - the liquidatorAccount will get the rewardAmount (remaining deposit)\\n * - the targetAccount will pay for the rewardAmount\\n * - if the targetAccount is insolvent\\n * - the liquidatorAccount will get the rewardAmount (single deposit)\\n * - the rewardAccount will pay for both the rewardAmount and bailoutAmount\\n * - the targetAccount will receive the bailoutAmount\\n */\\n event AgreementLiquidatedV2(\\n address indexed agreementClass,\\n bytes32 id,\\n address indexed liquidatorAccount,\\n address indexed targetAccount,\\n address rewardAccount,\\n uint256 rewardAmount,\\n int256 targetAccountBalanceDelta,\\n bytes liquidationTypeData\\n );\\n\\n /**************************************************************************\\n * Function modifiers for access control and parameter validations\\n *\\n * While they cannot be explicitly stated in function definitions, they are\\n * listed in function definition comments instead for clarity.\\n *\\n * NOTE: solidity-coverage not supporting it\\n *************************************************************************/\\n\\n /// @dev The msg.sender must be host contract\\n //modifier onlyHost() virtual;\\n\\n /// @dev The msg.sender must be a listed agreement.\\n //modifier onlyAgreement() virtual;\\n\\n /**************************************************************************\\n * DEPRECATED\\n *************************************************************************/\\n\\n /**\\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy)\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @param penaltyAccount Account of the agreement to be penalized\\n * @param rewardAccount Account that collect the reward\\n * @param rewardAmount Amount of liquidation reward\\n *\\n * NOTE:\\n *\\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\\n */\\n event AgreementLiquidated(\\n address indexed agreementClass,\\n bytes32 id,\\n address indexed penaltyAccount,\\n address indexed rewardAccount,\\n uint256 rewardAmount\\n );\\n\\n /**\\n * @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy)\\n * @param bailoutAccount Account that bailout the penalty account\\n * @param bailoutAmount Amount of account bailout\\n *\\n * NOTE:\\n *\\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\\n */\\n event Bailout(\\n address indexed bailoutAccount,\\n uint256 bailoutAmount\\n );\\n\\n /**\\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2)\\n * @param liquidatorAccount Account of the agent that performed the liquidation.\\n * @param agreementClass Contract address of the agreement\\n * @param id Agreement ID\\n * @param penaltyAccount Account of the agreement to be penalized\\n * @param bondAccount Account that collect the reward or bailout accounts\\n * @param rewardAmount Amount of liquidation reward\\n * @param bailoutAmount Amount of liquidation bailouot\\n *\\n * NOTE:\\n * Reward account rule:\\n * - if bailout is equal to 0, then\\n * - the bondAccount will get the rewardAmount,\\n * - the penaltyAccount will pay for the rewardAmount.\\n * - if bailout is larger than 0, then\\n * - the liquidatorAccount will get the rewardAmouont,\\n * - the bondAccount will pay for both the rewardAmount and bailoutAmount,\\n * - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount.\\n */\\n event AgreementLiquidatedBy(\\n address liquidatorAccount,\\n address indexed agreementClass,\\n bytes32 id,\\n address indexed penaltyAccount,\\n address indexed bondAccount,\\n uint256 rewardAmount,\\n uint256 bailoutAmount\\n );\\n}\\n\",\"keccak256\":\"0x9189eaba9e856cc4932ea29eeaf4e89a09448dde13860591691ec122856fdc75\",\"license\":\"AGPLv3\"},\"src/common/helpers/BalancesHelperV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\n// solhint-disable-next-line\\r\\npragma solidity 0.8.4;\\r\\n\\r\\n/// @title BalancesHelperV2\\r\\n/// @author Luke Wickens \\r\\n/// @notice Used to get account balances of ERC20 tokens and Wrapped Super Tokens\\r\\n\\r\\nimport {ISuperfluidToken} from \\\"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol\\\";\\r\\nimport {IERC20} from \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\r\\nimport {Address} from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\ncontract BalancesHelperV2 {\\r\\n using Address for address;\\r\\n\\r\\n /// @notice Custom errors to handle address(0)\\r\\n error AccountZeroAddress(address account, address token);\\r\\n error TokenZeroAddress(address account, address token);\\r\\n\\r\\n constructor() {}\\r\\n\\r\\n /// @notice Returns balances of accounts for multiple ERC20 tokens.\\r\\n /// @dev Error thrown if: account or token address is address(0),\\r\\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\\r\\n /// @param accounts = Array of accounts addresses\\r\\n /// @param tokens = Array of tokens addresses\\r\\n /// @return One-dimensional that's accounts.length * tokens.length long. The\\r\\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\\r\\n\\r\\n function getBalances(address[] calldata accounts, address[] calldata tokens)\\r\\n external\\r\\n view\\r\\n returns (uint256[] memory)\\r\\n {\\r\\n uint256[] memory result = new uint256[](\\r\\n accounts.length * tokens.length\\r\\n );\\r\\n\\r\\n for (uint256 i; i < accounts.length; i++) {\\r\\n for (uint256 j; j < tokens.length; j++) {\\r\\n uint256 index = j + (tokens.length * i);\\r\\n result[index] = _getBalance(accounts[i], tokens[j]);\\r\\n }\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n /// @notice Returns balances of accounts for multiple Wrapped Super Tokens.\\r\\n /// @dev Error thrown if: account or token address is address(0),\\r\\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\\r\\n /// @param accounts = Array of accounts addresses\\r\\n /// @param tokens = Array of tokens addresses\\r\\n /// @return One-dimensional that's accounts.length * tokens.length long. The\\r\\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\\r\\n\\r\\n function getSuperfluidWrappedTokenBalances(\\r\\n address[] calldata accounts,\\r\\n address[] calldata tokens\\r\\n ) external view returns (int256[] memory) {\\r\\n int256[] memory result = new int256[](accounts.length * tokens.length);\\r\\n\\r\\n for (uint256 i; i < accounts.length; i++) {\\r\\n for (uint256 j; j < tokens.length; j++) {\\r\\n uint256 index = j + (tokens.length * i);\\r\\n result[index] = _getSuperfluidWrappedTokenBalance(\\r\\n accounts[i],\\r\\n tokens[j]\\r\\n );\\r\\n }\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n /// Private fuctions\\r\\n\\r\\n /// @notice Returns balance of account for an ERC20 token.\\r\\n /// @dev Error thrown if: account or token address is address(0)\\r\\n /// @param account = account address\\r\\n /// @param token = tokens address\\r\\n /// @return balance of account as uint256.\\r\\n\\r\\n function _getBalance(address account, address token)\\r\\n private\\r\\n view\\r\\n returns (uint256)\\r\\n {\\r\\n if (account == address(0)) revert AccountZeroAddress(account, token);\\r\\n if (token == address(0)) revert TokenZeroAddress(account, token);\\r\\n\\r\\n bytes memory returnedData = token.functionStaticCall(\\r\\n abi.encodeWithSelector(IERC20(token).balanceOf.selector, account)\\r\\n );\\r\\n\\r\\n return abi.decode(returnedData, (uint256));\\r\\n }\\r\\n\\r\\n /// @notice Returns real balance of a user, taking into consideration all agreements of account\\r\\n /// @dev Error thrown if: account or token address is address(0)\\r\\n /// @param account = account address\\r\\n /// @param token = tokens address\\r\\n /// @return available balance of account as int256.\\r\\n\\r\\n function _getSuperfluidWrappedTokenBalance(address account, address token)\\r\\n private\\r\\n view\\r\\n returns (int256)\\r\\n {\\r\\n if (account == address(0)) revert AccountZeroAddress(account, token);\\r\\n if (token == address(0)) revert TokenZeroAddress(account, token);\\r\\n\\r\\n bytes memory returnedData = token.functionStaticCall(\\r\\n abi.encodeWithSelector(\\r\\n ISuperfluidToken(token).realtimeBalanceOfNow.selector,\\r\\n account\\r\\n )\\r\\n );\\r\\n\\r\\n (int256 availableBalance, , , ) = abi.decode(\\r\\n returnedData,\\r\\n (int256, uint256, uint256, uint256)\\r\\n );\\r\\n return availableBalance;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xee88323570149a5d9e569da056eaa089cf4baacfb3713a0dd282090b1d0847d2\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061108a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806350c5a7101461003b578063ef5bfc371461006b575b600080fd5b610055600480360381019061005091906109e6565b61009b565b6040516100629190610ce8565b60405180910390f35b610085600480360381019061008091906109e6565b610279565b6040516100929190610d0a565b60405180910390f35b6060600083839050868690506100b19190610e68565b67ffffffffffffffff8111156100f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405190808252806020026020018201604052801561011e5781602001602082028036833780820191505090505b50905060005b8686905081101561026c5760005b85859050811015610258576000828787905061014e9190610e68565b826101599190610e12565b90506101ff898985818110610197577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906101ac91906109bd565b8888858181106101e5577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906101fa91906109bd565b610457565b848281518110610238577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505050808061025090610f3b565b915050610132565b50808061026490610f3b565b915050610124565b5080915050949350505050565b60606000838390508686905061028f9190610e68565b67ffffffffffffffff8111156102ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156102fc5781602001602082028036833780820191505090505b50905060005b8686905081101561044a5760005b85859050811015610436576000828787905061032c9190610e68565b826103379190610e12565b90506103dd898985818110610375577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b905060200201602081019061038a91906109bd565b8888858181106103c3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906103d891906109bd565b610608565b848281518110610416577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505050808061042e90610f3b565b915050610310565b50808061044290610f3b565b915050610302565b5080915050949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156104cc5782826040517f484305ff0000000000000000000000000000000000000000000000000000000081526004016104c3929190610cbf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156105405782826040517f41f93bdf000000000000000000000000000000000000000000000000000000008152600401610537929190610cbf565b60405180910390fd5b60006105e0632ec8eec760e01b8560405160240161055e9190610ca4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508473ffffffffffffffffffffffffffffffffffffffff166107b090919063ffffffff16565b90506000818060200190518101906105f89190610a5b565b5050509050809250505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561067d5782826040517f484305ff000000000000000000000000000000000000000000000000000000008152600401610674929190610cbf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156106f15782826040517f41f93bdf0000000000000000000000000000000000000000000000000000000081526004016106e8929190610cbf565b60405180910390fd5b60006107916370a0823160e01b8560405160240161070f9190610ca4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508473ffffffffffffffffffffffffffffffffffffffff166107b090919063ffffffff16565b9050808060200190518101906107a79190610abe565b91505092915050565b60606107d58383604051806060016040528060258152602001611059602591396107dd565b905092915050565b60606107e8846108aa565b610827576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081e90610d4e565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff168560405161084f9190610c8d565b600060405180830381855afa9150503d806000811461088a576040519150601f19603f3d011682016040523d82523d6000602084013e61088f565b606091505b509150915061089f8282866108cd565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156108dd5782905061092d565b6000835111156108f05782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109249190610d2c565b60405180910390fd5b9392505050565b60008135905061094381611013565b92915050565b60008083601f84011261095b57600080fd5b8235905067ffffffffffffffff81111561097457600080fd5b60208301915083602082028301111561098c57600080fd5b9250929050565b6000815190506109a28161102a565b92915050565b6000815190506109b781611041565b92915050565b6000602082840312156109cf57600080fd5b60006109dd84828501610934565b91505092915050565b600080600080604085870312156109fc57600080fd5b600085013567ffffffffffffffff811115610a1657600080fd5b610a2287828801610949565b9450945050602085013567ffffffffffffffff811115610a4157600080fd5b610a4d87828801610949565b925092505092959194509250565b60008060008060808587031215610a7157600080fd5b6000610a7f87828801610993565b9450506020610a90878288016109a8565b9350506040610aa1878288016109a8565b9250506060610ab2878288016109a8565b91505092959194509250565b600060208284031215610ad057600080fd5b6000610ade848285016109a8565b91505092915050565b6000610af38383610c13565b60208301905092915050565b6000610b0b8383610c7e565b60208301905092915050565b610b2081610ec2565b82525050565b6000610b3182610d8e565b610b3b8185610dd4565b9350610b4683610d6e565b8060005b83811015610b77578151610b5e8882610ae7565b9750610b6983610dba565b925050600181019050610b4a565b5085935050505092915050565b6000610b8f82610d99565b610b998185610de5565b9350610ba483610d7e565b8060005b83811015610bd5578151610bbc8882610aff565b9750610bc783610dc7565b925050600181019050610ba8565b5085935050505092915050565b6000610bed82610da4565b610bf78185610df6565b9350610c07818560208601610f08565b80840191505092915050565b610c1c81610ed4565b82525050565b6000610c2d82610daf565b610c378185610e01565b9350610c47818560208601610f08565b610c5081610fb3565b840191505092915050565b6000610c68602483610e01565b9150610c7382610fc4565b604082019050919050565b610c8781610efe565b82525050565b6000610c998284610be2565b915081905092915050565b6000602082019050610cb96000830184610b17565b92915050565b6000604082019050610cd46000830185610b17565b610ce16020830184610b17565b9392505050565b60006020820190508181036000830152610d028184610b26565b905092915050565b60006020820190508181036000830152610d248184610b84565b905092915050565b60006020820190508181036000830152610d468184610c22565b905092915050565b60006020820190508181036000830152610d6781610c5b565b9050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000610e1d82610efe565b9150610e2883610efe565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610e5d57610e5c610f84565b5b828201905092915050565b6000610e7382610efe565b9150610e7e83610efe565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610eb757610eb6610f84565b5b828202905092915050565b6000610ecd82610ede565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610f26578082015181840152602081019050610f0b565b83811115610f35576000848401525b50505050565b6000610f4682610efe565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f7957610f78610f84565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000601f19601f8301169050919050565b7f416464726573733a207374617469632063616c6c20746f206e6f6e2d636f6e7460008201527f7261637400000000000000000000000000000000000000000000000000000000602082015250565b61101c81610ec2565b811461102757600080fd5b50565b61103381610ed4565b811461103e57600080fd5b50565b61104a81610efe565b811461105557600080fd5b5056fe416464726573733a206c6f772d6c6576656c207374617469632063616c6c206661696c6564a164736f6c6343000804000a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806350c5a7101461003b578063ef5bfc371461006b575b600080fd5b610055600480360381019061005091906109e6565b61009b565b6040516100629190610ce8565b60405180910390f35b610085600480360381019061008091906109e6565b610279565b6040516100929190610d0a565b60405180910390f35b6060600083839050868690506100b19190610e68565b67ffffffffffffffff8111156100f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405190808252806020026020018201604052801561011e5781602001602082028036833780820191505090505b50905060005b8686905081101561026c5760005b85859050811015610258576000828787905061014e9190610e68565b826101599190610e12565b90506101ff898985818110610197577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906101ac91906109bd565b8888858181106101e5577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906101fa91906109bd565b610457565b848281518110610238577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505050808061025090610f3b565b915050610132565b50808061026490610f3b565b915050610124565b5080915050949350505050565b60606000838390508686905061028f9190610e68565b67ffffffffffffffff8111156102ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156102fc5781602001602082028036833780820191505090505b50905060005b8686905081101561044a5760005b85859050811015610436576000828787905061032c9190610e68565b826103379190610e12565b90506103dd898985818110610375577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b905060200201602081019061038a91906109bd565b8888858181106103c3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906103d891906109bd565b610608565b848281518110610416577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505050808061042e90610f3b565b915050610310565b50808061044290610f3b565b915050610302565b5080915050949350505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156104cc5782826040517f484305ff0000000000000000000000000000000000000000000000000000000081526004016104c3929190610cbf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156105405782826040517f41f93bdf000000000000000000000000000000000000000000000000000000008152600401610537929190610cbf565b60405180910390fd5b60006105e0632ec8eec760e01b8560405160240161055e9190610ca4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508473ffffffffffffffffffffffffffffffffffffffff166107b090919063ffffffff16565b90506000818060200190518101906105f89190610a5b565b5050509050809250505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561067d5782826040517f484305ff000000000000000000000000000000000000000000000000000000008152600401610674929190610cbf565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156106f15782826040517f41f93bdf0000000000000000000000000000000000000000000000000000000081526004016106e8929190610cbf565b60405180910390fd5b60006107916370a0823160e01b8560405160240161070f9190610ca4565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508473ffffffffffffffffffffffffffffffffffffffff166107b090919063ffffffff16565b9050808060200190518101906107a79190610abe565b91505092915050565b60606107d58383604051806060016040528060258152602001611059602591396107dd565b905092915050565b60606107e8846108aa565b610827576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081e90610d4e565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff168560405161084f9190610c8d565b600060405180830381855afa9150503d806000811461088a576040519150601f19603f3d011682016040523d82523d6000602084013e61088f565b606091505b509150915061089f8282866108cd565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156108dd5782905061092d565b6000835111156108f05782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109249190610d2c565b60405180910390fd5b9392505050565b60008135905061094381611013565b92915050565b60008083601f84011261095b57600080fd5b8235905067ffffffffffffffff81111561097457600080fd5b60208301915083602082028301111561098c57600080fd5b9250929050565b6000815190506109a28161102a565b92915050565b6000815190506109b781611041565b92915050565b6000602082840312156109cf57600080fd5b60006109dd84828501610934565b91505092915050565b600080600080604085870312156109fc57600080fd5b600085013567ffffffffffffffff811115610a1657600080fd5b610a2287828801610949565b9450945050602085013567ffffffffffffffff811115610a4157600080fd5b610a4d87828801610949565b925092505092959194509250565b60008060008060808587031215610a7157600080fd5b6000610a7f87828801610993565b9450506020610a90878288016109a8565b9350506040610aa1878288016109a8565b9250506060610ab2878288016109a8565b91505092959194509250565b600060208284031215610ad057600080fd5b6000610ade848285016109a8565b91505092915050565b6000610af38383610c13565b60208301905092915050565b6000610b0b8383610c7e565b60208301905092915050565b610b2081610ec2565b82525050565b6000610b3182610d8e565b610b3b8185610dd4565b9350610b4683610d6e565b8060005b83811015610b77578151610b5e8882610ae7565b9750610b6983610dba565b925050600181019050610b4a565b5085935050505092915050565b6000610b8f82610d99565b610b998185610de5565b9350610ba483610d7e565b8060005b83811015610bd5578151610bbc8882610aff565b9750610bc783610dc7565b925050600181019050610ba8565b5085935050505092915050565b6000610bed82610da4565b610bf78185610df6565b9350610c07818560208601610f08565b80840191505092915050565b610c1c81610ed4565b82525050565b6000610c2d82610daf565b610c378185610e01565b9350610c47818560208601610f08565b610c5081610fb3565b840191505092915050565b6000610c68602483610e01565b9150610c7382610fc4565b604082019050919050565b610c8781610efe565b82525050565b6000610c998284610be2565b915081905092915050565b6000602082019050610cb96000830184610b17565b92915050565b6000604082019050610cd46000830185610b17565b610ce16020830184610b17565b9392505050565b60006020820190508181036000830152610d028184610b26565b905092915050565b60006020820190508181036000830152610d248184610b84565b905092915050565b60006020820190508181036000830152610d468184610c22565b905092915050565b60006020820190508181036000830152610d6781610c5b565b9050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000610e1d82610efe565b9150610e2883610efe565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610e5d57610e5c610f84565b5b828201905092915050565b6000610e7382610efe565b9150610e7e83610efe565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610eb757610eb6610f84565b5b828202905092915050565b6000610ecd82610ede565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610f26578082015181840152602081019050610f0b565b83811115610f35576000848401525b50505050565b6000610f4682610efe565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f7957610f78610f84565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000601f19601f8301169050919050565b7f416464726573733a207374617469632063616c6c20746f206e6f6e2d636f6e7460008201527f7261637400000000000000000000000000000000000000000000000000000000602082015250565b61101c81610ec2565b811461102757600080fd5b50565b61103381610ed4565b811461103e57600080fd5b50565b61104a81610efe565b811461105557600080fd5b5056fe416464726573733a206c6f772d6c6576656c207374617469632063616c6c206661696c6564a164736f6c6343000804000a", + "devdoc": { + "kind": "dev", + "methods": { + "getBalances(address[],address[])": { + "details": "Error thrown if: account or token address is address(0), large arrays of accounts/tokens are passed in could cause gas block limit issue", + "params": { + "accounts": "= Array of accounts addresses", + "tokens": "= Array of tokens addresses" + }, + "returns": { + "_0": "One-dimensional that's accounts.length * tokens.length long. The array is ordered by all of accounts[0] token balances, then accounts[1] etc." + } + }, + "getSuperfluidWrappedTokenBalances(address[],address[])": { + "details": "Error thrown if: account or token address is address(0), large arrays of accounts/tokens are passed in could cause gas block limit issue", + "params": { + "accounts": "= Array of accounts addresses", + "tokens": "= Array of tokens addresses" + }, + "returns": { + "_0": "One-dimensional that's accounts.length * tokens.length long. The array is ordered by all of accounts[0] token balances, then accounts[1] etc." + } + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "AccountZeroAddress(address,address)": [ + { + "notice": "Custom errors to handle address(0)" + } + ] + }, + "kind": "user", + "methods": { + "getBalances(address[],address[])": { + "notice": "Returns balances of accounts for multiple ERC20 tokens." + }, + "getSuperfluidWrappedTokenBalances(address[],address[])": { + "notice": "Returns balances of accounts for multiple Wrapped Super Tokens." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/deployments/scroll/solcInputs/563ec5ca6d970456eae054874235a0ad.json b/deployments/scroll/solcInputs/563ec5ca6d970456eae054874235a0ad.json new file mode 100644 index 00000000..8f9d58b4 --- /dev/null +++ b/deployments/scroll/solcInputs/563ec5ca6d970456eae054874235a0ad.json @@ -0,0 +1,157 @@ +{ + "language": "Solidity", + "sources": { + "src/common/access/Controlled.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Controlled\n *\n * @dev Contract module which provides an access control mechanism.\n * It ensures there is only one controlling account of the smart contract\n * and grants that account exclusive access to specific functions.\n *\n * The controller account will be the one that deploys the contract.\n *\n * @author Stanisław Głogowski \n */\ncontract Controlled {\n /**\n * @return controller account address\n */\n address public controller;\n\n // modifiers\n\n /**\n * @dev Throws if msg.sender is not the controller\n */\n modifier onlyController() {\n require(\n msg.sender == controller,\n \"Controlled: msg.sender is not the controller\"\n );\n\n _;\n }\n\n /**\n * @dev Internal constructor\n */\n constructor()\n internal\n {\n controller = msg.sender;\n }\n}\n" + }, + "src/payments/PaymentDepositAccount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/access/Controlled.sol\";\n\n\n/**\n * @title Payment deposit account\n *\n * @dev Simple account contract with only one method - `executeTransaction`\n *\n * @author Stanisław Głogowski \n */\ncontract PaymentDepositAccount is Controlled {\n /**\n * @dev Public constructor\n */\n constructor() public payable Controlled() {}\n\n /**\n * @notice Allow receives\n */\n receive()\n external\n payable\n {\n //\n }\n\n // external functions\n\n /**\n * @notice Executes transaction\n * @param to to address\n * @param value value\n * @param data data\n * @return transaction result\n */\n function executeTransaction(\n address to,\n uint256 value,\n bytes calldata data\n )\n external\n onlyController\n returns (bytes memory)\n {\n bytes memory result;\n bool succeeded;\n\n // solhint-disable-next-line avoid-call-value, avoid-low-level-calls\n (succeeded, result) = payable(to).call{value: value}(data);\n\n require(\n succeeded,\n \"Account: transaction reverted\"\n );\n\n return result;\n }\n}\n" + }, + "src/payments/PaymentRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/libs/ECDSALib.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/signature/SignatureValidator.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../external/ExternalAccountRegistry.sol\";\nimport \"../personal/PersonalAccountRegistry.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\nimport \"./PaymentDepositAccount.sol\";\n\n\n/**\n * @title Payment registry\n *\n * @notice A registry for payment and payment channels\n *\n * @dev the `DepositExit` process can be used in a case operator (guardian) couldn't sign commit / withdrawal message.\n * Process will be rejected when any of senders channels will be committed.\n *\n * @author Stanisław Głogowski \n */\ncontract PaymentRegistry is Guarded, Initializable, SignatureValidator, GatewayRecipient {\n using ECDSALib for bytes32;\n using SafeMathLib for uint256;\n\n struct Deposit {\n address account;\n mapping(address => uint256) withdrawnAmount;\n mapping(address => uint256) exitLockedUntil;\n }\n\n struct PaymentChannel {\n uint256 committedAmount;\n }\n\n struct DepositWithdrawal {\n address owner;\n address token;\n uint256 amount;\n }\n\n struct PaymentChannelCommit {\n address sender;\n address recipient;\n address token;\n bytes32 uid;\n uint256 blockNumber;\n uint256 amount;\n }\n\n uint256 private constant DEFAULT_DEPOSIT_EXIT_LOCK_PERIOD = 28 days;\n\n bytes32 private constant HASH_PREFIX_DEPOSIT_WITHDRAWAL = keccak256(\n \"DepositWithdrawal(address owner,address token,uint256 amount)\"\n );\n bytes32 private constant HASH_PREFIX_PAYMENT_CHANNEL_COMMIT = keccak256(\n \"PaymentChannelCommit(address sender,address recipient,address token,bytes32 uid,uint256 blockNumber,uint256 amount)\"\n );\n\n ExternalAccountRegistry public externalAccountRegistry;\n PersonalAccountRegistry public personalAccountRegistry;\n\n uint256 public depositExitLockPeriod;\n\n mapping(address => Deposit) private deposits;\n mapping(bytes32 => PaymentChannel) private paymentChannels;\n\n // events\n\n /**\n * @dev Emitted when the deposit account is deployed\n * @param depositAccount deposit account address\n * @param owner owner address\n */\n event DepositAccountDeployed(\n address depositAccount,\n address owner\n );\n\n /**\n * @dev Emitted when the deposit exist is requested\n * @param depositAccount deposit account address\n * @param owner owner address\n * @param token token address\n * @param lockedUntil deposit exist locked util time\n */\n event DepositExitRequested(\n address depositAccount,\n address owner,\n address token,\n uint256 lockedUntil\n );\n\n /**\n * @dev Emitted when the deposit exist is completed\n * @param depositAccount deposit account address\n * @param owner owner address\n * @param token token address\n * @param amount deposit exist amount\n */\n event DepositExitCompleted(\n address depositAccount,\n address owner,\n address token,\n uint256 amount\n );\n\n /**\n * @dev Emitted when the deposit exist is rejected\n * @param depositAccount deposit account address\n * @param owner owner address\n * @param token token address\n */\n event DepositExitRejected(\n address depositAccount,\n address owner,\n address token\n );\n\n /**\n * @dev Emitted when the deposit has been withdrawn\n * @param depositAccount deposit account address\n * @param owner owner address\n * @param token token address\n * @param amount withdrawn amount\n */\n event DepositWithdrawn(\n address depositAccount,\n address owner,\n address token,\n uint256 amount\n );\n\n /**\n * @dev Emitted when the payment channel has been committed\n * @param hash channel hash\n * @param sender sender address\n * @param recipient recipient address\n * @param token token address\n * @param uid unique channel id\n * @param amount committed amount\n */\n event PaymentChannelCommitted(\n bytes32 hash,\n address sender,\n address recipient,\n address token,\n bytes32 uid,\n uint256 amount\n );\n\n /**\n * @dev Emitted when the payment has been withdrawn\n * @param channelHash channel hash\n * @param value payment value\n */\n event PaymentWithdrawn(\n bytes32 channelHash,\n uint256 value\n );\n\n /**\n * @dev Emitted when the payment has been deposited\n * @param channelHash channel hash\n * @param value payment value\n */\n event PaymentDeposited(\n bytes32 channelHash,\n uint256 value\n );\n\n /**\n * @dev Emitted when the payment has been withdrawn and deposited (split)\n * @param channelHash channel hash\n * @param totalValue payment total value\n * @param depositValue payment deposited value\n */\n event PaymentSplit(\n bytes32 channelHash,\n uint256 totalValue,\n uint256 depositValue\n );\n\n /**\n * @dev Public constructor\n */\n constructor() public Initializable() SignatureValidator() {}\n\n // external functions\n\n /**\n * @notice Initialize `PaymentRegistry` contract\n * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\n * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\n * @param depositExitLockPeriod_ deposit exit lock period\n * @param guardians_ array of guardians addresses\n * @param gateway_ `Gateway` contract address\n */\n function initialize(\n ExternalAccountRegistry externalAccountRegistry_,\n PersonalAccountRegistry personalAccountRegistry_,\n uint256 depositExitLockPeriod_,\n address[] calldata guardians_,\n address gateway_\n )\n external\n onlyInitializer\n {\n externalAccountRegistry = externalAccountRegistry_;\n personalAccountRegistry = personalAccountRegistry_;\n\n if (depositExitLockPeriod_ == 0) {\n depositExitLockPeriod = DEFAULT_DEPOSIT_EXIT_LOCK_PERIOD;\n } else {\n depositExitLockPeriod = depositExitLockPeriod_;\n }\n\n // Guarded\n _initializeGuarded(guardians_);\n\n // GatewayRecipient\n _initializeGatewayRecipient(gateway_);\n }\n\n /**\n * @notice Deploys deposit account\n * @param owner owner address\n */\n function deployDepositAccount(\n address owner\n )\n external\n {\n _deployDepositAccount(owner);\n }\n\n /**\n * @notice Requests deposit exit\n * @param token token address\n */\n function requestDepositExit(\n address token\n )\n external\n {\n address owner = _getContextAccount();\n uint256 lockedUntil = deposits[owner].exitLockedUntil[token];\n\n require(\n lockedUntil == 0,\n \"PaymentRegistry: deposit exit already requested\"\n );\n\n _deployDepositAccount(owner);\n\n // solhint-disable-next-line not-rely-on-time\n lockedUntil = now.add(depositExitLockPeriod);\n\n deposits[owner].exitLockedUntil[token] = lockedUntil;\n\n emit DepositExitRequested(\n deposits[owner].account,\n owner,\n token,\n lockedUntil\n );\n }\n\n /**\n * @notice Processes deposit exit\n * @param token token address\n */\n function processDepositExit(\n address token\n )\n external\n {\n address owner = _getContextAccount();\n uint256 lockedUntil = deposits[owner].exitLockedUntil[token];\n\n require(\n lockedUntil != 0,\n \"PaymentRegistry: deposit exit not requested\"\n );\n\n require(\n // solhint-disable-next-line not-rely-on-time\n lockedUntil <= now,\n \"PaymentRegistry: deposit exit locked\"\n );\n\n deposits[owner].exitLockedUntil[token] = 0;\n\n address depositAccount = deposits[owner].account;\n uint256 depositValue;\n\n if (token == address(0)) {\n depositValue = depositAccount.balance;\n } else {\n depositValue = ERC20Token(token).balanceOf(depositAccount);\n }\n\n _transferFromDeposit(\n depositAccount,\n owner,\n token,\n depositValue\n );\n\n emit DepositExitCompleted(\n depositAccount,\n owner,\n token,\n depositValue\n );\n }\n\n /**\n * @notice Withdraws deposit\n * @param token token address\n * @param amount amount to withdraw\n * @param guardianSignature guardian signature\n */\n function withdrawDeposit(\n address token,\n uint256 amount,\n bytes calldata guardianSignature\n )\n external\n {\n address owner = _getContextAccount();\n uint256 value = amount.sub(deposits[owner].withdrawnAmount[token]);\n\n require(\n value > 0,\n \"PaymentRegistry: invalid amount\"\n );\n\n bytes32 messageHash = _hashDepositWithdrawal(\n owner,\n token,\n amount\n );\n\n require(\n _verifyGuardianSignature(messageHash, guardianSignature),\n \"PaymentRegistry: invalid guardian signature\"\n );\n\n deposits[owner].withdrawnAmount[token] = amount;\n\n _verifyDepositExitOrDeployAccount(owner, token);\n\n _transferFromDeposit(\n deposits[owner].account,\n owner,\n token,\n value\n );\n\n emit DepositWithdrawn(\n deposits[owner].account,\n owner,\n token,\n amount\n );\n }\n\n /**\n * @notice Commits payment channel and withdraw payment\n * @param sender sender address\n * @param token token address\n * @param uid unique channel id\n * @param blockNumber block number\n * @param amount amount to commit\n * @param senderSignature sender signature\n * @param guardianSignature guardian signature\n */\n function commitPaymentChannelAndWithdraw(\n address sender,\n address token,\n bytes32 uid,\n uint256 blockNumber,\n uint256 amount,\n bytes calldata senderSignature,\n bytes calldata guardianSignature\n )\n external\n {\n address recipient = _getContextAccount();\n\n (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n sender,\n recipient,\n token,\n uid,\n blockNumber,\n amount,\n senderSignature,\n guardianSignature\n );\n\n _transferFromDeposit(\n depositAccount,\n recipient,\n token,\n paymentValue\n );\n\n emit PaymentWithdrawn(hash, paymentValue);\n }\n\n /**\n * @notice Commits payment channel and deposit payment\n * @param sender sender address\n * @param token token address\n * @param uid unique channel id\n * @param blockNumber block number\n * @param amount amount to commit\n * @param senderSignature sender signature\n * @param guardianSignature guardian signature\n */\n function commitPaymentChannelAndDeposit(\n address sender,\n address token,\n bytes32 uid,\n uint256 blockNumber,\n uint256 amount,\n bytes calldata senderSignature,\n bytes calldata guardianSignature\n )\n external\n {\n address recipient = _getContextAccount();\n\n (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n sender,\n recipient,\n token,\n uid,\n blockNumber,\n amount,\n senderSignature,\n guardianSignature\n );\n\n _transferFromDeposit(\n depositAccount,\n _computeDepositAccountAddress(recipient),\n token,\n paymentValue\n );\n\n emit PaymentDeposited(hash, paymentValue);\n }\n\n /**\n * @notice Commits payment channel, withdraws and deposits (split) payment\n * @param sender sender address\n * @param token token address\n * @param uid unique channel id\n * @param blockNumber block number\n * @param amount amount to commit\n * @param depositPaymentValue amount to deposit\n * @param senderSignature sender signature\n * @param guardianSignature guardian signature\n */\n function commitPaymentChannelAndSplit(\n address sender,\n address token,\n bytes32 uid,\n uint256 blockNumber,\n uint256 amount,\n uint256 depositPaymentValue,\n bytes calldata senderSignature,\n bytes calldata guardianSignature\n )\n external\n {\n address recipient = _getContextAccount();\n\n (bytes32 hash, address depositAccount, uint256 paymentValue) = _commitPaymentChannel(\n sender,\n recipient,\n token,\n uid,\n blockNumber,\n amount,\n senderSignature,\n guardianSignature\n );\n\n _transferSplitFromDeposit(\n depositAccount,\n recipient,\n token,\n paymentValue,\n depositPaymentValue\n );\n\n emit PaymentSplit(hash, paymentValue, depositPaymentValue);\n }\n\n // external functions (views)\n\n /**\n * @notice Computes deposit account address\n * @param owner owner address\n * @return deposit account address\n */\n function computeDepositAccountAddress(\n address owner\n )\n external\n view\n returns (address)\n {\n return _computeDepositAccountAddress(owner);\n }\n\n /**\n * @notice Checks if deposit account is deployed\n * @param owner owner address\n * @return true when deposit account is deployed\n */\n function isDepositAccountDeployed(\n address owner\n )\n external\n view\n returns (bool)\n {\n return deposits[owner].account != address(0);\n }\n\n /**\n * @notice Gets deposit exit locked until time\n * @param owner owner address\n * @param token token address\n * @return locked until time\n */\n function getDepositExitLockedUntil(\n address owner,\n address token\n )\n external\n view\n returns (uint256)\n {\n return deposits[owner].exitLockedUntil[token];\n }\n\n /**\n * @notice Gets deposit withdrawn amount\n * @param owner owner address\n * @param token token address\n * @return withdrawn amount\n */\n function getDepositWithdrawnAmount(\n address owner,\n address token\n )\n external\n view\n returns (uint256)\n {\n return deposits[owner].withdrawnAmount[token];\n }\n\n /**\n * @notice Gets payment channel committed amount\n * @param hash payment channel hash\n * @return committed amount\n */\n function getPaymentChannelCommittedAmount(\n bytes32 hash\n )\n external\n view\n returns (uint256)\n {\n return paymentChannels[hash].committedAmount;\n }\n\n // external functions (pure)\n\n /**\n * @notice Computes payment channel hash\n * @param sender sender address\n * @param recipient recipient address\n * @param token token address\n * @param uid unique channel id\n * @return hash\n */\n function computePaymentChannelHash(\n address sender,\n address recipient,\n address token,\n bytes32 uid\n )\n external\n pure\n returns (bytes32)\n {\n return _computePaymentChannelHash(\n sender,\n recipient,\n token,\n uid\n );\n }\n\n // public functions (views)\n\n /**\n * @notice Hashes `DepositWithdrawal` message payload\n * @param depositWithdrawal struct\n * @return hash\n */\n function hashDepositWithdrawal(\n DepositWithdrawal memory depositWithdrawal\n )\n public\n view\n returns (bytes32)\n {\n return _hashDepositWithdrawal(\n depositWithdrawal.owner,\n depositWithdrawal.token,\n depositWithdrawal.amount\n );\n }\n\n /**\n * @notice Hashes `PaymentChannelCommit` message payload\n * @param paymentChannelCommit struct\n * @return hash\n */\n function hashPaymentChannelCommit(\n PaymentChannelCommit memory paymentChannelCommit\n )\n public\n view\n returns (bytes32)\n {\n return _hashPaymentChannelCommit(\n paymentChannelCommit.sender,\n paymentChannelCommit.recipient,\n paymentChannelCommit.token,\n paymentChannelCommit.uid,\n paymentChannelCommit.blockNumber,\n paymentChannelCommit.amount\n );\n }\n\n // private functions\n\n function _deployDepositAccount(\n address owner\n )\n private\n {\n if (deposits[owner].account == address(0)) {\n bytes32 salt = keccak256(\n abi.encodePacked(\n owner\n )\n );\n\n deposits[owner].account = address(new PaymentDepositAccount{salt: salt}());\n\n emit DepositAccountDeployed(\n deposits[owner].account,\n owner\n );\n }\n }\n\n function _verifyDepositExitOrDeployAccount(\n address owner,\n address token\n )\n private\n {\n if (deposits[owner].exitLockedUntil[token] > 0) {\n deposits[owner].exitLockedUntil[token] = 0;\n\n emit DepositExitRejected(\n deposits[owner].account,\n owner,\n token\n );\n } else {\n _deployDepositAccount(owner);\n }\n }\n\n function _commitPaymentChannel(\n address sender,\n address recipient,\n address token,\n bytes32 uid,\n uint256 blockNumber,\n uint256 amount,\n bytes memory senderSignature,\n bytes memory guardianSignature\n )\n private\n returns (bytes32 hash, address depositAccount, uint256 paymentValue)\n {\n bytes32 messageHash = _hashPaymentChannelCommit(\n sender,\n recipient,\n token,\n uid,\n blockNumber,\n amount\n );\n\n if (senderSignature.length == 0) {\n require(\n externalAccountRegistry.verifyAccountProofAtBlock(sender, messageHash, blockNumber),\n \"PaymentRegistry: invalid guardian signature\"\n );\n } else {\n address signer = messageHash.recoverAddress(senderSignature);\n\n if (sender != signer) {\n require(\n personalAccountRegistry.verifyAccountOwnerAtBlock(sender, signer, blockNumber) ||\n externalAccountRegistry.verifyAccountOwnerAtBlock(sender, signer, blockNumber),\n \"PaymentRegistry: invalid sender signature\"\n );\n }\n }\n\n require(\n _verifyGuardianSignature(messageHash, guardianSignature),\n \"PaymentRegistry: invalid guardian signature\"\n );\n\n hash = _computePaymentChannelHash(\n sender,\n recipient,\n token,\n uid\n );\n\n /// @dev calc payment value\n paymentValue = amount.sub(paymentChannels[hash].committedAmount);\n\n require(\n paymentValue != 0,\n \"PaymentRegistry: invalid payment value\"\n );\n\n paymentChannels[hash].committedAmount = amount;\n\n _verifyDepositExitOrDeployAccount(sender, token);\n\n depositAccount = deposits[sender].account;\n\n emit PaymentChannelCommitted(\n hash,\n sender,\n recipient,\n token,\n uid,\n amount\n );\n\n return (hash, depositAccount, paymentValue);\n }\n\n function _transferFromDeposit(\n address depositAccount,\n address to,\n address token,\n uint256 value\n )\n private\n {\n if (token == address(0)) {\n PaymentDepositAccount(payable(depositAccount)).executeTransaction(\n to,\n value,\n new bytes(0)\n );\n } else {\n bytes memory response = PaymentDepositAccount(payable(depositAccount)).executeTransaction(\n token,\n 0,\n abi.encodeWithSelector(\n ERC20Token(token).transfer.selector,\n to,\n value\n )\n );\n\n if (response.length > 0) {\n require(\n abi.decode(response, (bool)),\n \"PaymentRegistry: ERC20Token transfer reverted\"\n );\n }\n }\n }\n\n function _transferSplitFromDeposit(\n address depositAccount,\n address to,\n address token,\n uint256 paymentValue,\n uint256 depositValue\n )\n private\n {\n require(\n depositValue > 0,\n \"PaymentRegistry: invalid deposit value\"\n );\n\n uint256 withdrawValue = paymentValue.sub(depositValue);\n\n require(\n withdrawValue > 0,\n \"PaymentRegistry: invalid withdraw value\"\n );\n\n _transferFromDeposit(\n depositAccount,\n to,\n token,\n withdrawValue\n );\n\n _transferFromDeposit(\n depositAccount,\n _computeDepositAccountAddress(to),\n token,\n depositValue\n );\n }\n\n // private functions (views)\n\n function _computeDepositAccountAddress(\n address owner\n )\n private\n view\n returns (address)\n {\n bytes32 salt = keccak256(\n abi.encodePacked(\n owner\n )\n );\n\n bytes memory creationCode = type(PaymentDepositAccount).creationCode;\n\n bytes32 data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(creationCode)\n )\n );\n\n return address(uint160(uint256(data)));\n }\n\n function _hashDepositWithdrawal(\n address owner,\n address token,\n uint256 amount\n )\n private\n view\n returns (bytes32)\n {\n return _hashMessagePayload(HASH_PREFIX_DEPOSIT_WITHDRAWAL, abi.encodePacked(\n owner,\n token,\n amount\n ));\n }\n\n function _hashPaymentChannelCommit(\n address sender,\n address recipient,\n address token,\n bytes32 uid,\n uint256 blockNumber,\n uint256 amount\n )\n private\n view\n returns (bytes32)\n {\n return _hashMessagePayload(HASH_PREFIX_PAYMENT_CHANNEL_COMMIT, abi.encodePacked(\n sender,\n recipient,\n token,\n uid,\n blockNumber,\n amount\n ));\n }\n\n // private functions (pure)\n\n function _computePaymentChannelHash(\n address sender,\n address recipient,\n address token,\n bytes32 uid\n )\n private\n pure\n returns (bytes32)\n {\n return keccak256(\n abi.encodePacked(\n sender,\n recipient,\n token,\n uid\n )\n );\n }\n}\n" + }, + "src/common/access/Guarded.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/ECDSALib.sol\";\n\n\n/**\n * @title Guarded\n *\n * @dev Contract module which provides a guardian-type control mechanism.\n * It allows key accounts to have guardians and restricts specific methods to be accessible by guardians only.\n *\n * Each guardian account can remove other guardians\n *\n * Use `_initializeGuarded` to initialize the contract\n *\n * @author Stanisław Głogowski \n */\ncontract Guarded {\n using ECDSALib for bytes32;\n\n mapping(address => bool) private guardians;\n\n // events\n\n /**\n * @dev Emitted when a new guardian is added\n * @param sender sender address\n * @param guardian guardian address\n */\n event GuardianAdded(\n address sender,\n address guardian\n );\n\n /**\n * @dev Emitted when the existing guardian is removed\n * @param sender sender address\n * @param guardian guardian address\n */\n event GuardianRemoved(\n address sender,\n address guardian\n );\n\n // modifiers\n\n /**\n * @dev Throws if tx.origin is not a guardian account\n */\n modifier onlyGuardian() {\n require(\n // solhint-disable-next-line avoid-tx-origin\n guardians[tx.origin],\n \"Guarded: tx.origin is not the guardian\"\n );\n\n _;\n }\n\n /**\n * @dev Internal constructor\n */\n constructor() internal {}\n\n // external functions\n\n /**\n * @notice Adds a new guardian\n * @param guardian guardian address\n */\n function addGuardian(\n address guardian\n )\n external\n onlyGuardian\n {\n _addGuardian(guardian);\n }\n\n /**\n * @notice Removes the existing guardian\n * @param guardian guardian address\n */\n function removeGuardian(\n address guardian\n )\n external\n onlyGuardian\n {\n require(\n // solhint-disable-next-line avoid-tx-origin\n tx.origin != guardian,\n \"Guarded: cannot remove self\"\n );\n\n require(\n guardians[guardian],\n \"Guarded: guardian doesn't exist\"\n );\n\n guardians[guardian] = false;\n\n emit GuardianRemoved(\n // solhint-disable-next-line avoid-tx-origin\n tx.origin,\n guardian\n );\n }\n\n // external functions (views)\n\n /**\n * @notice Check if guardian exists\n * @param guardian guardian address\n * @return true when guardian exists\n */\n function isGuardian(\n address guardian\n )\n external\n view\n returns (bool)\n {\n return guardians[guardian];\n }\n\n /**\n * @notice Verifies guardian signature\n * @param messageHash message hash\n * @param signature signature\n * @return true on correct guardian signature\n */\n function verifyGuardianSignature(\n bytes32 messageHash,\n bytes calldata signature\n )\n external\n view\n returns (bool)\n {\n return _verifyGuardianSignature(\n messageHash,\n signature\n );\n }\n\n // internal functions\n\n /**\n * @notice Initializes `Guarded` contract\n * @dev If `guardians_` array is empty `tx.origin` is added as guardian account\n * @param guardians_ array of guardians addresses\n */\n function _initializeGuarded(\n address[] memory guardians_\n )\n internal\n {\n if (guardians_.length == 0) {\n // solhint-disable-next-line avoid-tx-origin\n _addGuardian(tx.origin);\n } else {\n uint guardiansLen = guardians_.length;\n for (uint i = 0; i < guardiansLen; i++) {\n _addGuardian(guardians_[i]);\n }\n }\n }\n\n\n // internal functions (views)\n\n function _verifyGuardianSignature(\n bytes32 messageHash,\n bytes memory signature\n )\n internal\n view\n returns (bool)\n {\n address guardian = messageHash.recoverAddress(signature);\n\n return guardians[guardian];\n }\n\n // private functions\n\n function _addGuardian(\n address guardian\n )\n private\n {\n require(\n guardian != address(0),\n \"Guarded: cannot add 0x0 guardian\"\n );\n\n require(\n !guardians[guardian],\n \"Guarded: guardian already exists\"\n );\n\n guardians[guardian] = true;\n\n emit GuardianAdded(\n // solhint-disable-next-line avoid-tx-origin\n tx.origin,\n guardian\n );\n }\n}\n" + }, + "src/common/libs/ECDSALib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ECDSA library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/cryptography/ECDSA.sol#L26\n */\nlibrary ECDSALib {\n function recoverAddress(\n bytes32 messageHash,\n bytes memory signature\n )\n internal\n pure\n returns (address)\n {\n address result = address(0);\n\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n\n if (v < 27) {\n v += 27;\n }\n\n if (v == 27 || v == 28) {\n result = ecrecover(messageHash, v, r, s);\n }\n }\n\n return result;\n }\n\n function toEthereumSignedMessageHash(\n bytes32 messageHash\n )\n internal\n pure\n returns (bytes32)\n {\n return keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n messageHash\n ));\n }\n}\n" + }, + "src/common/libs/SafeMathLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Safe math library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/math/SafeMath.sol\n */\nlibrary SafeMathLib {\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n\n require(c >= a, \"SafeMathLib: addition overflow\");\n\n return c;\n }\n\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMathLib: subtraction overflow\");\n }\n\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n\n return a - b;\n }\n\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n\n require(c / a == b, \"SafeMathLib: multiplication overflow\");\n\n return c;\n }\n\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMathLib: division by zero\");\n }\n\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b > 0, errorMessage);\n\n return a / b;\n }\n\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMathLib: modulo by zero\");\n }\n\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n\n return a % b;\n }\n}\n" + }, + "src/common/lifecycle/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Initializable\n *\n * @dev Contract module which provides access control mechanism, where\n * there is the initializer account that can be granted exclusive access to\n * specific functions.\n *\n * The initializer account will be tx.origin during contract deployment and will be removed on first use.\n * Use `onlyInitializer` modifier on contract initialize process.\n *\n * @author Stanisław Głogowski \n */\ncontract Initializable {\n address private initializer;\n\n // events\n\n /**\n * @dev Emitted after `onlyInitializer`\n * @param initializer initializer address\n */\n event Initialized(\n address initializer\n );\n\n // modifiers\n\n /**\n * @dev Throws if tx.origin is not the initializer\n */\n modifier onlyInitializer() {\n require(\n // solhint-disable-next-line avoid-tx-origin\n tx.origin == initializer,\n \"Initializable: tx.origin is not the initializer\"\n );\n\n /// @dev removes initializer\n initializer = address(0);\n\n _;\n\n emit Initialized(\n // solhint-disable-next-line avoid-tx-origin\n tx.origin\n );\n }\n\n /**\n * @dev Internal constructor\n */\n constructor()\n internal\n {\n // solhint-disable-next-line avoid-tx-origin\n initializer = tx.origin;\n }\n\n // external functions (views)\n\n /**\n * @notice Check if contract is initialized\n * @return true when contract is initialized\n */\n function isInitialized()\n external\n view\n returns (bool)\n {\n return initializer == address(0);\n }\n}\n" + }, + "src/common/signature/SignatureValidator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/ECDSALib.sol\";\n\n/**\n * @title Signature validator\n *\n * @author Stanisław Głogowski \n */\ncontract SignatureValidator {\n using ECDSALib for bytes32;\n\n uint256 public chainId;\n\n /**\n * @dev internal constructor\n */\n constructor() internal {\n uint256 chainId_;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n chainId_ := chainid()\n }\n\n chainId = chainId_;\n }\n\n // internal functions\n\n function _hashMessagePayload(\n bytes32 messagePrefix,\n bytes memory messagePayload\n )\n internal\n view\n returns (bytes32)\n {\n return keccak256(abi.encodePacked(\n chainId,\n address(this),\n messagePrefix,\n messagePayload\n )).toEthereumSignedMessageHash();\n }\n}\n" + }, + "src/common/token/ERC20Token.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../libs/SafeMathLib.sol\";\n\n\n/**\n * @title ERC20 token\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/token/ERC20/ERC20.sol\n */\ncontract ERC20Token {\n using SafeMathLib for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public totalSupply;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowances;\n\n // events\n\n event Transfer(\n address indexed from,\n address indexed to,\n uint256 value\n );\n\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n /**\n * @dev internal constructor\n */\n constructor() internal {}\n\n // external functions\n\n function transfer(\n address to,\n uint256 value\n )\n external\n returns (bool)\n {\n _transfer(_getSender(), to, value);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n )\n virtual\n external\n returns (bool)\n {\n address sender = _getSender();\n\n _transfer(from, to, value);\n _approve(from, sender, allowances[from][sender].sub(value));\n\n return true;\n }\n\n function approve(\n address spender,\n uint256 value\n )\n virtual\n external\n returns (bool)\n {\n _approve(_getSender(), spender, value);\n\n return true;\n }\n\n // external functions (views)\n\n function balanceOf(\n address owner\n )\n virtual\n external\n view\n returns (uint256)\n {\n return balances[owner];\n }\n\n function allowance(\n address owner,\n address spender\n )\n virtual\n external\n view\n returns (uint256)\n {\n return allowances[owner][spender];\n }\n\n // internal functions\n\n function _transfer(\n address from,\n address to,\n uint256 value\n )\n virtual\n internal\n {\n require(\n from != address(0),\n \"ERC20Token: cannot transfer from 0x0 address\"\n );\n require(\n to != address(0),\n \"ERC20Token: cannot transfer to 0x0 address\"\n );\n\n balances[from] = balances[from].sub(value);\n balances[to] = balances[to].add(value);\n\n emit Transfer(from, to, value);\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 value\n )\n virtual\n internal\n {\n require(\n owner != address(0),\n \"ERC20Token: cannot approve from 0x0 address\"\n );\n require(\n spender != address(0),\n \"ERC20Token: cannot approve to 0x0 address\"\n );\n\n allowances[owner][spender] = value;\n\n emit Approval(owner, spender, value);\n }\n\n function _mint(\n address owner,\n uint256 value\n )\n virtual\n internal\n {\n require(\n owner != address(0),\n \"ERC20Token: cannot mint to 0x0 address\"\n );\n require(\n value > 0,\n \"ERC20Token: cannot mint 0 value\"\n );\n\n balances[owner] = balances[owner].add(value);\n totalSupply = totalSupply.add(value);\n\n emit Transfer(address(0), owner, value);\n }\n\n function _burn(\n address owner,\n uint256 value\n )\n virtual\n internal\n {\n require(\n owner != address(0),\n \"ERC20Token: cannot burn from 0x0 address\"\n );\n\n balances[owner] = balances[owner].sub(\n value,\n \"ERC20Token: burn value exceeds balance\"\n );\n\n totalSupply = totalSupply.sub(value);\n\n emit Transfer(owner, address(0), value);\n }\n\n // internal functions (views)\n\n function _getSender()\n virtual\n internal\n view\n returns (address)\n {\n return msg.sender;\n }\n}\n" + }, + "src/external/ExternalAccountRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/BlockLib.sol\";\n\n\n/**\n * @title External account registry\n *\n * @notice Global registry for keys and external (outside of the platform) contract based wallets\n *\n * @dev An account can call the registry to add (`addAccountOwner`) or remove (`removeAccountOwner`) its own owners.\n * When the owner has been added, information about that fact will live in the registry forever.\n * Removing an owner only affects the future blocks (until the owner is re-added).\n *\n * Given the fact, there is no way to sign the data using a contract based wallet,\n * we created a registry to store signed by the key wallet proofs.\n * ERC-1271 allows removing a signer after the signature was created. Thus store the signature for the later use\n * doesn't guarantee the signer is still has access to that smart account.\n * Because of that, the ERC1271's `isValidSignature()` cannot be used in e.g. `PaymentRegistry`.*\n *\n * An account can call the registry to add (`addAccountProof`) or remove (`removeAccountProof`) proof hash.\n * When the proof has been added, information about that fact will live in the registry forever.\n * Removing a proof only affects the future blocks (until the proof is re-added).\n *\n * @author Stanisław Głogowski \n */\ncontract ExternalAccountRegistry {\n using BlockLib for BlockLib.BlockRelated;\n\n struct Account {\n mapping(address => BlockLib.BlockRelated) owners;\n mapping(bytes32 => BlockLib.BlockRelated) proofs;\n }\n\n mapping(address => Account) private accounts;\n\n // events\n\n /**\n * @dev Emitted when the new owner is added\n * @param account account address\n * @param owner owner address\n */\n event AccountOwnerAdded(\n address account,\n address owner\n );\n\n /**\n * @dev Emitted when the existing owner is removed\n * @param account account address\n * @param owner owner address\n */\n event AccountOwnerRemoved(\n address account,\n address owner\n );\n\n /**\n * @dev Emitted when the new proof is added\n * @param account account address\n * @param hash proof hash\n */\n event AccountProofAdded(\n address account,\n bytes32 hash\n );\n\n /**\n * @dev Emitted when the existing proof is removed\n * @param account account address\n * @param hash proof hash\n */\n event AccountProofRemoved(\n address account,\n bytes32 hash\n );\n\n // external functions\n\n /**\n * @notice Adds a new account owner\n * @param owner owner address\n */\n function addAccountOwner(\n address owner\n )\n external\n {\n require(\n owner != address(0),\n \"ExternalAccountRegistry: cannot add 0x0 owner\"\n );\n\n require(\n !accounts[msg.sender].owners[owner].verifyAtCurrentBlock(),\n \"ExternalAccountRegistry: owner already exists\"\n );\n\n accounts[msg.sender].owners[owner].added = true;\n accounts[msg.sender].owners[owner].removedAtBlockNumber = 0;\n\n emit AccountOwnerAdded(\n msg.sender,\n owner\n );\n }\n\n /**\n * @notice Removes existing account owner\n * @param owner owner address\n */\n function removeAccountOwner(\n address owner\n )\n external\n {\n require(\n accounts[msg.sender].owners[owner].verifyAtCurrentBlock(),\n \"ExternalAccountRegistry: owner doesn't exist\"\n );\n\n accounts[msg.sender].owners[owner].removedAtBlockNumber = block.number;\n\n emit AccountOwnerRemoved(\n msg.sender,\n owner\n );\n }\n\n /**\n * @notice Adds a new account proof\n * @param hash proof hash\n */\n function addAccountProof(\n bytes32 hash\n )\n external\n {\n require(\n !accounts[msg.sender].proofs[hash].verifyAtCurrentBlock(),\n \"ExternalAccountRegistry: proof already exists\"\n );\n\n accounts[msg.sender].proofs[hash].added = true;\n accounts[msg.sender].proofs[hash].removedAtBlockNumber = 0;\n\n emit AccountProofAdded(\n msg.sender,\n hash\n );\n }\n\n /**\n * @notice Removes existing account proof\n * @param hash proof hash\n */\n function removeAccountProof(\n bytes32 hash\n )\n external\n {\n require(\n accounts[msg.sender].proofs[hash].verifyAtCurrentBlock(),\n \"ExternalAccountRegistry: proof doesn't exist\"\n );\n\n accounts[msg.sender].proofs[hash].removedAtBlockNumber = block.number;\n\n emit AccountProofRemoved(\n msg.sender,\n hash\n );\n }\n\n // external functions (views)\n\n /**\n * @notice Verifies the owner of the account at current block\n * @param account account address\n * @param owner owner address\n * @return true on correct account owner\n */\n function verifyAccountOwner(\n address account,\n address owner\n )\n external\n view\n returns (bool)\n {\n return accounts[account].owners[owner].verifyAtCurrentBlock();\n }\n\n /**\n * @notice Verifies the owner of the account at specific block\n * @param account account address\n * @param owner owner address\n * @param blockNumber block number to verify\n * @return true on correct account owner\n */\n function verifyAccountOwnerAtBlock(\n address account,\n address owner,\n uint256 blockNumber\n )\n external\n view\n returns (bool)\n {\n return accounts[account].owners[owner].verifyAtBlock(blockNumber);\n }\n\n /**\n * @notice Verifies the proof of the account at current block\n * @param account account address\n * @param hash proof hash\n * @return true on correct account proof\n */\n function verifyAccountProof(\n address account,\n bytes32 hash\n )\n external\n view\n returns (bool)\n {\n return accounts[account].proofs[hash].verifyAtCurrentBlock();\n }\n\n /**\n * @notice Verifies the proof of the account at specific block\n * @param account account address\n * @param hash proof hash\n * @param blockNumber block number to verify\n * @return true on correct account proof\n */\n function verifyAccountProofAtBlock(\n address account,\n bytes32 hash,\n uint256 blockNumber\n )\n external\n view\n returns (bool)\n {\n return accounts[account].proofs[hash].verifyAtBlock(blockNumber);\n }\n}\n" + }, + "src/personal/PersonalAccountRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/account/AccountController.sol\";\nimport \"../common/account/AccountRegistry.sol\";\nimport \"../common/libs/BlockLib.sol\";\nimport \"../common/libs/ECDSALib.sol\";\nimport \"../common/libs/ECDSAExtendedLib.sol\";\nimport \"../common/libs/SafeMathLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\n\n\n/**\n * @title Personal account registry\n *\n * @notice A registry for personal (controlled by owners) accounts\n *\n * @author Stanisław Głogowski \n */\ncontract PersonalAccountRegistry is Guarded, AccountController, AccountRegistry, Initializable, GatewayRecipient {\n using BlockLib for BlockLib.BlockRelated;\n using SafeMathLib for uint256;\n using ECDSALib for bytes32;\n using ECDSAExtendedLib for bytes;\n\n struct Account {\n bool deployed;\n bytes32 salt;\n mapping(address => BlockLib.BlockRelated) owners;\n }\n\n mapping(address => Account) private accounts;\n\n // events\n\n /**\n * @dev Emitted when the new owner is added\n * @param account account address\n * @param owner owner address\n */\n event AccountOwnerAdded(\n address account,\n address owner\n );\n\n /**\n * @dev Emitted when the existing owner is removed\n * @param account account address\n * @param owner owner address\n */\n event AccountOwnerRemoved(\n address account,\n address owner\n );\n\n /**\n * @dev Emitted when the call is refunded\n * @param account account address\n * @param beneficiary beneficiary address\n * @param token token address\n * @param value value\n */\n event AccountCallRefunded(\n address account,\n address beneficiary,\n address token,\n uint256 value\n );\n\n /**\n * @dev Public constructor\n */\n constructor() public Initializable() {}\n\n // external functions\n\n /**\n * @notice Initializes `PersonalAccountRegistry` contract\n * @param guardians_ array of guardians addresses\n * @param accountImplementation_ account implementation address\n * @param gateway_ `Gateway` contract address\n */\n function initialize(\n address[] calldata guardians_,\n address accountImplementation_,\n address gateway_\n )\n external\n onlyInitializer\n {\n // Guarded\n _initializeGuarded(guardians_);\n\n // AccountController\n _initializeAccountController(address(this), accountImplementation_);\n\n // GatewayRecipient\n _initializeGatewayRecipient(gateway_);\n }\n\n /**\n * @notice Upgrades `PersonalAccountRegistry` contract\n * @param accountImplementation_ account implementation address\n */\n function upgrade(\n address accountImplementation_\n )\n external\n onlyGuardian\n {\n _setAccountImplementation(accountImplementation_, true);\n }\n\n /**\n * @notice Deploys account\n * @param account account address\n */\n function deployAccount(\n address account\n )\n external\n {\n _verifySender(account);\n _deployAccount(account);\n }\n\n /**\n * @notice Upgrades account\n * @param account account address\n */\n function upgradeAccount(\n address account\n )\n external\n {\n _verifySender(account);\n _upgradeAccount(account, true);\n }\n\n /**\n * @notice Adds a new account owner\n * @param account account address\n * @param owner owner address\n */\n function addAccountOwner(\n address account,\n address owner\n )\n external\n {\n _verifySender(account);\n\n require(\n owner != address(0),\n \"PersonalAccountRegistry: cannot add 0x0 owner\"\n );\n\n require(\n !accounts[account].owners[owner].verifyAtCurrentBlock(),\n \"PersonalAccountRegistry: owner already exists\"\n );\n\n accounts[account].owners[owner].added = true;\n accounts[account].owners[owner].removedAtBlockNumber = 0;\n\n emit AccountOwnerAdded(\n account,\n owner\n );\n }\n\n /**\n * @notice Removes the existing account owner\n * @param account account address\n * @param owner owner address\n */\n function removeAccountOwner(\n address account,\n address owner\n )\n external\n {\n address sender = _verifySender(account);\n\n require(\n owner != sender,\n \"PersonalAccountRegistry: cannot remove self\"\n );\n\n require(\n accounts[account].owners[owner].verifyAtCurrentBlock(),\n \"PersonalAccountRegistry: owner doesn't exist\"\n );\n\n accounts[account].owners[owner].removedAtBlockNumber = block.number;\n\n emit AccountOwnerRemoved(\n account,\n owner\n );\n }\n\n /**\n * @notice Executes account transaction\n * @dev Deploys an account if not deployed yet\n * @param account account address\n * @param to to address\n * @param value value\n * @param data data\n */\n function executeAccountTransaction(\n address account,\n address to,\n uint256 value,\n bytes calldata data\n )\n external\n {\n _verifySender(account);\n\n _deployAccount(account);\n\n _executeAccountTransaction(\n account,\n to,\n value,\n data,\n true\n );\n }\n\n /**\n * @notice Refunds account call\n * @dev Deploys an account if not deployed yet\n * @param account account address\n * @param token token address\n * @param value value\n */\n function refundAccountCall(\n address account,\n address token,\n uint256 value\n )\n external\n {\n _verifySender(account);\n\n _deployAccount(account);\n\n /* solhint-disable avoid-tx-origin */\n\n if (token == address(0)) {\n _executeAccountTransaction(\n account,\n tx.origin,\n value,\n new bytes(0),\n false\n );\n } else {\n bytes memory response = _executeAccountTransaction(\n account,\n token,\n 0,\n abi.encodeWithSelector(\n ERC20Token(token).transfer.selector,\n tx.origin,\n value\n ),\n false\n );\n\n if (response.length > 0) {\n require(\n abi.decode(response, (bool)),\n \"PersonalAccountRegistry: ERC20Token transfer reverted\"\n );\n }\n }\n\n emit AccountCallRefunded(\n account,\n tx.origin,\n token,\n value\n );\n\n /* solhint-enable avoid-tx-origin */\n }\n\n // external functions (views)\n\n /**\n * @notice Computes account address\n * @param saltOwner salt owner address\n * @return account address\n */\n function computeAccountAddress(\n address saltOwner\n )\n external\n view\n returns (address)\n {\n return _computeAccountAddress(saltOwner);\n }\n\n /**\n * @notice Checks if account is deployed\n * @param account account address\n * @return true when account is deployed\n */\n function isAccountDeployed(\n address account\n )\n external\n view\n returns (bool)\n {\n return accounts[account].deployed;\n }\n\n /**\n * @notice Verifies the owner of the account at the current block\n * @param account account address\n * @param owner owner address\n * @return true on correct account owner\n */\n function verifyAccountOwner(\n address account,\n address owner\n )\n external\n view\n returns (bool)\n {\n return _verifyAccountOwner(account, owner);\n }\n\n /**\n * @notice Verifies the owner of the account at a specific block\n * @param account account address\n * @param owner owner address\n * @param blockNumber block number to verify\n * @return true on correct account owner\n */\n function verifyAccountOwnerAtBlock(\n address account,\n address owner,\n uint256 blockNumber\n )\n external\n view\n returns (bool)\n {\n bool result = false;\n\n if (_verifyAccountOwner(account, owner)) {\n result = true;\n } else {\n result = accounts[account].owners[owner].verifyAtBlock(blockNumber);\n }\n\n return result;\n }\n\n /**\n * @notice Verifies account signature\n * @param account account address\n * @param messageHash message hash\n * @param signature signature\n * @return magic hash if valid\n */\n function isValidAccountSignature(\n address account,\n bytes32 messageHash,\n bytes calldata signature\n )\n override\n external\n view\n returns (bool)\n {\n return _verifyAccountOwner(\n account,\n messageHash.recoverAddress(signature)\n );\n }\n\n /**\n * @notice Verifies account signature\n * @param account account address\n * @param message message\n * @param signature signature\n * @return magic hash if valid\n */\n function isValidAccountSignature(\n address account,\n bytes calldata message,\n bytes calldata signature\n )\n override\n external\n view\n returns (bool)\n {\n return _verifyAccountOwner(\n account,\n message.toEthereumSignedMessageHash().recoverAddress(signature)\n );\n }\n\n // private functions\n\n function _verifySender(\n address account\n )\n private\n returns (address)\n {\n address sender = _getContextSender();\n\n if (accounts[account].owners[sender].added) {\n require(\n accounts[account].owners[sender].removedAtBlockNumber == 0,\n \"PersonalAccountRegistry: sender is not the account owner\"\n );\n } else {\n require(\n accounts[account].salt == 0,\n \"PersonalAccountRegistry: sender is not the account owner\"\n );\n\n bytes32 salt = keccak256(\n abi.encodePacked(sender)\n );\n\n require(\n account == _computeAccountAddress(salt),\n \"PersonalAccountRegistry: sender is not the account owner\"\n );\n\n accounts[account].salt = salt;\n accounts[account].owners[sender].added = true;\n\n emit AccountOwnerAdded(\n account,\n sender\n );\n }\n\n return sender;\n }\n\n function _deployAccount(\n address account\n )\n internal\n {\n if (!accounts[account].deployed) {\n _deployAccount(\n accounts[account].salt,\n true\n );\n\n accounts[account].deployed = true;\n }\n }\n\n // private functions (views)\n\n function _computeAccountAddress(\n address saltOwner\n )\n private\n view\n returns (address)\n {\n bytes32 salt = keccak256(\n abi.encodePacked(saltOwner)\n );\n\n return _computeAccountAddress(salt);\n }\n\n function _verifyAccountOwner(\n address account,\n address owner\n )\n private\n view\n returns (bool)\n {\n bool result;\n\n if (accounts[account].owners[owner].added) {\n result = accounts[account].owners[owner].removedAtBlockNumber == 0;\n } else if (accounts[account].salt == 0) {\n result = account == _computeAccountAddress(owner);\n }\n\n return result;\n }\n}\n" + }, + "src/gateway/GatewayRecipient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/BytesLib.sol\";\n\n\n/**\n * @title Gateway recipient\n *\n * @notice Gateway target contract\n *\n * @author Stanisław Głogowski \n */\ncontract GatewayRecipient {\n using BytesLib for bytes;\n\n address public gateway;\n\n /**\n * @dev internal constructor\n */\n constructor() internal {}\n\n // internal functions\n\n /**\n * @notice Initializes `GatewayRecipient` contract\n * @param gateway_ `Gateway` contract address\n */\n function _initializeGatewayRecipient(\n address gateway_\n )\n internal\n {\n gateway = gateway_;\n }\n\n // internal functions (views)\n\n /**\n * @notice Gets gateway context account\n * @return context account address\n */\n function _getContextAccount()\n internal\n view\n returns (address)\n {\n return _getContextAddress(40);\n }\n\n /**\n * @notice Gets gateway context sender\n * @return context sender address\n */\n function _getContextSender()\n internal\n view\n returns (address)\n {\n return _getContextAddress(20);\n }\n\n /**\n * @notice Gets gateway context data\n * @return context data\n */\n function _getContextData()\n internal\n view\n returns (bytes calldata)\n {\n bytes calldata result;\n\n if (_isGatewaySender()) {\n result = msg.data[:msg.data.length - 40];\n } else {\n result = msg.data;\n }\n\n return result;\n }\n\n // private functions (views)\n\n function _getContextAddress(\n uint256 offset\n )\n private\n view\n returns (address)\n {\n address result = address(0);\n\n if (_isGatewaySender()) {\n uint from = msg.data.length - offset;\n result = bytes(msg.data[from:from + 20]).toAddress();\n } else {\n result = msg.sender;\n }\n\n return result;\n }\n\n function _isGatewaySender()\n private\n view\n returns (bool)\n {\n bool result;\n\n if (msg.sender == gateway) {\n require(\n msg.data.length >= 44,\n \"GatewayRecipient: invalid msg.data\"\n );\n\n result = true;\n }\n\n return result;\n }\n}\n" + }, + "src/common/libs/BlockLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Block library\n *\n * @author Stanisław Głogowski \n */\nlibrary BlockLib {\n struct BlockRelated {\n bool added;\n uint256 removedAtBlockNumber;\n }\n\n /**\n * @notice Verifies self struct at current block\n * @param self self struct\n * @return true on correct self struct\n */\n function verifyAtCurrentBlock(\n BlockRelated memory self\n )\n internal\n view\n returns (bool)\n {\n return verifyAtBlock(self, block.number);\n }\n\n /**\n * @notice Verifies self struct at any block\n * @param self self struct\n * @return true on correct self struct\n */\n function verifyAtAnyBlock(\n BlockRelated memory self\n )\n internal\n pure\n returns (bool)\n {\n return verifyAtBlock(self, 0);\n }\n\n /**\n * @notice Verifies self struct at specific block\n * @param self self struct\n * @param blockNumber block number to verify\n * @return true on correct self struct\n */\n function verifyAtBlock(\n BlockRelated memory self,\n uint256 blockNumber\n )\n internal\n pure\n returns (bool)\n {\n bool result = false;\n\n if (self.added) {\n if (self.removedAtBlockNumber == 0) {\n result = true;\n } else if (blockNumber == 0) {\n result = true;\n } else {\n result = self.removedAtBlockNumber > blockNumber;\n }\n }\n\n return result;\n }\n}\n" + }, + "src/common/account/AccountController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./Account.sol\";\n\n\n/**\n * @title Account controller\n *\n * @dev Contract module which provides Account deployment mechanism\n *\n * @author Stanisław Głogowski \n */\ncontract AccountController {\n address public accountRegistry;\n address public accountImplementation;\n\n // events\n\n /**\n * @dev Emitted when the account registry is updated\n * @param accountRegistry account registry address\n */\n event AccountRegistryUpdated(\n address accountRegistry\n );\n\n /**\n * @dev Emitted when the account implementation is updated\n * @param accountImplementation account implementation address\n */\n event AccountImplementationUpdated(\n address accountImplementation\n );\n\n /**\n * @dev Emitted when the account is deployed\n * @param account account address\n * @param accountImplementation account implementation address\n */\n event AccountDeployed(\n address account,\n address accountImplementation\n );\n\n /**\n * @dev Emitted when the account is upgraded\n * @param account account address\n * @param accountImplementation account implementation address\n */\n event AccountUpgraded(\n address account,\n address accountImplementation\n );\n\n /**\n * @dev Emitted when the transaction is executed\n * @param account account address\n * @param to to address\n * @param value value\n * @param data data\n * @param response response\n */\n event AccountTransactionExecuted(\n address account,\n address to,\n uint256 value,\n bytes data,\n bytes response\n );\n\n /**\n * @dev Internal constructor\n */\n constructor() internal {}\n\n // internal functions\n\n /**\n * @notice Initializes `AccountController` contract\n * @param accountRegistry_ account registry address\n * @param accountImplementation_ account implementation address\n */\n function _initializeAccountController(\n address accountRegistry_,\n address accountImplementation_\n )\n internal\n {\n _setAccountRegistry(accountRegistry_, false);\n _setAccountImplementation(accountImplementation_, false);\n }\n\n /**\n * @notice Sets account registry\n * @param accountRegistry_ account registry address\n * @param emitEvent it will emit event when flag is set to true\n */\n function _setAccountRegistry(\n address accountRegistry_,\n bool emitEvent\n )\n internal\n {\n require(\n accountRegistry_ != address(0),\n \"AccountController: cannot set account registry to 0x0\"\n );\n\n accountRegistry = accountRegistry_;\n\n if (emitEvent) {\n emit AccountRegistryUpdated(accountRegistry);\n }\n }\n\n /**\n * @notice Sets account implementation\n * @param accountImplementation_ account implementation address\n * @param emitEvent it will emit event when flag is set to true\n */\n function _setAccountImplementation(\n address accountImplementation_,\n bool emitEvent\n )\n internal\n {\n require(\n accountImplementation_ != address(0),\n \"AccountController: cannot set account Implementation to 0x0\"\n );\n\n accountImplementation = accountImplementation_;\n\n if (emitEvent) {\n emit AccountImplementationUpdated(accountImplementation);\n }\n }\n\n /**\n * @notice Deploys account\n * @param salt CREATE2 salt\n * @param emitEvent it will emit event when flag is set to true\n * @return account address\n */\n function _deployAccount(\n bytes32 salt,\n bool emitEvent\n )\n internal\n returns (address)\n {\n address account = address(new Account{salt: salt}(\n accountRegistry,\n accountImplementation\n ));\n\n if (emitEvent) {\n emit AccountDeployed(\n account,\n accountImplementation\n );\n }\n\n return account;\n }\n\n /**\n * @notice Upgrades account\n * @param account account address\n * @param emitEvent it will emit event when flag is set to true\n */\n function _upgradeAccount(\n address account,\n bool emitEvent\n )\n internal\n {\n require(\n Account(payable(account)).implementation() != accountImplementation,\n \"AccountController: account already upgraded\"\n );\n\n Account(payable(account)).setImplementation(accountImplementation);\n\n if (emitEvent) {\n emit AccountUpgraded(\n account,\n accountImplementation\n );\n }\n }\n\n /**\n * @notice Executes transaction from the account\n * @param account account address\n * @param to to address\n * @param value value\n * @param data data\n * @param emitEvent it will emit event when flag is set to true\n * @return transaction result\n */\n function _executeAccountTransaction(\n address account,\n address to,\n uint256 value,\n bytes memory data,\n bool emitEvent\n )\n internal\n returns (bytes memory)\n {\n require(\n to != address(0),\n \"AccountController: cannot send to 0x0\"\n );\n\n require(\n to != address(this),\n \"AccountController: cannot send to controller\"\n );\n\n require(\n to != account,\n \"AccountController: cannot send to self\"\n );\n\n bytes memory response = Account(payable(account)).executeTransaction(\n to,\n value,\n data\n );\n\n if (emitEvent) {\n emit AccountTransactionExecuted(\n account,\n to,\n value,\n data,\n response\n );\n }\n\n return response;\n }\n\n // internal functions (views)\n\n /**\n * @notice Computes account CREATE2 address\n * @param salt CREATE2 salt\n * @return account address\n */\n function _computeAccountAddress(\n bytes32 salt\n )\n internal\n view\n returns (address)\n {\n bytes memory creationCode = abi.encodePacked(\n type(Account).creationCode,\n bytes12(0),\n accountRegistry,\n bytes12(0),\n accountImplementation\n );\n\n bytes32 data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(creationCode)\n )\n );\n\n return address(uint160(uint256(data)));\n }\n}\n" + }, + "src/common/account/AccountRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./Account.sol\";\n\n\n/**\n * @title Account registry\n *\n * @author Stanisław Głogowski \n */\nabstract contract AccountRegistry {\n /**\n * @notice Verifies account signature\n * @param account account address\n * @param messageHash message hash\n * @param signature signature\n * @return true if valid\n */\n function isValidAccountSignature(\n address account,\n bytes32 messageHash,\n bytes calldata signature\n )\n virtual\n external\n view\n returns (bool);\n\n /**\n * @notice Verifies account signature\n * @param account account address\n * @param message message\n * @param signature signature\n * @return true if valid\n */\n function isValidAccountSignature(\n address account,\n bytes calldata message,\n bytes calldata signature\n )\n virtual\n external\n view\n returns (bool);\n}\n" + }, + "src/common/libs/ECDSAExtendedLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./StringsLib.sol\";\n\n\n/**\n * @title ECDSA extended library\n */\nlibrary ECDSAExtendedLib {\n using StringsLib for uint;\n\n function toEthereumSignedMessageHash(\n bytes memory message\n )\n internal\n pure\n returns (bytes32)\n {\n return keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n\",\n message.length.toString(),\n abi.encodePacked(message)\n ));\n }\n}\n" + }, + "src/common/account/Account.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../access/Controlled.sol\";\nimport \"./AccountBase.sol\";\n\n\n/**\n * @title Account\n *\n * @author Stanisław Głogowski \n */\ncontract Account is Controlled, AccountBase {\n address public implementation;\n\n /**\n * @dev Public constructor\n * @param registry_ account registry address\n * @param implementation_ account implementation address\n */\n constructor(\n address registry_,\n address implementation_\n )\n public\n Controlled()\n {\n registry = registry_;\n implementation = implementation_;\n }\n\n // external functions\n\n /**\n * @notice Payable receive\n */\n receive()\n external\n payable\n {\n //\n }\n\n /**\n * @notice Fallback\n */\n // solhint-disable-next-line payable-fallback\n fallback()\n external\n {\n if (msg.data.length != 0) {\n address implementation_ = implementation;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let calldedatasize := calldatasize()\n\n calldatacopy(0, 0, calldedatasize)\n\n let result := delegatecall(gas(), implementation_, 0, calldedatasize, 0, 0)\n let returneddatasize := returndatasize()\n\n returndatacopy(0, 0, returneddatasize)\n\n switch result\n case 0 { revert(0, returneddatasize) }\n default { return(0, returneddatasize) }\n }\n }\n }\n\n /**\n * @notice Sets implementation\n * @param implementation_ implementation address\n */\n function setImplementation(\n address implementation_\n )\n external\n onlyController\n {\n implementation = implementation_;\n }\n\n /**\n * @notice Executes transaction\n * @param to to address\n * @param value value\n * @param data data\n * @return transaction result\n */\n function executeTransaction(\n address to,\n uint256 value,\n bytes calldata data\n )\n external\n onlyController\n returns (bytes memory)\n {\n bytes memory result;\n bool succeeded;\n\n // solhint-disable-next-line avoid-call-value, avoid-low-level-calls\n (succeeded, result) = payable(to).call{value: value}(data);\n\n require(\n succeeded,\n \"Account: transaction reverted\"\n );\n\n return result;\n }\n}\n" + }, + "src/common/account/AccountBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Account base\n *\n * @author Stanisław Głogowski \n */\ncontract AccountBase {\n address public registry;\n}\n" + }, + "src/common/libs/StringsLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Strings library\n *\n * @dev Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.3.0/contracts/utils/Strings.sol#L12\n */\nlibrary StringsLib {\n function toString(\n uint256 value\n )\n internal\n pure\n returns (string memory)\n {\n if (value == 0) {\n return \"0\";\n }\n\n uint256 temp = value;\n uint256 digits;\n\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n\n bytes memory buffer = new bytes(digits);\n uint256 index = digits - 1;\n temp = value;\n\n while (temp != 0) {\n buffer[index--] = byte(uint8(48 + temp % 10));\n temp /= 10;\n }\n\n return string(buffer);\n }\n}\n" + }, + "src/common/libs/BytesLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Bytes library\n *\n * @author Stanisław Głogowski \n */\nlibrary BytesLib {\n /**\n * @notice Converts bytes to address\n * @param data data\n * @return address\n */\n function toAddress(\n bytes memory data\n )\n internal\n pure\n returns (address)\n {\n address result;\n\n require(\n data.length == 20,\n \"BytesLib: invalid data length\"\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n result := div(mload(add(data, 0x20)), 0x1000000000000000000000000)\n }\n\n return result;\n }\n}\n" + }, + "src/tokens/WrappedWeiToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/token/ERC20Token.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\n\n\n/**\n * @title Wrapped wei token\n *\n * @notice One to one wei consumable ERC20 token\n *\n * @dev After the transfer to consumer's account is done, the token will be automatically burned and withdrawn.\n *\n * Use `startConsuming` to become a consumer.\n *\n * @author Stanisław Głogowski \n */\ncontract WrappedWeiToken is Initializable, ERC20Token, GatewayRecipient {\n mapping(address => bool) private consumers;\n\n // events\n\n /**\n * @dev Emitted when the new consumer is added\n * @param consumer consumer address\n */\n event ConsumerAdded(\n address consumer\n );\n\n /**\n * @dev Emitted when the existing consumer is removed\n * @param consumer consumer address\n */\n event ConsumerRemoved(\n address consumer\n );\n\n /**\n * @dev Public constructor\n */\n constructor()\n public\n Initializable()\n {\n name = \"Wrapped Wei\";\n symbol = \"WWEI\";\n }\n\n /**\n * @notice Receive fallback\n */\n receive()\n external\n payable\n {\n _mint(_getSender(), msg.value);\n }\n\n // external functions\n\n /**\n * @notice Initializes `WrappedWeiToken` contract\n * @param consumers_ array of consumers addresses\n * @param gateway_ `Gateway` contract address\n */\n function initialize(\n address[] calldata consumers_,\n address gateway_\n )\n external\n onlyInitializer\n {\n if (consumers_.length != 0) {\n uint consumersLen = consumers_.length;\n for (uint i = 0; i < consumersLen; i++) {\n _addConsumer(consumers_[i]);\n }\n }\n\n _initializeGatewayRecipient(gateway_);\n }\n\n /**\n * @notice Starts consuming\n * @dev Add caller as a consumer\n */\n function startConsuming()\n external\n {\n _addConsumer(_getSender());\n }\n\n /**\n * @notice Stops consuming\n * @dev Remove caller from consumers\n */\n function stopConsuming()\n external\n {\n address consumer = _getSender();\n\n require(\n consumers[consumer],\n \"WrappedWeiToken: consumer doesn't exist\"\n );\n\n consumers[consumer] = false;\n\n emit ConsumerRemoved(consumer);\n }\n\n /**\n * @notice Deposits `msg.value` to address\n * @param to to address\n */\n function depositTo(\n address to\n )\n external\n payable\n {\n _mint(to, msg.value);\n }\n\n /**\n * @notice Withdraws\n * @param value value to withdraw\n */\n function withdraw(\n uint256 value\n )\n external\n {\n _withdraw(_getSender(), _getSender(), value);\n }\n\n /**\n * @notice Withdraws to address\n * @param to to address\n * @param value value to withdraw\n */\n function withdrawTo(\n address to,\n uint256 value\n )\n external\n {\n _withdraw(_getSender(), to, value);\n }\n\n /**\n * @notice Withdraws all\n */\n function withdrawAll()\n external\n {\n address sender = _getSender();\n\n _withdraw(sender, sender, balances[sender]);\n }\n\n /**\n * @notice Withdraws all to address\n * @param to to address\n */\n function withdrawAllTo(\n address to\n )\n external\n {\n address sender = _getSender();\n\n _withdraw(sender, to, balances[sender]);\n }\n\n // external functions (views)\n\n /**\n * @notice Checks if consumer exists\n * @param consumer consumer address\n * @return true if consumer exists\n */\n function isConsumer(\n address consumer\n )\n external\n view\n returns (bool)\n {\n return consumers[consumer];\n }\n\n // internal functions\n\n function _transfer(\n address from,\n address to,\n uint256 value\n )\n override\n internal\n {\n if (consumers[to]) {\n _withdraw(from, to, value);\n } else {\n super._transfer(from, to, value);\n }\n }\n\n // internal functions (views)\n\n function _getSender()\n override\n internal\n view\n returns (address)\n {\n return _getContextAccount();\n }\n\n // private functions\n\n function _addConsumer(\n address consumer\n )\n private\n {\n require(\n !consumers[consumer],\n \"WrappedWeiToken: consumer already exists\"\n );\n\n consumers[consumer] = true;\n\n emit ConsumerAdded(consumer);\n }\n\n function _withdraw(\n address from,\n address to,\n uint256 value\n )\n private\n {\n _burn(from, value);\n\n require(\n // solhint-disable-next-line check-send-result\n payable(to).send(value),\n \"WrappedWeiToken: transaction reverted\"\n );\n }\n}\n" + }, + "src/gateway/GatewayV2.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.12;\r\npragma experimental ABIEncoderV2;\r\n\r\nimport \"../common/access/Guarded.sol\";\r\nimport \"../common/libs/ECDSALib.sol\";\r\nimport \"../common/libs/SafeMathLib.sol\";\r\nimport \"../common/lifecycle/Initializable.sol\";\r\nimport \"../common/signature/SignatureValidator.sol\";\r\nimport \"../external/ExternalAccountRegistry.sol\";\r\nimport \"../personal/PersonalAccountRegistry.sol\";\r\n\r\n/**\r\n * @title Gateway V2 with guarded batching functions\r\n *\r\n * @notice GSN replacement\r\n *\r\n * @author Utkir Sobirov \r\n */\r\ncontract GatewayV2 is Initializable, SignatureValidator, Guarded {\r\n using ECDSALib for bytes32;\r\n using SafeMathLib for uint256;\r\n\r\n struct DelegatedBatch {\r\n address account;\r\n uint256 nonce;\r\n address[] to;\r\n bytes[] data;\r\n }\r\n\r\n struct DelegatedBatchWithGasPrice {\r\n address account;\r\n uint256 nonce;\r\n address[] to;\r\n bytes[] data;\r\n uint256 gasPrice;\r\n }\r\n\r\n bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\r\n \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\r\n );\r\n\r\n bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\r\n \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\r\n );\r\n\r\n ExternalAccountRegistry public externalAccountRegistry;\r\n PersonalAccountRegistry public personalAccountRegistry;\r\n\r\n mapping(address => uint256) private accountNonce;\r\n\r\n // events\r\n\r\n /**\r\n * @dev Emitted when the single batch is delegated\r\n * @param sender sender address\r\n * @param batch batch\r\n * @param succeeded if succeeded\r\n */\r\n event BatchDelegated(\r\n address sender,\r\n bytes batch,\r\n bool succeeded\r\n );\r\n\r\n /**\r\n * @dev Public constructor\r\n */\r\n constructor() public Initializable() SignatureValidator() {}\r\n\r\n // external functions\r\n\r\n /**\r\n * @notice Initializes `Gateway` contract\r\n * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\r\n * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\r\n */\r\n function initialize(\r\n ExternalAccountRegistry externalAccountRegistry_,\r\n PersonalAccountRegistry personalAccountRegistry_\r\n )\r\n external\r\n onlyInitializer\r\n {\r\n externalAccountRegistry = externalAccountRegistry_;\r\n personalAccountRegistry = personalAccountRegistry_;\r\n\r\n address[] memory guardians;\r\n _initializeGuarded(guardians); // adds tx.origin to guardians list\r\n }\r\n\r\n // public functions\r\n\r\n /**\r\n * @notice Sends batch\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `msg.sender`\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatch(\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n {\r\n _sendBatch(\r\n msg.sender,\r\n msg.sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends guarded batch\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `msg.sender`\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatchGuarded(\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n onlyGuardian\r\n {\r\n sendBatch(to, data);\r\n }\r\n\r\n /**\r\n * @notice Sends batch from the account\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param account account address\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatchFromAccount(\r\n address account,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n {\r\n _sendBatch(\r\n account,\r\n msg.sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends guarded batch from the account\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param account account address\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatchFromAccountGuarded(\r\n address account,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n onlyGuardian\r\n {\r\n sendBatchFromAccount(account, to, data);\r\n }\r\n\r\n /**\r\n * @notice Delegates batch from the account\r\n * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatch(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n {\r\n require(\r\n nonce > accountNonce[account],\r\n \"Gateway: nonce is lower than current account nonce\"\r\n );\r\n\r\n address sender = _hashDelegatedBatch(\r\n account,\r\n nonce,\r\n to,\r\n data\r\n ).recoverAddress(senderSignature);\r\n\r\n accountNonce[account] = nonce;\r\n\r\n _sendBatch(\r\n account,\r\n sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Delegates guarded batch from the account\r\n * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatchGuarded(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n onlyGuardian\r\n {\r\n delegateBatch(account, nonce, to, data, senderSignature);\r\n }\r\n\r\n /**\r\n * @notice Delegates batch from the account (with gas price)\r\n *\r\n * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatchWithGasPrice(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n {\r\n require(\r\n nonce > accountNonce[account],\r\n \"Gateway: nonce is lower than current account nonce\"\r\n );\r\n\r\n address sender = _hashDelegatedBatchWithGasPrice(\r\n account,\r\n nonce,\r\n to,\r\n data,\r\n tx.gasprice\r\n ).recoverAddress(senderSignature);\r\n\r\n accountNonce[account] = nonce;\r\n\r\n _sendBatch(\r\n account,\r\n sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Delegates guarded batch from the account (with gas price)\r\n *\r\n * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatchWithGasPriceGuarded(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n onlyGuardian\r\n {\r\n delegateBatchWithGasPrice(account, nonce, to, data, senderSignature);\r\n }\r\n\r\n /**\r\n * @notice Delegates multiple batches\r\n * @dev It will revert when all batches fail\r\n * @param batches array of batches\r\n * @param revertOnFailure reverts on any error\r\n */\r\n function delegateBatches(\r\n bytes[] memory batches,\r\n bool revertOnFailure\r\n )\r\n public\r\n {\r\n require(\r\n batches.length > 0,\r\n \"Gateway: cannot delegate empty batches\"\r\n );\r\n\r\n bool anySucceeded;\r\n\r\n for (uint256 i = 0; i < batches.length; i++) {\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool succeeded,) = address(this).call(batches[i]);\r\n\r\n if (revertOnFailure) {\r\n require(\r\n succeeded,\r\n \"Gateway: batch reverted\"\r\n );\r\n } else if (succeeded && !anySucceeded) {\r\n anySucceeded = true;\r\n }\r\n\r\n emit BatchDelegated(\r\n msg.sender,\r\n batches[i],\r\n succeeded\r\n );\r\n }\r\n\r\n if (!anySucceeded) {\r\n revert(\"Gateway: all batches reverted\");\r\n }\r\n }\r\n\r\n /**\r\n * @notice Delegates multiple guarded batches\r\n * @dev It will revert when all batches fail\r\n * @param batches array of batches\r\n * @param revertOnFailure reverts on any error\r\n */\r\n function delegateBatchesGuarded(\r\n bytes[] memory batches,\r\n bool revertOnFailure\r\n )\r\n public\r\n onlyGuardian\r\n {\r\n delegateBatches(batches, revertOnFailure);\r\n }\r\n\r\n // public functions (views)\r\n\r\n /**\r\n * @notice Hashes `DelegatedBatch` message payload\r\n * @param delegatedBatch struct\r\n * @return hash\r\n */\r\n function hashDelegatedBatch(\r\n DelegatedBatch memory delegatedBatch\r\n )\r\n public\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashDelegatedBatch(\r\n delegatedBatch.account,\r\n delegatedBatch.nonce,\r\n delegatedBatch.to,\r\n delegatedBatch.data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Hashes `DelegatedBatchWithGasPrice` message payload\r\n * @param delegatedBatch struct\r\n * @return hash\r\n */\r\n function hashDelegatedBatchWithGasPrice(\r\n DelegatedBatchWithGasPrice memory delegatedBatch\r\n )\r\n public\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashDelegatedBatchWithGasPrice(\r\n delegatedBatch.account,\r\n delegatedBatch.nonce,\r\n delegatedBatch.to,\r\n delegatedBatch.data,\r\n delegatedBatch.gasPrice\r\n );\r\n }\r\n\r\n // external functions (views)\r\n\r\n /**\r\n * @notice Gets next account nonce\r\n * @param account account address\r\n * @return next nonce\r\n */\r\n function getAccountNextNonce(\r\n address account\r\n )\r\n external\r\n view\r\n returns (uint256)\r\n {\r\n return accountNonce[account].add(1);\r\n }\r\n\r\n // private functions\r\n\r\n function _sendBatch(\r\n address account,\r\n address sender,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n private\r\n {\r\n require(\r\n account != address(0),\r\n \"Gateway: cannot send from 0x0 account\"\r\n );\r\n require(\r\n to.length > 0,\r\n \"Gateway: cannot send empty batch\"\r\n );\r\n require(\r\n data.length == to.length,\r\n \"Gateway: invalid batch\"\r\n );\r\n\r\n if (account != sender) {\r\n require(\r\n personalAccountRegistry.verifyAccountOwner(account, sender) ||\r\n externalAccountRegistry.verifyAccountOwner(account, sender),\r\n \"Gateway: sender is not the account owner\"\r\n );\r\n }\r\n\r\n bool succeeded;\r\n\r\n for (uint256 i = 0; i < data.length; i++) {\r\n require(\r\n to[i] != address(0),\r\n \"Gateway: cannot send to 0x0\"\r\n );\r\n\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\r\n\r\n require(\r\n succeeded,\r\n \"Gateway: batch transaction reverted\"\r\n );\r\n }\r\n }\r\n\r\n // private functions (views)\r\n\r\n function _hashDelegatedBatch(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n private\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\r\n account,\r\n nonce,\r\n to,\r\n _concatBytes(data)\r\n ));\r\n }\r\n\r\n function _hashDelegatedBatchWithGasPrice(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n uint256 gasPrice\r\n )\r\n private\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\r\n account,\r\n nonce,\r\n to,\r\n _concatBytes(data),\r\n gasPrice\r\n ));\r\n }\r\n\r\n// private functions (pure)\r\n\r\n function _concatBytes(bytes[] memory data)\r\n private\r\n pure\r\n returns (bytes memory)\r\n {\r\n bytes memory result;\r\n uint dataLen = data.length;\r\n\r\n for (uint i = 0 ; i < dataLen ; i++) {\r\n result = abi.encodePacked(result, data[i]);\r\n }\r\n\r\n return result;\r\n }\r\n}\r\n" + }, + "src/gateway/Gateway.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.12;\r\npragma experimental ABIEncoderV2;\r\n\r\nimport \"../common/libs/ECDSALib.sol\";\r\nimport \"../common/libs/SafeMathLib.sol\";\r\nimport \"../common/lifecycle/Initializable.sol\";\r\nimport \"../common/signature/SignatureValidator.sol\";\r\nimport \"../external/ExternalAccountRegistry.sol\";\r\nimport \"../personal/PersonalAccountRegistry.sol\";\r\n\r\n\r\n/**\r\n * @title Gateway\r\n *\r\n * @notice GSN replacement\r\n *\r\n * @author Stanisław Głogowski \r\n */\r\ncontract Gateway is Initializable, SignatureValidator {\r\n using ECDSALib for bytes32;\r\n using SafeMathLib for uint256;\r\n\r\n struct DelegatedBatch {\r\n address account;\r\n uint256 nonce;\r\n address[] to;\r\n bytes[] data;\r\n }\r\n\r\n struct DelegatedBatchWithGasPrice {\r\n address account;\r\n uint256 nonce;\r\n address[] to;\r\n bytes[] data;\r\n uint256 gasPrice;\r\n }\r\n\r\n bytes32 private constant HASH_PREFIX_DELEGATED_BATCH = keccak256(\r\n \"DelegatedBatch(address account,uint256 nonce,address[] to,bytes[] data)\"\r\n );\r\n\r\n bytes32 private constant HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE = keccak256(\r\n \"DelegatedBatchWithGasPrice(address account,uint256 nonce,address[] to,bytes[] data,uint256 gasPrice)\"\r\n );\r\n\r\n ExternalAccountRegistry public externalAccountRegistry;\r\n PersonalAccountRegistry public personalAccountRegistry;\r\n\r\n mapping(address => uint256) private accountNonce;\r\n\r\n // events\r\n\r\n /**\r\n * @dev Emitted when the single batch is delegated\r\n * @param sender sender address\r\n * @param batch batch\r\n * @param succeeded if succeeded\r\n */\r\n event BatchDelegated(\r\n address sender,\r\n bytes batch,\r\n bool succeeded\r\n );\r\n\r\n /**\r\n * @dev Public constructor\r\n */\r\n constructor() public Initializable() SignatureValidator() {}\r\n\r\n // external functions\r\n\r\n /**\r\n * @notice Initializes `Gateway` contract\r\n * @param externalAccountRegistry_ `ExternalAccountRegistry` contract address\r\n * @param personalAccountRegistry_ `PersonalAccountRegistry` contract address\r\n */\r\n function initialize(\r\n ExternalAccountRegistry externalAccountRegistry_,\r\n PersonalAccountRegistry personalAccountRegistry_\r\n )\r\n external\r\n onlyInitializer\r\n {\r\n externalAccountRegistry = externalAccountRegistry_;\r\n personalAccountRegistry = personalAccountRegistry_;\r\n }\r\n\r\n // public functions\r\n\r\n /**\r\n * @notice Sends batch\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `msg.sender`\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatch(\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n {\r\n _sendBatch(\r\n msg.sender,\r\n msg.sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends batch from the account\r\n * @dev `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return `msg.sender`\r\n *\r\n * @param account account address\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n */\r\n function sendBatchFromAccount(\r\n address account,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n public\r\n {\r\n _sendBatch(\r\n account,\r\n msg.sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Delegates batch from the account\r\n * @dev Use `hashDelegatedBatch` to create sender message payload.\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatch(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n {\r\n require(\r\n nonce > accountNonce[account],\r\n \"Gateway: nonce is lower than current account nonce\"\r\n );\r\n\r\n address sender = _hashDelegatedBatch(\r\n account,\r\n nonce,\r\n to,\r\n data\r\n ).recoverAddress(senderSignature);\r\n\r\n accountNonce[account] = nonce;\r\n\r\n _sendBatch(\r\n account,\r\n sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Delegates batch from the account (with gas price)\r\n *\r\n * @dev Use `hashDelegatedBatchWithGasPrice` to create sender message payload (tx.gasprice as gasPrice)\r\n *\r\n * `GatewayRecipient` context api:\r\n * `_getContextAccount` will return `account` arg\r\n * `_getContextSender` will return recovered address from `senderSignature` arg\r\n *\r\n * @param account account address\r\n * @param nonce next account nonce\r\n * @param to array of batch recipients contracts\r\n * @param data array of batch data\r\n * @param senderSignature sender signature\r\n */\r\n function delegateBatchWithGasPrice(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n bytes memory senderSignature\r\n )\r\n public\r\n {\r\n require(\r\n nonce > accountNonce[account],\r\n \"Gateway: nonce is lower than current account nonce\"\r\n );\r\n\r\n address sender = _hashDelegatedBatchWithGasPrice(\r\n account,\r\n nonce,\r\n to,\r\n data,\r\n tx.gasprice\r\n ).recoverAddress(senderSignature);\r\n\r\n accountNonce[account] = nonce;\r\n\r\n _sendBatch(\r\n account,\r\n sender,\r\n to,\r\n data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Delegates multiple batches\r\n * @dev It will revert when all batches fail\r\n * @param batches array of batches\r\n * @param revertOnFailure reverts on any error\r\n */\r\n function delegateBatches(\r\n bytes[] memory batches,\r\n bool revertOnFailure\r\n )\r\n public\r\n {\r\n require(\r\n batches.length > 0,\r\n \"Gateway: cannot delegate empty batches\"\r\n );\r\n\r\n bool anySucceeded;\r\n\r\n for (uint256 i = 0; i < batches.length; i++) {\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool succeeded,) = address(this).call(batches[i]);\r\n\r\n if (revertOnFailure) {\r\n require(\r\n succeeded,\r\n \"Gateway: batch reverted\"\r\n );\r\n } else if (succeeded && !anySucceeded) {\r\n anySucceeded = true;\r\n }\r\n\r\n emit BatchDelegated(\r\n msg.sender,\r\n batches[i],\r\n succeeded\r\n );\r\n }\r\n\r\n if (!anySucceeded) {\r\n revert(\"Gateway: all batches reverted\");\r\n }\r\n }\r\n\r\n // public functions (views)\r\n\r\n /**\r\n * @notice Hashes `DelegatedBatch` message payload\r\n * @param delegatedBatch struct\r\n * @return hash\r\n */\r\n function hashDelegatedBatch(\r\n DelegatedBatch memory delegatedBatch\r\n )\r\n public\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashDelegatedBatch(\r\n delegatedBatch.account,\r\n delegatedBatch.nonce,\r\n delegatedBatch.to,\r\n delegatedBatch.data\r\n );\r\n }\r\n\r\n /**\r\n * @notice Hashes `DelegatedBatchWithGasPrice` message payload\r\n * @param delegatedBatch struct\r\n * @return hash\r\n */\r\n function hashDelegatedBatchWithGasPrice(\r\n DelegatedBatchWithGasPrice memory delegatedBatch\r\n )\r\n public\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashDelegatedBatchWithGasPrice(\r\n delegatedBatch.account,\r\n delegatedBatch.nonce,\r\n delegatedBatch.to,\r\n delegatedBatch.data,\r\n delegatedBatch.gasPrice\r\n );\r\n }\r\n\r\n // external functions (views)\r\n\r\n /**\r\n * @notice Gets next account nonce\r\n * @param account account address\r\n * @return next nonce\r\n */\r\n function getAccountNextNonce(\r\n address account\r\n )\r\n external\r\n view\r\n returns (uint256)\r\n {\r\n return accountNonce[account].add(1);\r\n }\r\n\r\n // private functions\r\n\r\n function _sendBatch(\r\n address account,\r\n address sender,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n private\r\n {\r\n require(\r\n account != address(0),\r\n \"Gateway: cannot send from 0x0 account\"\r\n );\r\n require(\r\n to.length > 0,\r\n \"Gateway: cannot send empty batch\"\r\n );\r\n require(\r\n data.length == to.length,\r\n \"Gateway: invalid batch\"\r\n );\r\n\r\n if (account != sender) {\r\n require(\r\n personalAccountRegistry.verifyAccountOwner(account, sender) ||\r\n externalAccountRegistry.verifyAccountOwner(account, sender),\r\n \"Gateway: sender is not the account owner\"\r\n );\r\n }\r\n\r\n bool succeeded;\r\n\r\n for (uint256 i = 0; i < data.length; i++) {\r\n require(\r\n to[i] != address(0),\r\n \"Gateway: cannot send to 0x0\"\r\n );\r\n\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (succeeded,) = to[i].call(abi.encodePacked(data[i], account, sender));\r\n\r\n require(\r\n succeeded,\r\n \"Gateway: batch transaction reverted\"\r\n );\r\n }\r\n }\r\n\r\n // private functions (views)\r\n\r\n function _hashDelegatedBatch(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data\r\n )\r\n private\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH, abi.encodePacked(\r\n account,\r\n nonce,\r\n to,\r\n _concatBytes(data)\r\n ));\r\n }\r\n\r\n function _hashDelegatedBatchWithGasPrice(\r\n address account,\r\n uint256 nonce,\r\n address[] memory to,\r\n bytes[] memory data,\r\n uint256 gasPrice\r\n )\r\n private\r\n view\r\n returns (bytes32)\r\n {\r\n return _hashMessagePayload(HASH_PREFIX_DELEGATED_BATCH_WITH_GAS_PRICE, abi.encodePacked(\r\n account,\r\n nonce,\r\n to,\r\n _concatBytes(data),\r\n gasPrice\r\n ));\r\n }\r\n\r\n// private functions (pure)\r\n\r\n function _concatBytes(bytes[] memory data)\r\n private\r\n pure\r\n returns (bytes memory)\r\n {\r\n bytes memory result;\r\n uint dataLen = data.length;\r\n\r\n for (uint i = 0 ; i < dataLen ; i++) {\r\n result = abi.encodePacked(result, data[i]);\r\n }\r\n\r\n return result;\r\n }\r\n}" + }, + "src/ens/ENSController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/access/Guarded.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"../common/signature/SignatureValidator.sol\";\nimport \"../gateway/GatewayRecipient.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./resolvers/ENSPubKeyResolver.sol\";\nimport \"./resolvers/ENSTextResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n\n/**\n * @title ENS controller\n *\n * @notice ENS subnode registrar\n *\n * @dev The process of adding root node consists of 3 steps:\n * 1. `submitNode` - should be called from ENS node owner,\n * 2. Change ENS node owner in ENS registry to ENS controller,\n * 3. `verifyNode` - should be called from previous ENS node owner,\n *\n * To register sub node, `msg.sender` need to send valid signature from one of guardian key.\n * Once registration is complete `msg.sender` becoming both node owner and `addr` record value.\n *\n * After registration sub node cannot be replaced.\n *\n * @author Stanisław Głogowski \n */\ncontract ENSController is Guarded, Initializable, SignatureValidator, GatewayRecipient, ENSAddressResolver, ENSNameResolver, ENSPubKeyResolver, ENSTextResolver {\n struct SubNodeRegistration {\n address account;\n bytes32 node;\n bytes32 label;\n }\n\n bytes4 private constant INTERFACE_META_ID = bytes4(keccak256(abi.encodePacked(\"supportsInterface(bytes4)\")));\n\n bytes32 private constant HASH_PREFIX_SUB_NODE_REGISTRATION = keccak256(\n \"SubNodeRegistration(address account,bytes32 node,bytes32 label)\"\n );\n\n ENSRegistry public registry;\n\n mapping(bytes32 => address) public nodeOwners;\n\n // events\n\n /**\n * @dev Emitted when new node is submitted\n * @param node node name hash\n * @param owner owner address\n */\n event NodeSubmitted(\n bytes32 node,\n address owner\n );\n\n /**\n * @dev Emitted when the existing owner is verified\n * @param node node name hash\n */\n event NodeVerified(\n bytes32 node\n );\n\n /**\n * @dev Emitted when new node is released\n * @param node node name hash\n * @param owner owner address\n */\n event NodeReleased(\n bytes32 node,\n address owner\n );\n\n /**\n * @dev Emitted when ENS registry address is changed\n * @param registry registry address\n */\n event RegistryChanged(\n address registry\n );\n\n /**\n * @dev Public constructor\n */\n constructor() public Guarded() Initializable() SignatureValidator() {}\n\n // external functions\n\n /**\n * @notice Initializes `ENSController` contract\n * @param registry_ ENS registry address\n * @param gateway_ gateway address\n */\n function initialize(\n ENSRegistry registry_,\n address[] calldata guardians_,\n address gateway_\n )\n external\n onlyInitializer\n {\n require(\n address(registry_) != address(0),\n \"ENSController: cannot set 0x0 registry\"\n );\n\n registry = registry_;\n\n // Guarded\n _initializeGuarded(guardians_);\n\n // GatewayRecipient\n _initializeGatewayRecipient(gateway_);\n }\n\n /**\n * @notice Sets registry\n * @param registry_ registry address\n */\n function setRegistry(\n ENSRegistry registry_\n )\n external\n onlyGuardian\n {\n require(\n address(registry_) != address(0),\n \"ENSController: cannot set 0x0 registry\"\n );\n\n require(\n registry_ != registry,\n \"ENSController: registry already set\"\n );\n\n registry = registry_;\n\n emit RegistryChanged(\n address(registry)\n );\n }\n\n /**\n * @notice Submits node\n * @dev Should be called from the current ENS node owner\n * @param node node name hash\n */\n function submitNode(\n bytes32 node\n )\n external\n {\n address owner = _getContextAccount();\n\n require(\n _addr(node) == address(0),\n \"ENSController: node already exists\"\n );\n\n require(\n nodeOwners[node] == address(0),\n \"ENSController: node already submitted\"\n );\n\n require(\n registry.owner(node) == owner,\n \"ENSController: invalid ens node owner\"\n );\n\n nodeOwners[node] = owner;\n\n emit NodeSubmitted(node, owner);\n }\n\n /**\n * @notice Verifies node\n * @dev Should be called from the previous ENS node owner\n * @param node node name hash\n */\n function verifyNode(\n bytes32 node\n )\n external\n {\n address owner = _getContextAccount();\n\n require(\n _addr(node) == address(0),\n \"ENSController: node already exists\"\n );\n\n require(\n nodeOwners[node] == owner,\n \"ENSController: invalid node owner\"\n );\n\n require(\n registry.owner(node) == address(this),\n \"ENSController: invalid ens node owner\"\n );\n\n _setAddr(node, address(this));\n\n registry.setResolver(node, address(this));\n\n emit NodeVerified(node);\n }\n\n /**\n * @notice Releases node\n * @dev Should be called from the previous ENS node owner\n * @param node node name hash\n */\n function releaseNode(\n bytes32 node\n )\n external\n {\n address owner = _getContextAccount();\n\n require(\n _addr(node) == address(this),\n \"ENSController: node doesn't exist\"\n );\n\n require(\n nodeOwners[node] == owner,\n \"ENSController: invalid node owner\"\n );\n\n registry.setOwner(node, owner);\n\n delete nodeOwners[node];\n\n emit NodeReleased(node, owner);\n }\n\n /**\n * @notice Sync address\n * @param node node name hash\n */\n function syncAddr(\n bytes32 node\n )\n external\n {\n address account = _getContextAccount();\n\n require(\n account == registry.owner(node),\n \"ENSController: caller is not the node owner\"\n );\n\n require(\n registry.resolver(node) == address(this),\n \"ENSController: invalid node resolver\"\n );\n\n require(\n _addr(node) == address(0),\n \"ENSController: node already in sync\"\n );\n\n _setAddr(node, account);\n }\n\n /**\n * @notice Registers sub node\n * @param node node name hash\n * @param label label hash\n * @param guardianSignature guardian signature\n */\n function registerSubNode(\n bytes32 node,\n bytes32 label,\n bytes calldata guardianSignature\n )\n external\n {\n address account = _getContextAccount();\n\n bytes32 messageHash = _hashSubNodeRegistration(\n account,\n node,\n label\n );\n\n require(\n _verifyGuardianSignature(messageHash, guardianSignature),\n \"ENSController: invalid guardian signature\"\n );\n\n bytes32 subNode = keccak256(\n abi.encodePacked(\n node,\n label\n )\n );\n\n require(\n _addr(node) == address(this),\n \"ENSController: invalid node\"\n );\n\n require(\n _addr(subNode) == address(0),\n \"ENSController: label already taken\"\n );\n\n registry.setSubnodeRecord(node, label, address(this), address(this), 0);\n registry.setOwner(subNode, account);\n\n _setAddr(subNode, account);\n }\n\n // external functions (pure)\n function supportsInterface(\n bytes4 interfaceID\n )\n external\n pure\n returns(bool)\n {\n return interfaceID == INTERFACE_META_ID ||\n interfaceID == INTERFACE_ADDR_ID ||\n interfaceID == INTERFACE_ADDRESS_ID ||\n interfaceID == INTERFACE_NAME_ID ||\n interfaceID == INTERFACE_PUB_KEY_ID ||\n interfaceID == INTERFACE_TEXT_ID;\n }\n\n // public functions (views)\n\n /**\n * @notice Hashes `SubNodeRegistration` message payload\n * @param subNodeRegistration struct\n * @return hash\n */\n function hashSubNodeRegistration(\n SubNodeRegistration memory subNodeRegistration\n )\n public\n view\n returns (bytes32)\n {\n return _hashSubNodeRegistration(\n subNodeRegistration.account,\n subNodeRegistration.node,\n subNodeRegistration.label\n );\n }\n\n // internal functions (views)\n\n function _isNodeOwner(\n bytes32 node\n )\n internal\n override\n view\n returns (bool)\n {\n return registry.owner(node) == _getContextAccount();\n }\n\n // private functions (views)\n\n function _hashSubNodeRegistration(\n address account,\n bytes32 node,\n bytes32 label\n )\n private\n view\n returns (bytes32)\n {\n return _hashMessagePayload(HASH_PREFIX_SUB_NODE_REGISTRATION, abi.encodePacked(\n account,\n node,\n label\n ));\n }\n}\n" + }, + "src/ens/resolvers/ENSAddressResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract address resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/AddrResolver.sol\n */\nabstract contract ENSAddressResolver is ENSAbstractResolver {\n bytes4 internal constant INTERFACE_ADDR_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32)\")));\n bytes4 internal constant INTERFACE_ADDRESS_ID = bytes4(keccak256(abi.encodePacked(\"addr(bytes32,uint)\")));\n\n uint internal constant COIN_TYPE_ETH = 60;\n\n mapping(bytes32 => mapping(uint => bytes)) internal resolverAddresses;\n\n // events\n\n event AddrChanged(\n bytes32 indexed node,\n address addr\n );\n\n event AddressChanged(\n bytes32 indexed node,\n uint coinType,\n bytes newAddress\n );\n\n // external functions\n\n function setAddr(\n bytes32 node,\n address addr_\n )\n external\n onlyNodeOwner(node)\n {\n _setAddr(node, addr_);\n }\n\n function setAddr(\n bytes32 node,\n uint coinType,\n bytes memory addr_\n )\n external\n onlyNodeOwner(node)\n {\n _setAddr(node, coinType, addr_);\n }\n\n // external functions (views)\n\n function addr(\n bytes32 node\n )\n external\n view\n returns (address)\n {\n return _addr(node);\n }\n\n function addr(\n bytes32 node,\n uint coinType\n )\n external\n view\n returns (bytes memory)\n {\n return resolverAddresses[node][coinType];\n }\n\n // internal functions\n\n function _setAddr(\n bytes32 node,\n address addr_\n )\n internal\n {\n _setAddr(node, COIN_TYPE_ETH, _addressToBytes(addr_));\n }\n\n function _setAddr(\n bytes32 node,\n uint coinType,\n bytes memory addr_\n )\n internal\n {\n emit AddressChanged(node, coinType, addr_);\n\n if(coinType == COIN_TYPE_ETH) {\n emit AddrChanged(node, _bytesToAddress(addr_));\n }\n\n resolverAddresses[node][coinType] = addr_;\n }\n\n // internal functions (views)\n\n function _addr(\n bytes32 node\n )\n internal\n view\n returns (address)\n {\n address result;\n\n bytes memory addr_ = resolverAddresses[node][COIN_TYPE_ETH];\n\n if (addr_.length > 0) {\n result = _bytesToAddress(addr_);\n }\n\n return result;\n }\n\n // private function (pure)\n\n function _bytesToAddress(\n bytes memory data\n )\n private\n pure\n returns(address payable)\n {\n address payable result;\n\n require(data.length == 20);\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n result := div(mload(add(data, 32)), exp(256, 12))\n }\n\n return result;\n }\n\n function _addressToBytes(\n address addr_\n )\n private\n pure\n returns(bytes memory)\n {\n bytes memory result = new bytes(20);\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n mstore(add(result, 32), mul(addr_, exp(256, 12)))\n }\n\n return result;\n }\n}\n" + }, + "src/ens/resolvers/ENSNameResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract name resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/NameResolver.sol\n */\nabstract contract ENSNameResolver is ENSAbstractResolver {\n bytes4 internal constant INTERFACE_NAME_ID = bytes4(keccak256(abi.encodePacked(\"name(bytes32)\")));\n\n mapping(bytes32 => string) internal resolverNames;\n\n // events\n\n event NameChanged(\n bytes32 indexed node,\n string name\n );\n\n // external functions\n\n function setName(\n bytes32 node,\n string calldata name\n )\n external\n onlyNodeOwner(node)\n {\n resolverNames[node] = name;\n\n emit NameChanged(node, name);\n }\n\n // external functions (views)\n\n function name(\n bytes32 node\n )\n external\n view\n returns (string memory)\n {\n return resolverNames[node];\n }\n}\n" + }, + "src/ens/resolvers/ENSPubKeyResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract pub key resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/PubkeyResolver.sol\n */\nabstract contract ENSPubKeyResolver is ENSAbstractResolver {\n bytes4 internal constant INTERFACE_PUB_KEY_ID = bytes4(keccak256(abi.encodePacked(\"pubkey(bytes32)\")));\n\n struct PubKey {\n bytes32 x;\n bytes32 y;\n }\n\n mapping(bytes32 => PubKey) internal resolverPubKeys;\n\n // events\n\n event PubkeyChanged(\n bytes32 indexed node,\n bytes32 x,\n bytes32 y\n );\n\n // external functions (views)\n\n function setPubkey(\n bytes32 node,\n bytes32 x,\n bytes32 y\n )\n external\n onlyNodeOwner(node)\n {\n resolverPubKeys[node] = PubKey(x, y);\n\n emit PubkeyChanged(node, x, y);\n }\n\n // external functions (views)\n\n function pubkey(\n bytes32 node\n )\n external\n view\n returns (bytes32 x, bytes32 y)\n {\n return (resolverPubKeys[node].x, resolverPubKeys[node].y);\n }\n}\n" + }, + "src/ens/resolvers/ENSTextResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"./ENSAbstractResolver.sol\";\n\n\n/**\n * @title ENS abstract text resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/profiles/TextResolver.sol\n */\nabstract contract ENSTextResolver is ENSAbstractResolver {\n bytes4 internal constant INTERFACE_TEXT_ID = bytes4(keccak256(abi.encodePacked(\"text(bytes32,string)\")));\n\n mapping(bytes32 => mapping(string => string)) internal resolverTexts;\n\n // events\n\n event TextChanged(\n bytes32 indexed node,\n string indexed indexedKey,\n string key\n );\n\n // external functions (views)\n\n function setText(\n bytes32 node,\n string calldata key,\n string calldata value\n )\n external\n onlyNodeOwner(node)\n {\n resolverTexts[node][key] = value;\n\n emit TextChanged(node, key, key);\n }\n\n // external functions (views)\n\n function text(\n bytes32 node,\n string calldata key\n )\n external\n view\n returns (string memory)\n {\n return resolverTexts[node][key];\n }\n}\n" + }, + "src/ens/ENSRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS registry\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ENSRegistry.sol\n */\ncontract ENSRegistry {\n struct Record {\n address owner;\n address resolver;\n uint64 ttl;\n }\n\n mapping (bytes32 => Record) private records;\n mapping (address => mapping(address => bool)) private operators;\n\n // events\n\n event NewOwner(\n bytes32 indexed node,\n bytes32 indexed label,\n address owner\n );\n\n event Transfer(\n bytes32 indexed node,\n address owner\n );\n\n event NewResolver(\n bytes32 indexed node,\n address resolver\n );\n\n event NewTTL(\n bytes32 indexed node,\n uint64 ttl\n );\n\n event ApprovalForAll(\n address indexed owner,\n address indexed operator,\n bool approved\n );\n\n // modifiers\n\n modifier authorised(\n bytes32 node\n )\n {\n address owner = records[node].owner;\n\n require(\n owner == msg.sender || operators[owner][msg.sender],\n \"ENSRegistry: reverted by authorised modifier\"\n );\n\n _;\n }\n\n /**\n * @dev Public constructor\n */\n constructor()\n public\n {\n // solhint-disable-next-line avoid-tx-origin\n records[0x0].owner = tx.origin;\n }\n\n // external functions\n\n function setRecord(\n bytes32 node,\n address owner_,\n address resolver_,\n uint64 ttl_\n )\n external\n {\n setOwner(node, owner_);\n\n _setResolverAndTTL(node, resolver_, ttl_);\n }\n\n function setTTL(\n bytes32 node,\n uint64 ttl_\n )\n external\n authorised(node)\n {\n records[node].ttl = ttl_;\n\n emit NewTTL(node, ttl_);\n }\n\n function setSubnodeRecord(\n bytes32 node,\n bytes32 label,\n address owner_,\n address resolver_,\n uint64 ttl_\n )\n external\n {\n bytes32 subNode = setSubnodeOwner(node, label, owner_);\n\n _setResolverAndTTL(subNode, resolver_, ttl_);\n }\n\n function setApprovalForAll(\n address operator,\n bool approved\n )\n external\n {\n operators[msg.sender][operator] = approved;\n\n emit ApprovalForAll(\n msg.sender,\n operator,\n approved\n );\n }\n\n // external functions (views)\n\n function owner(\n bytes32 node\n )\n external\n view\n returns (address)\n {\n address addr = records[node].owner;\n\n if (addr == address(this)) {\n return address(0x0);\n }\n\n return addr;\n }\n\n function resolver(\n bytes32 node\n )\n external\n view\n returns (address)\n {\n return records[node].resolver;\n }\n\n function ttl(\n bytes32 node\n )\n external\n view\n returns (uint64)\n {\n return records[node].ttl;\n }\n\n function recordExists(\n bytes32 node\n )\n external\n view\n returns (bool)\n {\n return records[node].owner != address(0x0);\n }\n\n function isApprovedForAll(\n address owner_,\n address operator\n )\n external\n view\n returns (bool)\n {\n return operators[owner_][operator];\n }\n\n // public functions\n\n function setOwner(\n bytes32 node,\n address owner_\n )\n public\n authorised(node)\n {\n records[node].owner = owner_;\n\n emit Transfer(node, owner_);\n }\n\n function setResolver(\n bytes32 node,\n address resolver_\n )\n public\n authorised(node)\n {\n records[node].resolver = resolver_;\n\n emit NewResolver(node, resolver_);\n }\n\n function setSubnodeOwner(\n bytes32 node,\n bytes32 label,\n address owner_\n )\n public\n authorised(node)\n returns(bytes32)\n {\n bytes32 subNode = keccak256(abi.encodePacked(node, label));\n\n records[subNode].owner = owner_;\n\n emit NewOwner(node, label, owner_);\n\n return subNode;\n }\n\n // private functions\n\n function _setResolverAndTTL(\n bytes32 node,\n address resolver_,\n uint64 ttl_\n )\n private\n {\n if (resolver_ != records[node].resolver) {\n records[node].resolver = resolver_;\n\n emit NewResolver(node, resolver_);\n }\n\n if (ttl_ != records[node].ttl) {\n records[node].ttl = ttl_;\n\n emit NewTTL(node, ttl_);\n }\n }\n}\n" + }, + "src/ens/resolvers/ENSAbstractResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title ENS abstract resolver\n *\n * @dev Base on https://github.com/ensdomains/resolvers/blob/f7d62ab04bfe1692a4344f6f1d31ff81315a98c3/contracts/ResolverBase.sol\n */\nabstract contract ENSAbstractResolver {\n // modifiers\n\n modifier onlyNodeOwner(bytes32 node)\n {\n require(\n _isNodeOwner(node),\n \"ENSAbstractResolver: reverted by onlyNodeOwner modifier\"\n );\n\n _;\n }\n\n // internal functions (views)\n\n function _isNodeOwner(\n bytes32 node\n )\n internal\n virtual\n view\n returns (bool);\n}\n" + }, + "src/ens/ENSReverseRegistrar.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/libs/AddressLib.sol\";\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS reverse registrar\n *\n * @dev Base on https://github.com/ensdomains/ens/blob/ff0f41747c05f1598973b0fe7ad0d9e09565dfcd/contracts/ReverseRegistrar.sol\n */\ncontract ENSReverseRegistrar is Initializable {\n using AddressLib for address;\n\n // namehash('addr.reverse')\n bytes32 public constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;\n\n ENSRegistry public registry;\n ENSNameResolver public resolver;\n\n /**\n * @dev Public constructor\n */\n constructor() public Initializable() {}\n\n // external functions\n\n /**\n * @notice Initializes `ENSReverseRegistrar` contract\n * @param registry_ ENS registry address\n * @param resolver_ ENS name resolver address\n */\n function initialize(\n ENSRegistry registry_,\n ENSNameResolver resolver_\n )\n external\n onlyInitializer\n {\n registry = registry_;\n resolver = resolver_;\n }\n\n // external functions\n\n function claim(\n address owner\n )\n public\n returns (bytes32)\n {\n return _claimWithResolver(owner, address(0));\n }\n\n function claimWithResolver(\n address owner,\n address resolver_\n )\n public\n returns (bytes32)\n {\n return _claimWithResolver(owner, resolver_);\n }\n\n function setName(\n string memory name\n )\n public\n returns (bytes32)\n {\n bytes32 node = _claimWithResolver(address(this), address(resolver));\n\n resolver.setName(node, name);\n\n return node;\n }\n\n // external functions (pure)\n\n function node(\n address addr_\n )\n external\n pure\n returns (bytes32)\n {\n return keccak256(abi.encodePacked(ADDR_REVERSE_NODE, addr_.toSha3Hash()));\n }\n\n // private functions\n\n function _claimWithResolver(\n address owner,\n address resolver_\n )\n private\n returns (bytes32)\n {\n bytes32 label = address(msg.sender).toSha3Hash();\n bytes32 node_ = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));\n address currentOwner = registry.owner(node_);\n\n if (resolver_ != address(0x0) && resolver_ != registry.resolver(node_)) {\n if (currentOwner != address(this)) {\n registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));\n currentOwner = address(this);\n }\n\n registry.setResolver(node_, resolver_);\n }\n\n // Update the owner if required\n if (currentOwner != owner) {\n registry.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);\n }\n\n return node_;\n }\n}\n" + }, + "src/common/libs/AddressLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\n/**\n * @title Address library\n */\nlibrary AddressLib {\n /**\n * @notice Converts address into sha3 hash\n * @param self address\n * @return sha3 hash\n */\n function toSha3Hash(\n address self\n )\n internal\n pure\n returns (bytes32)\n {\n bytes32 result;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let lookup := 0x3031323334353637383961626364656600000000000000000000000000000000\n\n for { let i := 40 } gt(i, 0) { } {\n i := sub(i, 1)\n mstore8(i, byte(and(self, 0xf), lookup))\n self := div(self, 0x10)\n i := sub(i, 1)\n mstore8(i, byte(and(self, 0xf), lookup))\n self := div(self, 0x10)\n }\n\n result := keccak256(0, 40)\n }\n\n return result;\n }\n}\n" + }, + "src/ens/ENSHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\npragma experimental ABIEncoderV2;\n\nimport \"../common/lifecycle/Initializable.sol\";\nimport \"./resolvers/ENSAddressResolver.sol\";\nimport \"./resolvers/ENSNameResolver.sol\";\nimport \"./ENSRegistry.sol\";\n\n/**\n * @title ENS helper\n *\n * @author Stanisław Głogowski \n */\ncontract ENSHelper is Initializable {\n ENSRegistry public registry;\n\n /**\n * @dev Public constructor\n */\n constructor() public Initializable() {}\n\n // external functions\n\n /**\n * @notice Initializes `ENSLookupHelper` contract\n * @param registry_ ENS registry address\n */\n function initialize(\n ENSRegistry registry_\n )\n external\n onlyInitializer\n {\n registry = registry_;\n }\n\n // external functions (views)\n\n /**\n * @notice Gets nodes addresses\n * @param nodes array of nodes\n * @return nodes addresses\n */\n function getAddresses(\n bytes32[] memory nodes\n )\n external\n view\n returns (address[] memory)\n {\n uint nodesLen = nodes.length;\n address[] memory result = new address[](nodesLen);\n\n for (uint i = 0; i < nodesLen; i++) {\n result[i] = _getAddress(nodes[i]);\n }\n\n return result;\n }\n\n /**\n * @notice Gets nodes names\n * @param nodes array of nodes\n * @return nodes names\n */\n function getNames(\n bytes32[] memory nodes\n )\n external\n view\n returns (string[] memory)\n {\n uint nodesLen = nodes.length;\n string[] memory result = new string[](nodesLen);\n\n for (uint i = 0; i < nodesLen; i++) {\n result[i] = _getName(nodes[i]);\n }\n\n return result;\n }\n\n // private functions (views)\n\n function _getAddress(\n bytes32 node\n )\n private\n view\n returns (address)\n {\n address result;\n address resolver = registry.resolver(node);\n\n if (resolver != address(0)) {\n try ENSAddressResolver(resolver).addr(node) returns (address addr) {\n result = addr;\n } catch {\n //\n }\n }\n\n return result;\n }\n\n function _getName(\n bytes32 node\n )\n private\n view\n returns (string memory)\n {\n string memory result;\n address resolver = registry.resolver(node);\n\n if (resolver != address(0)) {\n try ENSNameResolver(resolver).name(node) returns (string memory name) {\n result = name;\n } catch {\n //\n }\n }\n\n return result;\n }\n}\n" + }, + "src/common/account/AccountImplementationV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../lifecycle/Initializable.sol\";\nimport \"./AccountBase.sol\";\nimport \"./AccountRegistry.sol\";\n\n\n/**\n * @title Account implementation (version 1)\n *\n * @author Stanisław Głogowski \n */\ncontract AccountImplementationV1 is Initializable, AccountBase {\n bytes32 constant private ERC777_TOKENS_RECIPIENT_INTERFACE_HASH = keccak256(abi.encodePacked(\"ERC777TokensRecipient\"));\n bytes32 constant private ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n bytes4 constant private ERC1271_VALID_MESSAGE_HASH_SIGNATURE = bytes4(keccak256(abi.encodePacked(\"isValidSignature(bytes32,bytes)\")));\n bytes4 constant private ERC1271_VALID_MESSAGE_SIGNATURE = bytes4(keccak256(abi.encodePacked(\"isValidSignature(bytes,bytes)\")));\n bytes4 constant private ERC1271_INVALID_SIGNATURE = 0xffffffff;\n\n /**\n * @dev Internal constructor\n */\n constructor() internal Initializable() {}\n\n // external functions\n\n /**\n * @notice Initializes `AccountImplementation` contract\n * @param registry_ registry address\n */\n function initialize(\n address registry_\n )\n external\n onlyInitializer\n {\n registry = registry_;\n }\n\n // external functions (views)\n\n // ERC1820\n\n function canImplementInterfaceForAddress(\n bytes32 interfaceHash,\n address addr\n )\n external\n view\n returns(bytes32)\n {\n bytes32 result;\n\n if (interfaceHash == ERC777_TOKENS_RECIPIENT_INTERFACE_HASH && addr == address(this)) {\n result = ERC1820_ACCEPT_MAGIC;\n }\n\n return result;\n }\n\n // ERC1271\n\n function isValidSignature(\n bytes32 messageHash,\n bytes calldata signature\n )\n external\n view\n returns (bytes4)\n {\n return AccountRegistry(registry).isValidAccountSignature(address(this), messageHash, signature)\n ? ERC1271_VALID_MESSAGE_HASH_SIGNATURE\n : ERC1271_INVALID_SIGNATURE;\n }\n\n function isValidSignature(\n bytes calldata message,\n bytes calldata signature\n )\n external\n view\n returns (bytes4)\n {\n return AccountRegistry(registry).isValidAccountSignature(address(this), message, signature)\n ? ERC1271_VALID_MESSAGE_SIGNATURE\n : ERC1271_INVALID_SIGNATURE;\n }\n\n // external functions (pure)\n\n // ERC721\n\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n )\n external\n pure\n returns (bytes4)\n {\n return this.onERC721Received.selector;\n }\n\n // ERC1155\n\n function onERC1155Received(\n address,\n address,\n uint256,\n uint256,\n bytes calldata\n )\n external\n pure\n returns (bytes4)\n {\n return this.onERC1155Received.selector;\n }\n\n // ERC777\n\n function tokensReceived(\n address,\n address,\n address,\n uint256,\n bytes calldata,\n bytes calldata\n )\n external\n pure\n {}\n}\n" + }, + "src/personal/PersonalAccountImplementationV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../common/account/AccountImplementationV1.sol\";\n\n\n/**\n * @title Personal account implementation (version 1)\n *\n * @author Stanisław Głogowski \n */\ncontract PersonalAccountImplementationV1 is AccountImplementationV1 {\n\n /**\n * @dev Public constructor\n */\n constructor() public AccountImplementationV1() {}\n}\n" + }, + "src/common/account/mocks/AccountImplementationV1Mock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../AccountImplementationV1.sol\";\n\n\n/**\n * @title Account implementation mock (version 1)\n *\n * @author Stanisław Głogowski \n */\ncontract AccountImplementationV1Mock is AccountImplementationV1 {\n /**\n * @dev Public constructor\n * @param registry_ account registry address\n */\n constructor(\n address registry_\n )\n public\n AccountImplementationV1()\n {\n registry = registry_;\n }\n}\n" + }, + "src/common/account/mocks/AccountRegistryMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../../libs/ECDSALib.sol\";\nimport \"../../libs/ECDSAExtendedLib.sol\";\nimport \"../AccountRegistry.sol\";\n\n\n/**\n * @title Account registry mock\n *\n * @author Stanisław Głogowski \n */\ncontract AccountRegistryMock is AccountRegistry {\n using ECDSALib for bytes32;\n using ECDSAExtendedLib for bytes;\n\n mapping(address => mapping(address => bool)) private mockedAccountsOwners;\n\n // external functions\n\n function mockAccountOwners(\n address account,\n address[] memory owners\n )\n external\n {\n uint ownersLen = owners.length;\n for (uint i = 0; i < ownersLen; i++) {\n mockedAccountsOwners[account][owners[i]] = true;\n }\n }\n\n // external functions (views)\n\n function isValidAccountSignature(\n address account,\n bytes32 messageHash,\n bytes calldata signature\n )\n override\n external\n view\n returns (bool)\n {\n address recovered = messageHash.recoverAddress(signature);\n\n return mockedAccountsOwners[account][recovered];\n }\n\n function isValidAccountSignature(\n address account,\n bytes calldata message,\n bytes calldata signature\n )\n override\n external\n view\n returns (bool)\n {\n address recovered = message.toEthereumSignedMessageHash().recoverAddress(signature);\n\n return mockedAccountsOwners[account][recovered];\n }\n}\n" + }, + "src/common/access/mocks/GuardedMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../Guarded.sol\";\n\n\n/**\n * @title Guarded mock\n *\n * @dev Used in `Guarded` contract tests\n *\n * @author Stanisław Głogowski \n */\ncontract GuardedMock is Guarded {\n /**\n * @dev Public constructor\n * @param guardians_ array of guardians addresses\n */\n constructor(\n address[] memory guardians_\n )\n public\n {\n _initializeGuarded(guardians_);\n }\n}\n" + }, + "src/common/account/mocks/AccountControllerMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../AccountController.sol\";\n\n\n/**\n * @title Account controller mock\n *\n * @author Stanisław Głogowski \n */\ncontract AccountControllerMock is AccountController {\n /**\n * @dev Public constructor\n * @param accountRegistry_ account registry address\n * @param accountImplementation_ account implementation address\n */\n constructor(\n address accountRegistry_,\n address accountImplementation_\n )\n public\n AccountController()\n {\n _initializeAccountController(accountRegistry_, accountImplementation_);\n }\n\n // external functions\n\n /**\n * @notice Sets account registry\n * @param accountRegistry_ account registry address\n */\n function setAccountRegistry(\n address accountRegistry_\n )\n external\n {\n _setAccountRegistry(accountRegistry_, true);\n }\n\n /**\n * @notice Sets account implementation\n * @param accountImplementation_ account implementation address\n */\n function setAccountImplementation(\n address accountImplementation_\n )\n external\n {\n _setAccountImplementation(accountImplementation_, true);\n }\n\n /**\n * @notice Deploys account\n * @param salt CREATE2 salt\n */\n function deployAccount(\n bytes32 salt\n )\n external\n {\n _deployAccount(salt, true);\n }\n\n /**\n * @notice Upgrades account\n * @param account account address\n */\n function upgradeAccount(\n address account\n )\n external\n {\n _upgradeAccount(account, true);\n }\n\n /**\n * @notice Executes transaction from the account\n * @param account account address\n * @param to to address\n * @param value value\n * @param data data\n */\n function executeAccountTransaction(\n address account,\n address to,\n uint256 value,\n bytes memory data\n )\n external\n {\n _executeAccountTransaction(account, to, value, data, true);\n }\n\n // external functions (views)\n\n /**\n * @notice Computes account CREATE2 address\n * @param salt CREATE2 salt\n * @return account address\n */\n function computeAccountAddress(\n bytes32 salt\n )\n external\n view\n returns (address)\n {\n return _computeAccountAddress(salt);\n }\n}\n" + }, + "src/common/helpers/BalancesHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../token/ERC20Token.sol\";\nimport \"../libs/SafeMathLib.sol\";\n\n\n/**\n * @title Balances helper\n *\n * @author Jegor Sidorenko \n * @author Stanisław Głogowski \n */\ncontract BalancesHelper {\n using SafeMathLib for uint256;\n\n // external functions\n\n /**\n * @notice Checks the token balances of accounts for multiple tokens.\n * @dev Pass 0x0 as a \"token\" address to get ETH balance.\n *\n * Possible error throws:\n * - extremely large arrays for account and or tokens (gas cost too high)\n *\n * @param accounts array of accounts addresses\n * @param tokens array of tokens addresses\n * @return a one-dimensional that's user.length * tokens.length long. The\n * array is ordered by all of the 0th accounts token balances, then the 1th\n * user, and so on.\n */\n function getBalances(\n address[] calldata accounts,\n address[] calldata tokens\n )\n external\n view\n returns (uint[] memory)\n {\n uint[] memory result = new uint[](accounts.length.mul(tokens.length));\n\n for (uint i = 0; i < accounts.length; i++) {\n for (uint j = 0; j < tokens.length; j++) {\n uint index = j.add(tokens.length.mul(i));\n\n if (tokens[j] != address(0x0)) {\n result[index] = _getBalance(accounts[i], tokens[j]);\n } else {\n result[index] = accounts[i].balance;\n }\n }\n }\n\n return result;\n }\n\n // private functions\n\n function _getBalance(\n address account,\n address token\n )\n private\n view\n returns (uint256)\n {\n uint256 result = 0;\n uint256 tokenCode;\n\n /// @dev check if token is actually a contract\n // solhint-disable-next-line no-inline-assembly\n assembly { tokenCode := extcodesize(token) } // contract code size\n\n if (tokenCode > 0) {\n /// @dev is it a contract and does it implement balanceOf\n // solhint-disable-next-line avoid-low-level-calls\n (bool methodExists,) = token.staticcall(abi.encodeWithSelector(\n ERC20Token(token).balanceOf.selector,\n account\n ));\n\n if (methodExists) {\n result = ERC20Token(token).balanceOf(account);\n }\n }\n\n return result;\n }\n}\n" + }, + "src/gateway/mocks/GatewayRecipientMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.6.12;\n\nimport \"../GatewayRecipient.sol\";\n\n\n/**\n * @title Gateway recipient mock\n *\n * @dev Used in `GatewayRecipient` contract tests\n *\n * @author Stanisław Głogowski \n */\ncontract GatewayRecipientMock is GatewayRecipient {\n // events\n\n event Context(\n address account,\n address sender,\n bytes data\n );\n\n /**\n * @dev Public constructor\n * @param gateway_ `Gateway` contract address\n */\n constructor(\n address gateway_\n )\n public\n {\n _initializeGatewayRecipient(gateway_);\n }\n\n function emitContext()\n external\n {\n emit Context(\n _getContextAccount(),\n _getContextSender(),\n _getContextData()\n );\n }\n}\n" + } + }, + "settings": { + "evmVersion": "istanbul", + "metadata": { + "bytecodeHash": "none", + "useLiteralContent": true + }, + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + } + } +} \ No newline at end of file diff --git a/deployments/scroll/solcInputs/893c7c8579088197a1acbd2718e7b759.json b/deployments/scroll/solcInputs/893c7c8579088197a1acbd2718e7b759.json new file mode 100644 index 00000000..28092e6e --- /dev/null +++ b/deployments/scroll/solcInputs/893c7c8579088197a1acbd2718e7b759.json @@ -0,0 +1,97 @@ +{ + "language": "Solidity", + "sources": { + "src/bridges/facets/StargateFacet.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.4;\r\n\r\nimport {IStargateRouter} from \"../interfaces/IStargateRouter.sol\";\r\nimport {IStargateReceiver} from \"../interfaces/IStargateReceiver.sol\";\r\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport {ReentrancyGuard} from \"../../common/helpers/DiamondReentrancyGuard.sol\";\r\nimport {CannotBridgeToSameNetwork, InvalidAmount, InvalidConfig} from \"../errors/GenericErrors.sol\";\r\nimport {SenderNotStargateRouter, NoMsgValueForCrossChainMessage, StargateRouterAddressZero, InvalidSourcePoolId, InvalidDestinationPoolId} from \"../errors/StargateErrors.sol\";\r\nimport {LibDiamond} from \"../libs/LibDiamond.sol\";\r\n\r\n/// @title StargateFacet\r\n/// @author Luke Wickens \r\n/// @notice Stargate/LayerZero intergration for bridging tokens\r\n\r\ncontract StargateFacet is IStargateReceiver, ReentrancyGuard {\r\n using SafeERC20 for IERC20;\r\n\r\n //////////////////////////////////////////////////////////////\r\n /////////////////////////// Events ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n event SGInitialized(address stargate, uint16 chainId);\r\n event SGTransferStarted(\r\n string bridgeUsed,\r\n address fromToken,\r\n address toToken,\r\n address from,\r\n address to,\r\n uint256 amount,\r\n uint16 chainIdTo\r\n );\r\n event SGReceivedOnDestination(address token, uint256 amount);\r\n event SGUpdatedRouter(address newAddress);\r\n event SGUpdatedSlippageTolerance(uint256 newSlippage);\r\n event SGAddedPool(uint16 chainId, address token, uint16 poolId);\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Storage ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n bytes32 internal constant NAMESPACE =\r\n keccak256(\"io.etherspot.facets.stargate\");\r\n struct Storage {\r\n address stargateRouter;\r\n uint16 chainId;\r\n uint256 dstGas;\r\n uint256 slippage;\r\n mapping(uint16 => mapping(address => uint16)) poolIds;\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Structs ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n struct StargateData {\r\n uint256 qty;\r\n address fromToken;\r\n address toToken;\r\n uint16 dstChainId;\r\n address to;\r\n address destStargateComposed;\r\n }\r\n\r\n /// @notice initializes state variables for the Stargate facet\r\n /// @param _stargateRouter - address of the Stargate router contract\r\n /// @param _chainId - current chain id\r\n function sgInitialize(address _stargateRouter, uint16 _chainId) external {\r\n if (_stargateRouter == address(0)) revert InvalidConfig();\r\n LibDiamond.enforceIsContractOwner();\r\n Storage storage s = getStorage();\r\n s.stargateRouter = address(_stargateRouter);\r\n s.chainId = _chainId;\r\n s.slippage = 50; // equates to 0.5%\r\n // Adding pre-existing pools => USDC: 1, USDT: 2, BUSD: 5\r\n sgAddPool(1, 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, 1);\r\n sgAddPool(1, 0xdAC17F958D2ee523a2206206994597C13D831ec7, 2);\r\n sgAddPool(2, 0x55d398326f99059fF775485246999027B3197955, 2);\r\n sgAddPool(2, 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56, 5);\r\n sgAddPool(6, 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E, 1);\r\n sgAddPool(6, 0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7, 2);\r\n sgAddPool(9, 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174, 1);\r\n sgAddPool(9, 0xc2132D05D31c914a87C6611C10748AEb04B58e8F, 2);\r\n sgAddPool(10, 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8, 1);\r\n sgAddPool(10, 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9, 2);\r\n sgAddPool(11, 0x7F5c764cBc14f9669B88837ca1490cCa17c31607, 1);\r\n sgAddPool(12, 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75, 1);\r\n emit SGInitialized(_stargateRouter, _chainId);\r\n }\r\n\r\n /// @notice initializes state variables for the stargate facet\r\n /// @param _sgData - struct containing information required to execute bridge\r\n function sgBridgeTokens(StargateData memory _sgData)\r\n external\r\n payable\r\n nonReentrant\r\n {\r\n // if (msg.value <= 0) revert NoMsgValueForCrossChainMessage();\r\n if (_sgData.qty <= 0) revert InvalidAmount();\r\n if (\r\n _sgData.fromToken == address(0) ||\r\n _sgData.toToken == address(0) ||\r\n _sgData.to == address(0) ||\r\n _sgData.destStargateComposed == address(0)\r\n ) revert InvalidConfig();\r\n\r\n // access storage\r\n Storage storage s = getStorage();\r\n\r\n // check pool ids are valid\r\n uint16 srcPoolId = sgRetrievePoolId(s.chainId, _sgData.fromToken);\r\n if (srcPoolId == 0) revert InvalidSourcePoolId();\r\n uint16 dstPoolId = sgRetrievePoolId(\r\n _sgData.dstChainId,\r\n _sgData.toToken\r\n );\r\n\r\n // calculate cross chain fees\r\n uint256 fees = sgCalculateFees(\r\n _sgData.dstChainId,\r\n _sgData.to,\r\n s.stargateRouter\r\n );\r\n\r\n // calculate slippage\r\n uint256 minAmountOut = sgMinAmountOut(_sgData.qty);\r\n\r\n // encode sgReceive implemented\r\n bytes memory destination = abi.encodePacked(\r\n _sgData.destStargateComposed\r\n );\r\n\r\n // encode payload data to send to destination contract, which it will handle with sgReceive()\r\n bytes memory payload = abi.encode(_sgData.to);\r\n\r\n // this contract calls stargate swap()\r\n IERC20(_sgData.fromToken).safeTransferFrom(\r\n msg.sender,\r\n address(this),\r\n _sgData.qty\r\n );\r\n\r\n IERC20(_sgData.fromToken).safeApprove(\r\n address(s.stargateRouter),\r\n _sgData.qty\r\n );\r\n\r\n // Stargate's Router.swap() function sends the tokens to the destination chain.\r\n IStargateRouter(s.stargateRouter).swap{value: fees}(\r\n _sgData.dstChainId, // the destination chain id\r\n srcPoolId, // the source Stargate poolId\r\n dstPoolId, // the destination Stargate poolId\r\n payable(msg.sender), // refund adddress. if msg.sender pays too much gas, return extra eth\r\n _sgData.qty, // total tokens to send to destination chain\r\n minAmountOut, // min amount allowed out\r\n IStargateRouter.lzTxObj(200000, 0, \"0x\"), // default lzTxObj\r\n destination, // destination address, the sgReceive() implementer\r\n payload // bytes payload\r\n );\r\n\r\n emit SGTransferStarted(\r\n \"stargate\",\r\n _sgData.fromToken,\r\n _sgData.toToken,\r\n msg.sender,\r\n _sgData.to,\r\n _sgData.qty,\r\n _sgData.dstChainId\r\n );\r\n }\r\n\r\n /// @notice required to receive tokens on destination chain\r\n /// @param _chainId The remote chainId sending the tokens\r\n /// @param _srcAddress The remote Bridge address\r\n /// @param _nonce The message ordering nonce\r\n /// @param _token The token contract on the local chain\r\n /// @param amountLD The qty of local _token contract tokens\r\n /// @param _payload The bytes containing the toAddress\r\n function sgReceive(\r\n uint16 _chainId,\r\n bytes memory _srcAddress,\r\n uint256 _nonce,\r\n address _token,\r\n uint256 amountLD,\r\n bytes memory _payload\r\n ) external override {\r\n Storage storage s = getStorage();\r\n if (msg.sender != address(s.stargateRouter))\r\n revert SenderNotStargateRouter();\r\n\r\n address _toAddr = abi.decode(_payload, (address));\r\n IERC20(_token).transfer(_toAddr, amountLD);\r\n emit SGReceivedOnDestination(_token, amountLD);\r\n }\r\n\r\n /// @notice Calculates cross chain fee\r\n /// @param _destChain Destination chain id\r\n /// @param _receiver Receiver on destination chain\r\n /// @param _router Address of stargate router\r\n function sgCalculateFees(\r\n uint16 _destChain,\r\n address _receiver,\r\n address _router\r\n ) public view returns (uint256) {\r\n (uint256 nativeFee, ) = IStargateRouter(_router).quoteLayerZeroFee(\r\n _destChain, // destination chain id\r\n 1, // 1 = swap\r\n abi.encodePacked(_receiver), // receiver on destination chain\r\n \"0x\", // payload, using abi.encode()\r\n IStargateRouter.lzTxObj(200000, 0, \"0x\")\r\n );\r\n return nativeFee;\r\n }\r\n\r\n /// @notice Calculates the minimum amount out using slippage tolerance\r\n /// @param _amount Transfer amount\r\n function sgMinAmountOut(uint256 _amount) public view returns (uint256) {\r\n Storage storage s = getStorage();\r\n // equates to 0.5% slippage\r\n return (_amount * (10000 - s.slippage)) / (10000);\r\n }\r\n\r\n /// @notice Updates stargate router address for deployed chain\r\n /// @param _newAddress Address of the new router\r\n function sgUpdateRouter(address _newAddress) external {\r\n LibDiamond.enforceIsContractOwner();\r\n if (_newAddress == address(0)) revert StargateRouterAddressZero();\r\n Storage storage s = getStorage();\r\n s.stargateRouter = address(_newAddress);\r\n emit SGUpdatedRouter(_newAddress);\r\n }\r\n\r\n /// @notice Updates slippage tolerance amount\r\n /// @param _newSlippage New slippage amount\r\n function sgUpdateSlippageTolerance(uint256 _newSlippage) external {\r\n LibDiamond.enforceIsContractOwner();\r\n Storage storage s = getStorage();\r\n s.slippage = _newSlippage;\r\n emit SGUpdatedSlippageTolerance(_newSlippage);\r\n }\r\n\r\n /// @notice Adds a new pool for a specific token and chain\r\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\r\n /// @param _token Address of token\r\n /// @param _poolId Pool id (check stargate pool ids docs)\r\n function sgAddPool(\r\n uint16 _chainId,\r\n address _token,\r\n uint16 _poolId\r\n ) public {\r\n LibDiamond.enforceIsContractOwner();\r\n Storage storage s = getStorage();\r\n s.poolIds[_chainId][_token] = _poolId;\r\n emit SGAddedPool(_chainId, _token, _poolId);\r\n }\r\n\r\n /// @notice Checks for a valid token pool on specific chain\r\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\r\n /// @param _token Address of token\r\n /// @param _poolId Pool id (check stargate pool ids docs)\r\n function sgCheckPoolId(\r\n uint16 _chainId,\r\n address _token,\r\n uint16 _poolId\r\n ) external view returns (bool) {\r\n Storage storage s = getStorage();\r\n return s.poolIds[_chainId][_token] == _poolId ? true : false;\r\n }\r\n\r\n /// @notice Retrieves pool id for a token on a specified chain\r\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\r\n /// @param _token Address of token\r\n function sgRetrievePoolId(uint16 _chainId, address _token)\r\n public\r\n view\r\n returns (uint16)\r\n {\r\n Storage storage s = getStorage();\r\n return s.poolIds[_chainId][_token];\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////// Private Functions /////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n /// @dev fetch local storage\r\n function getStorage() private pure returns (Storage storage s) {\r\n bytes32 namespace = NAMESPACE;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n s.slot := namespace\r\n }\r\n }\r\n}\r\n" + }, + "src/bridges/interfaces/IStargateRouter.sol": { + "content": "// SPDX-License-Identifier:MIT\r\n\r\npragma solidity 0.8.4;\r\npragma abicoder v2;\r\n\r\ninterface IStargateRouter {\r\n struct lzTxObj {\r\n uint256 dstGasForCall;\r\n uint256 dstNativeAmount;\r\n bytes dstNativeAddr;\r\n }\r\n\r\n function addLiquidity(\r\n uint256 _poolId,\r\n uint256 _amountLD,\r\n address _to\r\n ) external;\r\n\r\n function swap(\r\n uint16 _dstChainId,\r\n uint256 _srcPoolId,\r\n uint256 _dstPoolId,\r\n address payable _refundAddress,\r\n uint256 _amountLD,\r\n uint256 _minAmountLD,\r\n lzTxObj memory _lzTxParams,\r\n bytes calldata _to,\r\n bytes calldata _payload\r\n ) external payable;\r\n\r\n function redeemRemote(\r\n uint16 _dstChainId,\r\n uint256 _srcPoolId,\r\n uint256 _dstPoolId,\r\n address payable _refundAddress,\r\n uint256 _amountLP,\r\n uint256 _minAmountLD,\r\n bytes calldata _to,\r\n lzTxObj memory _lzTxParams\r\n ) external payable;\r\n\r\n function instantRedeemLocal(\r\n uint16 _srcPoolId,\r\n uint256 _amountLP,\r\n address _to\r\n ) external returns (uint256);\r\n\r\n function redeemLocal(\r\n uint16 _dstChainId,\r\n uint256 _srcPoolId,\r\n uint256 _dstPoolId,\r\n address payable _refundAddress,\r\n uint256 _amountLP,\r\n bytes calldata _to,\r\n lzTxObj memory _lzTxParams\r\n ) external payable;\r\n\r\n function sendCredits(\r\n uint16 _dstChainId,\r\n uint256 _srcPoolId,\r\n uint256 _dstPoolId,\r\n address payable _refundAddress\r\n ) external payable;\r\n\r\n function quoteLayerZeroFee(\r\n uint16 _dstChainId,\r\n uint8 _functionType,\r\n bytes calldata _toAddress,\r\n bytes calldata _transferAndCallPayload,\r\n lzTxObj memory _lzTxParams\r\n ) external view returns (uint256, uint256);\r\n}\r\n" + }, + "src/bridges/interfaces/IStargateReceiver.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity 0.8.4;\r\n\r\ninterface IStargateReceiver {\r\n function sgReceive(\r\n uint16 _srcChainId, // the remote chainId sending the tokens\r\n bytes memory _srcAddress, // the remote Bridge address\r\n uint256 _nonce,\r\n address _token, // the token contract on the local chain\r\n uint256 amountLD, // the qty of local _token contract tokens\r\n bytes memory payload\r\n ) external;\r\n}\r\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "src/common/helpers/DiamondReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\r\npragma solidity 0.8.4;\r\n\r\n/// @title Reentrancy Guard\r\n/// @notice Abstract contract to provide protection against reentrancy\r\nabstract contract ReentrancyGuard {\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Storage ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n bytes32 private constant NAMESPACE =\r\n keccak256(\"io.etherspot.helpers.reentrancyguard\");\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Structs ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n struct ReentrancyStorage {\r\n uint256 status;\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Errors ////////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n error ReentrancyError();\r\n\r\n //////////////////////////////////////////////////////////////\r\n ///////////////////////// Constants //////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n uint256 private constant _NOT_ENTERED = 0;\r\n uint256 private constant _ENTERED = 1;\r\n\r\n //////////////////////////////////////////////////////////////\r\n ///////////////////////// Modifiers ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n modifier nonReentrant() {\r\n ReentrancyStorage storage s = reentrancyStorage();\r\n if (s.status == _ENTERED) revert ReentrancyError();\r\n s.status = _ENTERED;\r\n _;\r\n s.status = _NOT_ENTERED;\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////// Private Functions /////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n /// @dev fetch local storage\r\n function reentrancyStorage()\r\n private\r\n pure\r\n returns (ReentrancyStorage storage data)\r\n {\r\n bytes32 position = NAMESPACE;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n data.slot := position\r\n }\r\n }\r\n}\r\n" + }, + "src/bridges/errors/GenericErrors.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\nerror InvalidAmount();\r\nerror TokenAddressIsZero();\r\nerror CannotBridgeToSameNetwork();\r\nerror ZeroPostSwapBalance();\r\nerror InvalidBridgeConfigLength();\r\nerror NoSwapDataProvided();\r\nerror NativeValueWithERC();\r\nerror ContractCallNotAllowed();\r\nerror NullAddrIsNotAValidSpender();\r\nerror NullAddrIsNotAnERC20Token();\r\nerror NoTransferToNullAddress();\r\nerror NativeAssetTransferFailed();\r\nerror InvalidContract();\r\nerror InvalidConfig();\r\nerror ZeroAddressProvided();\r\n" + }, + "src/bridges/errors/StargateErrors.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\nerror SenderNotStargateRouter();\r\nerror NoMsgValueForCrossChainMessage();\r\nerror StargateRouterAddressZero();\r\nerror InvalidSourcePoolId();\r\nerror InvalidDestinationPoolId();\r\n" + }, + "src/bridges/libs/LibDiamond.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.8.4 <0.9.0;\r\n\r\nimport {IDiamondCut} from \"../interfaces/IDiamondCut.sol\";\r\n\r\nlibrary LibDiamond {\r\n bytes32 internal constant DIAMOND_STORAGE_POSITION =\r\n keccak256(\"diamond.standard.diamond.storage\");\r\n\r\n struct FacetAddressAndPosition {\r\n address facetAddress;\r\n uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array\r\n }\r\n\r\n struct FacetFunctionSelectors {\r\n bytes4[] functionSelectors;\r\n uint256 facetAddressPosition; // position of facetAddress in facetAddresses array\r\n }\r\n\r\n struct DiamondStorage {\r\n // maps function selector to the facet address and\r\n // the position of the selector in the facetFunctionSelectors.selectors array\r\n mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;\r\n // maps facet addresses to function selectors\r\n mapping(address => FacetFunctionSelectors) facetFunctionSelectors;\r\n // facet addresses\r\n address[] facetAddresses;\r\n // Used to query if a contract implements an interface.\r\n // Used to implement ERC-165.\r\n mapping(bytes4 => bool) supportedInterfaces;\r\n // owner of the contract\r\n address contractOwner;\r\n }\r\n\r\n function diamondStorage()\r\n internal\r\n pure\r\n returns (DiamondStorage storage ds)\r\n {\r\n bytes32 position = DIAMOND_STORAGE_POSITION;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n ds.slot := position\r\n }\r\n }\r\n\r\n event OwnershipTransferred(\r\n address indexed previousOwner,\r\n address indexed newOwner\r\n );\r\n\r\n function setContractOwner(address _newOwner) internal {\r\n DiamondStorage storage ds = diamondStorage();\r\n address previousOwner = ds.contractOwner;\r\n ds.contractOwner = _newOwner;\r\n emit OwnershipTransferred(previousOwner, _newOwner);\r\n }\r\n\r\n function contractOwner() internal view returns (address contractOwner_) {\r\n contractOwner_ = diamondStorage().contractOwner;\r\n }\r\n\r\n function enforceIsContractOwner() internal view {\r\n require(\r\n msg.sender == diamondStorage().contractOwner,\r\n \"LibDiamond: Must be contract owner\"\r\n );\r\n }\r\n\r\n event DiamondCut(\r\n IDiamondCut.FacetCut[] _diamondCut,\r\n address _init,\r\n bytes _calldata\r\n );\r\n\r\n // Internal function version of diamondCut\r\n function diamondCut(\r\n IDiamondCut.FacetCut[] memory _diamondCut,\r\n address _init,\r\n bytes memory _calldata\r\n ) internal {\r\n for (\r\n uint256 facetIndex;\r\n facetIndex < _diamondCut.length;\r\n facetIndex++\r\n ) {\r\n IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;\r\n if (action == IDiamondCut.FacetCutAction.Add) {\r\n addFunctions(\r\n _diamondCut[facetIndex].facetAddress,\r\n _diamondCut[facetIndex].functionSelectors\r\n );\r\n } else if (action == IDiamondCut.FacetCutAction.Replace) {\r\n replaceFunctions(\r\n _diamondCut[facetIndex].facetAddress,\r\n _diamondCut[facetIndex].functionSelectors\r\n );\r\n } else if (action == IDiamondCut.FacetCutAction.Remove) {\r\n removeFunctions(\r\n _diamondCut[facetIndex].facetAddress,\r\n _diamondCut[facetIndex].functionSelectors\r\n );\r\n } else {\r\n revert(\"LibDiamondCut: Incorrect FacetCutAction\");\r\n }\r\n }\r\n emit DiamondCut(_diamondCut, _init, _calldata);\r\n initializeDiamondCut(_init, _calldata);\r\n }\r\n\r\n function addFunctions(\r\n address _facetAddress,\r\n bytes4[] memory _functionSelectors\r\n ) internal {\r\n require(\r\n _functionSelectors.length > 0,\r\n \"LibDiamondCut: No selectors in facet to cut\"\r\n );\r\n DiamondStorage storage ds = diamondStorage();\r\n require(\r\n _facetAddress != address(0),\r\n \"LibDiamondCut: Add facet can't be address(0)\"\r\n );\r\n uint96 selectorPosition = uint96(\r\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.length\r\n );\r\n // add new facet address if it does not exist\r\n if (selectorPosition == 0) {\r\n addFacet(ds, _facetAddress);\r\n }\r\n for (\r\n uint256 selectorIndex;\r\n selectorIndex < _functionSelectors.length;\r\n selectorIndex++\r\n ) {\r\n bytes4 selector = _functionSelectors[selectorIndex];\r\n address oldFacetAddress = ds\r\n .selectorToFacetAndPosition[selector]\r\n .facetAddress;\r\n require(\r\n oldFacetAddress == address(0),\r\n \"LibDiamondCut: Can't add function that already exists\"\r\n );\r\n addFunction(ds, selector, selectorPosition, _facetAddress);\r\n selectorPosition++;\r\n }\r\n }\r\n\r\n function replaceFunctions(\r\n address _facetAddress,\r\n bytes4[] memory _functionSelectors\r\n ) internal {\r\n require(\r\n _functionSelectors.length > 0,\r\n \"LibDiamondCut: No selectors in facet to cut\"\r\n );\r\n DiamondStorage storage ds = diamondStorage();\r\n require(\r\n _facetAddress != address(0),\r\n \"LibDiamondCut: Add facet can't be address(0)\"\r\n );\r\n uint96 selectorPosition = uint96(\r\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.length\r\n );\r\n // add new facet address if it does not exist\r\n if (selectorPosition == 0) {\r\n addFacet(ds, _facetAddress);\r\n }\r\n for (\r\n uint256 selectorIndex;\r\n selectorIndex < _functionSelectors.length;\r\n selectorIndex++\r\n ) {\r\n bytes4 selector = _functionSelectors[selectorIndex];\r\n address oldFacetAddress = ds\r\n .selectorToFacetAndPosition[selector]\r\n .facetAddress;\r\n require(\r\n oldFacetAddress != _facetAddress,\r\n \"LibDiamondCut: Can't replace function with same function\"\r\n );\r\n removeFunction(ds, oldFacetAddress, selector);\r\n addFunction(ds, selector, selectorPosition, _facetAddress);\r\n selectorPosition++;\r\n }\r\n }\r\n\r\n function removeFunctions(\r\n address _facetAddress,\r\n bytes4[] memory _functionSelectors\r\n ) internal {\r\n require(\r\n _functionSelectors.length > 0,\r\n \"LibDiamondCut: No selectors in facet to cut\"\r\n );\r\n DiamondStorage storage ds = diamondStorage();\r\n // if function does not exist then do nothing and return\r\n require(\r\n _facetAddress == address(0),\r\n \"LibDiamondCut: Remove facet address must be address(0)\"\r\n );\r\n for (\r\n uint256 selectorIndex;\r\n selectorIndex < _functionSelectors.length;\r\n selectorIndex++\r\n ) {\r\n bytes4 selector = _functionSelectors[selectorIndex];\r\n address oldFacetAddress = ds\r\n .selectorToFacetAndPosition[selector]\r\n .facetAddress;\r\n removeFunction(ds, oldFacetAddress, selector);\r\n }\r\n }\r\n\r\n function addFacet(DiamondStorage storage ds, address _facetAddress)\r\n internal\r\n {\r\n enforceHasContractCode(\r\n _facetAddress,\r\n \"LibDiamondCut: New facet has no code\"\r\n );\r\n ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds\r\n .facetAddresses\r\n .length;\r\n ds.facetAddresses.push(_facetAddress);\r\n }\r\n\r\n function addFunction(\r\n DiamondStorage storage ds,\r\n bytes4 _selector,\r\n uint96 _selectorPosition,\r\n address _facetAddress\r\n ) internal {\r\n ds\r\n .selectorToFacetAndPosition[_selector]\r\n .functionSelectorPosition = _selectorPosition;\r\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(\r\n _selector\r\n );\r\n ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;\r\n }\r\n\r\n function removeFunction(\r\n DiamondStorage storage ds,\r\n address _facetAddress,\r\n bytes4 _selector\r\n ) internal {\r\n require(\r\n _facetAddress != address(0),\r\n \"LibDiamondCut: Can't remove function that doesn't exist\"\r\n );\r\n // an immutable function is a function defined directly in a diamond\r\n require(\r\n _facetAddress != address(this),\r\n \"LibDiamondCut: Can't remove immutable function\"\r\n );\r\n // replace selector with last selector, then delete last selector\r\n uint256 selectorPosition = ds\r\n .selectorToFacetAndPosition[_selector]\r\n .functionSelectorPosition;\r\n uint256 lastSelectorPosition = ds\r\n .facetFunctionSelectors[_facetAddress]\r\n .functionSelectors\r\n .length - 1;\r\n // if not the same then replace _selector with lastSelector\r\n if (selectorPosition != lastSelectorPosition) {\r\n bytes4 lastSelector = ds\r\n .facetFunctionSelectors[_facetAddress]\r\n .functionSelectors[lastSelectorPosition];\r\n ds.facetFunctionSelectors[_facetAddress].functionSelectors[\r\n selectorPosition\r\n ] = lastSelector;\r\n ds\r\n .selectorToFacetAndPosition[lastSelector]\r\n .functionSelectorPosition = uint96(selectorPosition);\r\n }\r\n // delete the last selector\r\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();\r\n delete ds.selectorToFacetAndPosition[_selector];\r\n\r\n // if no more selectors for facet address then delete the facet address\r\n if (lastSelectorPosition == 0) {\r\n // replace facet address with last facet address and delete last facet address\r\n uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;\r\n uint256 facetAddressPosition = ds\r\n .facetFunctionSelectors[_facetAddress]\r\n .facetAddressPosition;\r\n if (facetAddressPosition != lastFacetAddressPosition) {\r\n address lastFacetAddress = ds.facetAddresses[\r\n lastFacetAddressPosition\r\n ];\r\n ds.facetAddresses[facetAddressPosition] = lastFacetAddress;\r\n ds\r\n .facetFunctionSelectors[lastFacetAddress]\r\n .facetAddressPosition = facetAddressPosition;\r\n }\r\n ds.facetAddresses.pop();\r\n delete ds\r\n .facetFunctionSelectors[_facetAddress]\r\n .facetAddressPosition;\r\n }\r\n }\r\n\r\n function initializeDiamondCut(address _init, bytes memory _calldata)\r\n internal\r\n {\r\n if (_init == address(0)) {\r\n require(\r\n _calldata.length == 0,\r\n \"LibDiamondCut: _init is address(0) but_calldata is not empty\"\r\n );\r\n } else {\r\n require(\r\n _calldata.length > 0,\r\n \"LibDiamondCut: _calldata is empty but _init is not address(0)\"\r\n );\r\n if (_init != address(this)) {\r\n enforceHasContractCode(\r\n _init,\r\n \"LibDiamondCut: _init address has no code\"\r\n );\r\n }\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, bytes memory error) = _init.delegatecall(_calldata);\r\n if (!success) {\r\n if (error.length > 0) {\r\n // bubble up the error\r\n revert(string(error));\r\n } else {\r\n revert(\"LibDiamondCut: _init function reverted\");\r\n }\r\n }\r\n }\r\n }\r\n\r\n function enforceHasContractCode(\r\n address _contract,\r\n string memory _errorMessage\r\n ) internal view {\r\n uint256 contractSize;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n contractSize := extcodesize(_contract)\r\n }\r\n require(contractSize > 0, _errorMessage);\r\n }\r\n}\r\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "src/bridges/interfaces/IDiamondCut.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.8.4 <0.9.0;\r\n\r\ninterface IDiamondCut {\r\n enum FacetCutAction {\r\n Add,\r\n Replace,\r\n Remove\r\n }\r\n // Add=0, Replace=1, Remove=2\r\n\r\n struct FacetCut {\r\n address facetAddress;\r\n FacetCutAction action;\r\n bytes4[] functionSelectors;\r\n }\r\n\r\n /// @notice Add/replace/remove any number of functions and optionally execute\r\n /// a function with delegatecall\r\n /// @param _diamondCut Contains the facet addresses and function selectors\r\n /// @param _init The address of the contract or facet to execute _calldata\r\n /// @param _calldata A function call, including function selector and arguments\r\n /// _calldata is executed with delegatecall on _init\r\n function diamondCut(\r\n FacetCut[] calldata _diamondCut,\r\n address _init,\r\n bytes calldata _calldata\r\n ) external;\r\n\r\n event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\r\n}\r\n" + }, + "src/bridges/libs/LibAsset.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\nimport {NullAddrIsNotAnERC20Token, NullAddrIsNotAValidSpender, NoTransferToNullAddress, InvalidAmount, NativeValueWithERC, NativeAssetTransferFailed} from \"../errors/GenericErrors.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\n\r\n/// @title LibAsset\r\n/// @author Connext \r\n/// @notice This library contains helpers for dealing with onchain transfers\r\n/// of assets, including accounting for the native asset `assetId`\r\n/// conventions and any noncompliant ERC20 transfers\r\nlibrary LibAsset {\r\n uint256 private constant MAX_INT = type(uint256).max;\r\n\r\n address internal constant NULL_ADDRESS =\r\n 0x0000000000000000000000000000000000000000; //address(0)\r\n\r\n /// @dev All native assets use the empty address for their asset id\r\n /// by convention\r\n\r\n address internal constant NATIVE_ASSETID = NULL_ADDRESS; //address(0)\r\n\r\n /// @notice Gets the balance of the inheriting contract for the given asset\r\n /// @param assetId The asset identifier to get the balance of\r\n /// @return Balance held by contracts using this library\r\n function getOwnBalance(address assetId) internal view returns (uint256) {\r\n return\r\n assetId == NATIVE_ASSETID\r\n ? address(this).balance\r\n : IERC20(assetId).balanceOf(address(this));\r\n }\r\n\r\n /// @notice Transfers ether from the inheriting contract to a given\r\n /// recipient\r\n /// @param recipient Address to send ether to\r\n /// @param amount Amount to send to given recipient\r\n function transferNativeAsset(address payable recipient, uint256 amount)\r\n private\r\n {\r\n if (recipient == NULL_ADDRESS) revert NoTransferToNullAddress();\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = recipient.call{value: amount}(\"\");\r\n if (!success) revert NativeAssetTransferFailed();\r\n }\r\n\r\n /// @notice Gives MAX approval for another address to spend tokens\r\n /// @param assetId Token address to transfer\r\n /// @param spender Address to give spend approval to\r\n /// @param amount Amount to approve for spending\r\n function maxApproveERC20(\r\n IERC20 assetId,\r\n address spender,\r\n uint256 amount\r\n ) internal {\r\n if (address(assetId) == NATIVE_ASSETID) return;\r\n if (spender == NULL_ADDRESS) revert NullAddrIsNotAValidSpender();\r\n uint256 allowance = assetId.allowance(address(this), spender);\r\n if (allowance < amount)\r\n SafeERC20.safeApprove(IERC20(assetId), spender, MAX_INT);\r\n }\r\n\r\n /// @notice Transfers tokens from the inheriting contract to a given\r\n /// recipient\r\n /// @param assetId Token address to transfer\r\n /// @param recipient Address to send token to\r\n /// @param amount Amount to send to given recipient\r\n function transferERC20(\r\n address assetId,\r\n address recipient,\r\n uint256 amount\r\n ) private {\r\n if (isNativeAsset(assetId)) revert NullAddrIsNotAnERC20Token();\r\n SafeERC20.safeTransfer(IERC20(assetId), recipient, amount);\r\n }\r\n\r\n /// @notice Transfers tokens from a sender to a given recipient\r\n /// @param assetId Token address to transfer\r\n /// @param from Address of sender/owner\r\n /// @param to Address of recipient/spender\r\n /// @param amount Amount to transfer from owner to spender\r\n function transferFromERC20(\r\n address assetId,\r\n address from,\r\n address to,\r\n uint256 amount\r\n ) internal {\r\n if (assetId == NATIVE_ASSETID) revert NullAddrIsNotAnERC20Token();\r\n if (to == NULL_ADDRESS) revert NoTransferToNullAddress();\r\n SafeERC20.safeTransferFrom(IERC20(assetId), from, to, amount);\r\n }\r\n\r\n /// @notice Deposits an asset into the contract and performs checks to avoid NativeValueWithERC\r\n /// @param tokenId Token to deposit\r\n /// @param amount Amount to deposit\r\n /// @param isNative Wether the token is native or ERC20\r\n function depositAsset(\r\n address tokenId,\r\n uint256 amount,\r\n bool isNative\r\n ) internal {\r\n if (amount == 0) revert InvalidAmount();\r\n if (isNative) {\r\n if (msg.value != amount) revert InvalidAmount();\r\n } else {\r\n if (msg.value != 0) revert NativeValueWithERC();\r\n uint256 _fromTokenBalance = LibAsset.getOwnBalance(tokenId);\r\n LibAsset.transferFromERC20(\r\n tokenId,\r\n msg.sender,\r\n address(this),\r\n amount\r\n );\r\n if (LibAsset.getOwnBalance(tokenId) - _fromTokenBalance != amount)\r\n revert InvalidAmount();\r\n }\r\n }\r\n\r\n /// @notice Overload for depositAsset(address tokenId, uint256 amount, bool isNative)\r\n /// @param tokenId Token to deposit\r\n /// @param amount Amount to deposit\r\n function depositAsset(address tokenId, uint256 amount) internal {\r\n return depositAsset(tokenId, amount, tokenId == NATIVE_ASSETID);\r\n }\r\n\r\n /// @notice Determines whether the given assetId is the native asset\r\n /// @param assetId The asset identifier to evaluate\r\n /// @return Boolean indicating if the asset is the native asset\r\n function isNativeAsset(address assetId) internal pure returns (bool) {\r\n return assetId == NATIVE_ASSETID;\r\n }\r\n\r\n /// @notice Wrapper function to transfer a given asset (native or erc20) to\r\n /// some recipient. Should handle all non-compliant return value\r\n /// tokens as well by using the SafeERC20 contract by open zeppelin.\r\n /// @param assetId Asset id for transfer (address(0) for native asset,\r\n /// token address for erc20s)\r\n /// @param recipient Address to send asset to\r\n /// @param amount Amount to send to given recipient\r\n function transferAsset(\r\n address assetId,\r\n address payable recipient,\r\n uint256 amount\r\n ) internal {\r\n (assetId == NATIVE_ASSETID)\r\n ? transferNativeAsset(recipient, amount)\r\n : transferERC20(assetId, recipient, amount);\r\n }\r\n\r\n /// @dev Checks whether the given address is a contract and contains code\r\n function isContract(address _contractAddr) internal view returns (bool) {\r\n uint256 size;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n size := extcodesize(_contractAddr)\r\n }\r\n return size > 0;\r\n }\r\n}\r\n" + }, + "src/common/helpers/BalancesHelperV2.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\n/// @title BalancesHelperV2\r\n/// @author Luke Wickens \r\n/// @notice Used to get account balances of ERC20 tokens and Wrapped Super Tokens\r\n\r\nimport {ISuperfluidToken} from \"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol\";\r\nimport {IERC20} from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\r\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\ncontract BalancesHelperV2 {\r\n using Address for address;\r\n\r\n /// @notice Custom errors to handle address(0)\r\n error AccountZeroAddress(address account, address token);\r\n error TokenZeroAddress(address account, address token);\r\n\r\n constructor() {}\r\n\r\n /// @notice Returns balances of accounts for multiple ERC20 tokens.\r\n /// @dev Error thrown if: account or token address is address(0),\r\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\r\n /// @param accounts = Array of accounts addresses\r\n /// @param tokens = Array of tokens addresses\r\n /// @return One-dimensional that's accounts.length * tokens.length long. The\r\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\r\n\r\n function getBalances(address[] calldata accounts, address[] calldata tokens)\r\n external\r\n view\r\n returns (uint256[] memory)\r\n {\r\n uint256[] memory result = new uint256[](\r\n accounts.length * tokens.length\r\n );\r\n\r\n for (uint256 i; i < accounts.length; i++) {\r\n for (uint256 j; j < tokens.length; j++) {\r\n uint256 index = j + (tokens.length * i);\r\n result[index] = _getBalance(accounts[i], tokens[j]);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /// @notice Returns balances of accounts for multiple Wrapped Super Tokens.\r\n /// @dev Error thrown if: account or token address is address(0),\r\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\r\n /// @param accounts = Array of accounts addresses\r\n /// @param tokens = Array of tokens addresses\r\n /// @return One-dimensional that's accounts.length * tokens.length long. The\r\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\r\n\r\n function getSuperfluidWrappedTokenBalances(\r\n address[] calldata accounts,\r\n address[] calldata tokens\r\n ) external view returns (int256[] memory) {\r\n int256[] memory result = new int256[](accounts.length * tokens.length);\r\n\r\n for (uint256 i; i < accounts.length; i++) {\r\n for (uint256 j; j < tokens.length; j++) {\r\n uint256 index = j + (tokens.length * i);\r\n result[index] = _getSuperfluidWrappedTokenBalance(\r\n accounts[i],\r\n tokens[j]\r\n );\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /// Private fuctions\r\n\r\n /// @notice Returns balance of account for an ERC20 token.\r\n /// @dev Error thrown if: account or token address is address(0)\r\n /// @param account = account address\r\n /// @param token = tokens address\r\n /// @return balance of account as uint256.\r\n\r\n function _getBalance(address account, address token)\r\n private\r\n view\r\n returns (uint256)\r\n {\r\n if (account == address(0)) revert AccountZeroAddress(account, token);\r\n if (token == address(0)) revert TokenZeroAddress(account, token);\r\n\r\n bytes memory returnedData = token.functionStaticCall(\r\n abi.encodeWithSelector(IERC20(token).balanceOf.selector, account)\r\n );\r\n\r\n return abi.decode(returnedData, (uint256));\r\n }\r\n\r\n /// @notice Returns real balance of a user, taking into consideration all agreements of account\r\n /// @dev Error thrown if: account or token address is address(0)\r\n /// @param account = account address\r\n /// @param token = tokens address\r\n /// @return available balance of account as int256.\r\n\r\n function _getSuperfluidWrappedTokenBalance(address account, address token)\r\n private\r\n view\r\n returns (int256)\r\n {\r\n if (account == address(0)) revert AccountZeroAddress(account, token);\r\n if (token == address(0)) revert TokenZeroAddress(account, token);\r\n\r\n bytes memory returnedData = token.functionStaticCall(\r\n abi.encodeWithSelector(\r\n ISuperfluidToken(token).realtimeBalanceOfNow.selector,\r\n account\r\n )\r\n );\r\n\r\n (int256 availableBalance, , , ) = abi.decode(\r\n returnedData,\r\n (int256, uint256, uint256, uint256)\r\n );\r\n return availableBalance;\r\n }\r\n}\r\n" + }, + "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol": { + "content": "// SPDX-License-Identifier: AGPLv3\npragma solidity >= 0.8.0;\n\nimport { ISuperAgreement } from \"./ISuperAgreement.sol\";\n\n\n/**\n * @title Superfluid token interface\n * @author Superfluid\n */\ninterface ISuperfluidToken {\n\n /**************************************************************************\n * Basic information\n *************************************************************************/\n\n /**\n * @dev Get superfluid host contract address\n */\n function getHost() external view returns(address host);\n\n /**\n * @dev Encoded liquidation type data mainly used for handling stack to deep errors\n *\n * Note:\n * - version: 1\n * - liquidationType key:\n * - 0 = reward account receives reward (PIC period)\n * - 1 = liquidator account receives reward (Pleb period)\n * - 2 = liquidator account receives reward (Pirate period/bailout)\n */\n struct LiquidationTypeData {\n uint256 version;\n uint8 liquidationType;\n }\n\n /**************************************************************************\n * Real-time balance functions\n *************************************************************************/\n\n /**\n * @dev Calculate the real balance of a user, taking in consideration all agreements of the account\n * @param account for the query\n * @param timestamp Time of balance\n * @return availableBalance Real-time balance\n * @return deposit Account deposit\n * @return owedDeposit Account owed Deposit\n */\n function realtimeBalanceOf(\n address account,\n uint256 timestamp\n )\n external view\n returns (\n int256 availableBalance,\n uint256 deposit,\n uint256 owedDeposit);\n\n /**\n * @notice Calculate the realtime balance given the current host.getNow() value\n * @dev realtimeBalanceOf with timestamp equals to block timestamp\n * @param account for the query\n * @return availableBalance Real-time balance\n * @return deposit Account deposit\n * @return owedDeposit Account owed Deposit\n */\n function realtimeBalanceOfNow(\n address account\n )\n external view\n returns (\n int256 availableBalance,\n uint256 deposit,\n uint256 owedDeposit,\n uint256 timestamp);\n\n /**\n * @notice Check if account is critical\n * @dev A critical account is when availableBalance < 0\n * @param account The account to check\n * @param timestamp The time we'd like to check if the account is critical (should use future)\n * @return isCritical Whether the account is critical\n */\n function isAccountCritical(\n address account,\n uint256 timestamp\n )\n external view\n returns(bool isCritical);\n\n /**\n * @notice Check if account is critical now (current host.getNow())\n * @dev A critical account is when availableBalance < 0\n * @param account The account to check\n * @return isCritical Whether the account is critical\n */\n function isAccountCriticalNow(\n address account\n )\n external view\n returns(bool isCritical);\n\n /**\n * @notice Check if account is solvent\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\n * @param account The account to check\n * @param timestamp The time we'd like to check if the account is solvent (should use future)\n * @return isSolvent\n */\n function isAccountSolvent(\n address account,\n uint256 timestamp\n )\n external view\n returns(bool isSolvent);\n\n /**\n * @notice Check if account is solvent now\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\n * @param account The account to check\n * @return isSolvent\n */\n function isAccountSolventNow(\n address account\n )\n external view\n returns(bool isSolvent);\n\n /**\n * @notice Get a list of agreements that is active for the account\n * @dev An active agreement is one that has state for the account\n * @param account Account to query\n * @return activeAgreements List of accounts that have non-zero states for the account\n */\n function getAccountActiveAgreements(address account)\n external view\n returns(ISuperAgreement[] memory activeAgreements);\n\n\n /**************************************************************************\n * Super Agreement hosting functions\n *************************************************************************/\n\n /**\n * @dev Create a new agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n function createAgreement(\n bytes32 id,\n bytes32[] calldata data\n )\n external;\n /**\n * @dev Agreement created event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n event AgreementCreated(\n address indexed agreementClass,\n bytes32 id,\n bytes32[] data\n );\n\n /**\n * @dev Get data of the agreement\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @return data Data of the agreement\n */\n function getAgreementData(\n address agreementClass,\n bytes32 id,\n uint dataLength\n )\n external view\n returns(bytes32[] memory data);\n\n /**\n * @dev Create a new agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n function updateAgreementData(\n bytes32 id,\n bytes32[] calldata data\n )\n external;\n /**\n * @dev Agreement updated event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n event AgreementUpdated(\n address indexed agreementClass,\n bytes32 id,\n bytes32[] data\n );\n\n /**\n * @dev Close the agreement\n * @param id Agreement ID\n */\n function terminateAgreement(\n bytes32 id,\n uint dataLength\n )\n external;\n /**\n * @dev Agreement terminated event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n */\n event AgreementTerminated(\n address indexed agreementClass,\n bytes32 id\n );\n\n /**\n * @dev Update agreement state slot\n * @param account Account to be updated\n *\n * NOTE\n * - To clear the storage out, provide zero-ed array of intended length\n */\n function updateAgreementStateSlot(\n address account,\n uint256 slotId,\n bytes32[] calldata slotData\n )\n external;\n /**\n * @dev Agreement account state updated event\n * @param agreementClass Contract address of the agreement\n * @param account Account updated\n * @param slotId slot id of the agreement state\n */\n event AgreementStateUpdated(\n address indexed agreementClass,\n address indexed account,\n uint256 slotId\n );\n\n /**\n * @dev Get data of the slot of the state of an agreement\n * @param agreementClass Contract address of the agreement\n * @param account Account to query\n * @param slotId slot id of the state\n * @param dataLength length of the state data\n */\n function getAgreementStateSlot(\n address agreementClass,\n address account,\n uint256 slotId,\n uint dataLength\n )\n external view\n returns (bytes32[] memory slotData);\n\n /**\n * @notice Settle balance from an account by the agreement\n * @dev The agreement needs to make sure that the balance delta is balanced afterwards\n * @param account Account to query.\n * @param delta Amount of balance delta to be settled\n *\n * Modifiers:\n * - onlyAgreement\n */\n function settleBalance(\n address account,\n int256 delta\n )\n external;\n\n /**\n * @dev Make liquidation payouts (v2)\n * @param id Agreement ID\n * @param liquidationTypeData Data regarding the version of the liquidation schema and the type\n * @param liquidatorAccount Address of the executor of the liquidation\n * @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount\n * @param targetAccount Account of the stream sender\n * @param rewardAmount The amount the reward recepient account will receive\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\n *\n * - If a bailout is required (bailoutAmount > 0)\n * - the actual reward (single deposit) goes to the executor,\n * - while the reward account becomes the bailout account\n * - total bailout include: bailout amount + reward amount\n * - the targetAccount will be bailed out\n * - If a bailout is not required\n * - the targetAccount will pay the rewardAmount\n * - the liquidator (reward account in PIC period) will receive the rewardAmount\n *\n * Modifiers:\n * - onlyAgreement\n */\n function makeLiquidationPayoutsV2\n (\n bytes32 id,\n bytes memory liquidationTypeData,\n address liquidatorAccount,\n bool useDefaultRewardAccount,\n address targetAccount,\n uint256 rewardAmount,\n int256 targetAccountBalanceDelta\n ) external;\n /**\n * @dev Agreement liquidation event v2 (including agent account)\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param liquidatorAccount Address of the executor of the liquidation\n * @param targetAccount Account of the stream sender\n * @param rewardAccount Account that collects the reward or bails out insolvent accounts\n * @param rewardAmount The amount the reward recipient account balance should change by\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\n * @param liquidationTypeData The encoded liquidation type data including the version (how to decode)\n *\n * NOTE:\n * Reward account rule:\n * - if the agreement is liquidated during the PIC period\n * - the rewardAccount will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount\n * - the targetAccount will pay for the rewardAmount\n * - if the agreement is liquidated after the PIC period AND the targetAccount is solvent\n * - the liquidatorAccount will get the rewardAmount (remaining deposit)\n * - the targetAccount will pay for the rewardAmount\n * - if the targetAccount is insolvent\n * - the liquidatorAccount will get the rewardAmount (single deposit)\n * - the rewardAccount will pay for both the rewardAmount and bailoutAmount\n * - the targetAccount will receive the bailoutAmount\n */\n event AgreementLiquidatedV2(\n address indexed agreementClass,\n bytes32 id,\n address indexed liquidatorAccount,\n address indexed targetAccount,\n address rewardAccount,\n uint256 rewardAmount,\n int256 targetAccountBalanceDelta,\n bytes liquidationTypeData\n );\n\n /**************************************************************************\n * Function modifiers for access control and parameter validations\n *\n * While they cannot be explicitly stated in function definitions, they are\n * listed in function definition comments instead for clarity.\n *\n * NOTE: solidity-coverage not supporting it\n *************************************************************************/\n\n /// @dev The msg.sender must be host contract\n //modifier onlyHost() virtual;\n\n /// @dev The msg.sender must be a listed agreement.\n //modifier onlyAgreement() virtual;\n\n /**************************************************************************\n * DEPRECATED\n *************************************************************************/\n\n /**\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy)\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param penaltyAccount Account of the agreement to be penalized\n * @param rewardAccount Account that collect the reward\n * @param rewardAmount Amount of liquidation reward\n *\n * NOTE:\n *\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\n */\n event AgreementLiquidated(\n address indexed agreementClass,\n bytes32 id,\n address indexed penaltyAccount,\n address indexed rewardAccount,\n uint256 rewardAmount\n );\n\n /**\n * @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy)\n * @param bailoutAccount Account that bailout the penalty account\n * @param bailoutAmount Amount of account bailout\n *\n * NOTE:\n *\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\n */\n event Bailout(\n address indexed bailoutAccount,\n uint256 bailoutAmount\n );\n\n /**\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2)\n * @param liquidatorAccount Account of the agent that performed the liquidation.\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param penaltyAccount Account of the agreement to be penalized\n * @param bondAccount Account that collect the reward or bailout accounts\n * @param rewardAmount Amount of liquidation reward\n * @param bailoutAmount Amount of liquidation bailouot\n *\n * NOTE:\n * Reward account rule:\n * - if bailout is equal to 0, then\n * - the bondAccount will get the rewardAmount,\n * - the penaltyAccount will pay for the rewardAmount.\n * - if bailout is larger than 0, then\n * - the liquidatorAccount will get the rewardAmouont,\n * - the bondAccount will pay for both the rewardAmount and bailoutAmount,\n * - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount.\n */\n event AgreementLiquidatedBy(\n address liquidatorAccount,\n address indexed agreementClass,\n bytes32 id,\n address indexed penaltyAccount,\n address indexed bondAccount,\n uint256 rewardAmount,\n uint256 bailoutAmount\n );\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\n" + }, + "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol": { + "content": "// SPDX-License-Identifier: AGPLv3\npragma solidity >= 0.8.0;\n\nimport { ISuperfluidToken } from \"./ISuperfluidToken.sol\";\n\n/**\n * @title Super agreement interface\n * @author Superfluid\n */\ninterface ISuperAgreement {\n\n /**\n * @dev Get the type of the agreement class\n */\n function agreementType() external view returns (bytes32);\n\n /**\n * @dev Calculate the real-time balance for the account of this agreement class\n * @param account Account the state belongs to\n * @param time Time used for the calculation\n * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement\n * @return deposit Account deposit amount of this agreement\n * @return owedDeposit Account owed deposit amount of this agreement\n */\n function realtimeBalanceOf(\n ISuperfluidToken token,\n address account,\n uint256 time\n )\n external\n view\n returns (\n int256 dynamicBalance,\n uint256 deposit,\n uint256 owedDeposit\n );\n\n}\n" + }, + "src/bridges/facets/CBridgeFacet.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\n/// @title CBridgeFacet\r\n/// @author Luke Wickens \r\n/// @notice cBridge intergration for bridging tokens\r\n\r\nimport {ICBridge} from \"../interfaces/ICBridge.sol\";\r\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport {ReentrancyGuard} from \"../../common/helpers/DiamondReentrancyGuard.sol\";\r\nimport {CannotBridgeToSameNetwork, InvalidAmount, InvalidConfig, TokenAddressIsZero, ZeroAddressProvided} from \"../errors/GenericErrors.sol\";\r\nimport {CBSlippageTooLow} from \"../errors/CBridgeErrors.sol\";\r\nimport {LibDiamond} from \"../libs/LibDiamond.sol\";\r\n\r\ncontract CBridgeFacet is ReentrancyGuard {\r\n using SafeERC20 for IERC20;\r\n //////////////////////////////////////////////////////////////\r\n /////////////////////////// Events ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n event CBInitialized(address cBridge, uint256 chainId);\r\n event CBTransferStarted(\r\n string bridgeUsed,\r\n address token,\r\n address from,\r\n address to,\r\n uint256 qty,\r\n uint256 chainIdTo\r\n );\r\n event CBUpdatedBridge(address newAddress);\r\n event CBUpdatedSlippageTolerance(uint256 newSlippage);\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Storage ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n bytes32 internal constant NAMESPACE =\r\n keccak256(\"io.etherspot.facets.cbridge\");\r\n struct Storage {\r\n address cbBridge;\r\n uint256 cbChainId;\r\n uint32 cbSlippage;\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////////// Structs ///////////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n struct CBridgeData {\r\n uint64 dstChainId;\r\n uint64 nonce;\r\n uint256 qty;\r\n address to;\r\n address token;\r\n }\r\n\r\n /// @notice initializes state variables for the cBridge facet\r\n /// @param _cbBridge address of the CBridge router contract\r\n function cbInitialize(address _cbBridge) external {\r\n LibDiamond.enforceIsContractOwner();\r\n if (_cbBridge == address(0)) revert ZeroAddressProvided();\r\n Storage storage s = getStorage();\r\n s.cbBridge = _cbBridge;\r\n s.cbChainId = block.chainid;\r\n s.cbSlippage = 10000; // equates to 1% - has to be > 0.5% (slippage * 1M)\r\n emit CBInitialized(_cbBridge, block.chainid);\r\n }\r\n\r\n /// @notice initiates token bridging\r\n /// @param _cbData: provides necessary data for cBridge transfer\r\n\r\n function cbBridgeTokens(CBridgeData calldata _cbData)\r\n external\r\n payable\r\n nonReentrant\r\n {\r\n if (block.chainid == _cbData.dstChainId)\r\n revert CannotBridgeToSameNetwork();\r\n if (_cbData.to == address(0)) revert ZeroAddressProvided();\r\n if (_cbData.qty <= 0) revert InvalidAmount();\r\n if (_cbData.token == address(0)) revert TokenAddressIsZero();\r\n\r\n Storage storage s = getStorage();\r\n address bridge = s.cbBridge;\r\n\r\n // this contract calls stargate swap()\r\n IERC20(_cbData.token).safeTransferFrom(\r\n msg.sender,\r\n address(this),\r\n _cbData.qty\r\n );\r\n IERC20(_cbData.token).safeApprove(address(bridge), _cbData.qty);\r\n\r\n ICBridge(bridge).send(\r\n _cbData.to,\r\n _cbData.token,\r\n _cbData.qty,\r\n _cbData.dstChainId,\r\n _cbData.nonce,\r\n s.cbSlippage\r\n );\r\n\r\n emit CBTransferStarted(\r\n \"cbridge\",\r\n _cbData.token,\r\n msg.sender,\r\n _cbData.to,\r\n _cbData.qty,\r\n _cbData.dstChainId\r\n );\r\n }\r\n\r\n function cbUpdateSlippageTolerance(uint32 _newSlippage) external {\r\n // should be > 0.5% (5000)\r\n if (_newSlippage <= 5000) revert CBSlippageTooLow();\r\n LibDiamond.enforceIsContractOwner();\r\n Storage storage s = getStorage();\r\n s.cbSlippage = _newSlippage;\r\n emit CBUpdatedSlippageTolerance(_newSlippage);\r\n }\r\n\r\n function cbUpdateBridge(address _newAddress) external {\r\n LibDiamond.enforceIsContractOwner();\r\n if (_newAddress == address(0)) revert ZeroAddressProvided();\r\n Storage storage s = getStorage();\r\n s.cbBridge = _newAddress;\r\n emit CBUpdatedBridge(_newAddress);\r\n }\r\n\r\n //////////////////////////////////////////////////////////////\r\n ////////////////////// Private Functions /////////////////////\r\n //////////////////////////////////////////////////////////////\r\n\r\n /// @dev fetch local storage\r\n function getStorage() private pure returns (Storage storage s) {\r\n bytes32 namespace = NAMESPACE;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n s.slot := namespace\r\n }\r\n }\r\n}\r\n" + }, + "src/bridges/interfaces/ICBridge.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\ninterface ICBridge {\r\n function send(\r\n address _receiver,\r\n address _token,\r\n uint256 _amount,\r\n uint64 _dstChinId,\r\n uint64 _nonce,\r\n uint32 _maxSlippage\r\n ) external;\r\n\r\n function sendNative(\r\n address _receiver,\r\n uint256 _amount,\r\n uint64 _dstChinId,\r\n uint64 _nonce,\r\n uint32 _maxSlippage\r\n ) external payable;\r\n\r\n function relay(\r\n bytes calldata _relayRequest,\r\n bytes[] calldata _sigs,\r\n address[] calldata _signers,\r\n uint256[] calldata _powers\r\n ) external;\r\n}\r\n" + }, + "src/bridges/errors/CBridgeErrors.sol": { + "content": "// SPDX-License-Identifier: MIT\r\n// solhint-disable-next-line\r\npragma solidity 0.8.4;\r\n\r\nerror CBSlippageTooLow();\r\n" + }, + "src/bridges/facets/HopFacet.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.4;\r\n\r\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport { IHopBridge } from \"../interfaces/IHopBridge.sol\";\r\nimport { LibAsset } from \"../libs/LibAsset.sol\";\r\nimport { LibDiamond } from \"../libs/LibDiamond.sol\";\r\nimport { ReentrancyGuard } from \"../../common/helpers/DiamondReentrancyGuard.sol\";\r\nimport {\r\n InvalidAmount,\r\n InvalidBridgeConfigLength,\r\n CannotBridgeToSameNetwork,\r\n NativeValueWithERC,\r\n InvalidConfig\r\n} from \"../errors/GenericErrors.sol\";\r\n\r\n/**\r\n * @title Hop Protocol Integration\r\n *\r\n * @notice Contract which provides bridging functionality through Hop Protocol\r\n *\r\n */\r\ncontract HopFacet is ReentrancyGuard {\r\n // storage\r\n\r\n bytes32 internal constant NAMESPACE = keccak256(\"io.etherspot.facets.hop\");\r\n struct Storage {\r\n uint256 chainLayerId;\r\n }\r\n\r\n // types\r\n\r\n struct HopData {\r\n address bridge;\r\n address ammWrapper;\r\n address asset;\r\n address recipient;\r\n uint256 chainId;\r\n uint256 amount;\r\n uint256 bonderFee;\r\n uint256 amountOutMin;\r\n uint256 deadline;\r\n uint256 destinationAmountOutMin;\r\n uint256 destinationDeadline;\r\n }\r\n\r\n // events\r\n\r\n /**\r\n * @dev Emitted when facet initializes\r\n * @param chainId current chain id\r\n * @param chainLayerId current chain layer id\r\n */\r\n event HopInitialized(\r\n uint256 chainId,\r\n uint256 chainLayerId\r\n );\r\n\r\n /**\r\n * @dev Emitted on token swap\r\n * @param _destination destination chain id\r\n * @param _bridge address of the bridge on chain _destination,\r\n * @param _ammWrapper address of the amm wrapper,\r\n * @param _recipient recipient\r\n * @param _asset address of the asset\r\n * @param _amount amount of assets\r\n * @param _bonderFee fee\r\n * @param _amountOutMin The minimum amount received after attempting to\r\n * swap in the destination\r\n * @param _deadline The deadline for swapping in the destination AMM market.\r\n * 0 if no * swap is intended.\r\n * @param _destinationAmountOutMin The minimum amount of tokens to receive after bridging\r\n * @param _destinationDeadline The time the transaction must be completed\r\n */\r\n event HopTokenSwap(\r\n uint256 indexed _destination,\r\n address _bridge,\r\n address _ammWrapper,\r\n address indexed _recipient,\r\n address indexed _asset,\r\n uint256 _amount,\r\n uint256 _bonderFee,\r\n uint256 _amountOutMin,\r\n uint256 _deadline,\r\n uint256 _destinationAmountOutMin,\r\n uint256 _destinationDeadline\r\n );\r\n\r\n\r\n\r\n // external functions\r\n\r\n /**\r\n * @notice Initializes local variables for the Connext facet\r\n */\r\n function initHop(uint256 _chainLayerId) external {\r\n LibDiamond.enforceIsContractOwner();\r\n\r\n Storage storage s = getStorage();\r\n s.chainLayerId = _chainLayerId;\r\n\r\n emit HopInitialized(\r\n getChainID(),\r\n _chainLayerId\r\n );\r\n }\r\n\r\n /**\r\n * @notice Bridges tokens via Hop Protocol\r\n * @param _hopData data specific to Hop Protocol\r\n */\r\n function hopTokenTransfer(\r\n HopData calldata _hopData\r\n ) external payable nonReentrant {\r\n LibAsset.depositAsset(_hopData.asset, _hopData.amount);\r\n\r\n address bridge;\r\n if (getLayerId() == 1) {\r\n bridge = _hopData.bridge;\r\n } else {\r\n bridge = _hopData.ammWrapper;\r\n }\r\n\r\n if (getChainID() == _hopData.chainId)\r\n revert CannotBridgeToSameNetwork();\r\n\r\n // Give Hop approval to bridge tokens\r\n LibAsset.maxApproveERC20(\r\n IERC20(_hopData.asset),\r\n bridge,\r\n _hopData.amount\r\n );\r\n\r\n uint256 value = LibAsset.isNativeAsset(_hopData.asset)\r\n ? _hopData.amount\r\n : 0;\r\n\r\n if (getLayerId() == 1) {\r\n // Ethereum L1\r\n IHopBridge(bridge).sendToL2{value: value}(\r\n _hopData.chainId,\r\n _hopData.recipient,\r\n _hopData.amount,\r\n _hopData.destinationAmountOutMin,\r\n _hopData.destinationDeadline,\r\n address(0),\r\n 0\r\n );\r\n } else {\r\n // L2\r\n IHopBridge(bridge).swapAndSend{value: value}(\r\n _hopData.chainId,\r\n _hopData.recipient,\r\n _hopData.amount,\r\n _hopData.bonderFee,\r\n _hopData.amountOutMin,\r\n _hopData.deadline,\r\n _hopData.destinationAmountOutMin,\r\n _hopData.destinationDeadline\r\n );\r\n }\r\n emit HopTokenSwap(\r\n _hopData.chainId,\r\n _hopData.bridge,\r\n _hopData.ammWrapper,\r\n _hopData.recipient,\r\n _hopData.asset,\r\n _hopData.amount,\r\n _hopData.bonderFee,\r\n _hopData.amountOutMin,\r\n _hopData.deadline,\r\n _hopData.destinationAmountOutMin,\r\n _hopData.destinationDeadline\r\n );\r\n }\r\n\r\n /// private Methods ///\r\n\r\n /**\r\n * @dev returns local storage\r\n */\r\n function getStorage() private pure returns (Storage storage s) {\r\n bytes32 namespace = NAMESPACE;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n s.slot := namespace\r\n }\r\n }\r\n\r\n /**\r\n * @dev returns current chain layer number\r\n * @return uint256 layer number\r\n */\r\n function getLayerId() private view returns (uint256) {\r\n return getStorage().chainLayerId;\r\n }\r\n\r\n /**\r\n * @dev fetch chain id\r\n */\r\n function getChainID() private view returns (uint256) {\r\n uint256 id;\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n id := chainid()\r\n }\r\n return id;\r\n }\r\n}\r\n" + }, + "src/bridges/interfaces/IHopBridge.sol": { + "content": "// SPDX-License-Identifier: MIT\r\npragma solidity 0.8.4;\r\n\r\ninterface IHopBridge {\r\n function sendToL2(\r\n uint256 chainId,\r\n address recipient,\r\n uint256 amount,\r\n uint256 amountOutMin,\r\n uint256 deadline,\r\n address relayer,\r\n uint256 relayerFee\r\n ) external payable;\r\n\r\n function swapAndSend(\r\n uint256 chainId,\r\n address recipient,\r\n uint256 amount,\r\n uint256 bonderFee,\r\n uint256 amountOutMin,\r\n uint256 deadline,\r\n uint256 destinationAmountOutMin,\r\n uint256 destinationDeadline\r\n ) external payable;\r\n}\r\n" + } + }, + "settings": { + "evmVersion": "istanbul", + "metadata": { + "bytecodeHash": "none", + "useLiteralContent": true + }, + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + } + } +} \ No newline at end of file diff --git a/extensions/constants.ts b/extensions/constants.ts index 8007472e..69982ac0 100644 --- a/extensions/constants.ts +++ b/extensions/constants.ts @@ -45,6 +45,7 @@ export enum NetworkNames { LocalB = "localB", LocalH = "localH", Flare = "flare", + Scroll = "scroll", } export const NETWORK_CONFIGS: { @@ -313,6 +314,12 @@ export const NETWORK_CONFIGS: { defaultGasPrice: 25, explorer: 'https://flare-explorer.flare.network/', }, + [NetworkNames.Scroll]: { + chainId: 534352, + defaultProviderUrl: 'https://rpc.scroll.io', + explorer: 'https://scrollscan.com/', + defaultGasPrice: 1, + } }; export enum ContractNames { diff --git a/package.json b/package.json index 48a0181f..2bac5cf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@etherspot/contracts", - "version": "2.0.4", + "version": "2.0.5", "description": "Etherspot Solidity contracts", "keywords": [ "ether",