From a63c9c37ebb931eb544aae6043b22d1dff24eb94 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Mon, 25 Oct 2021 17:09:42 +1100 Subject: [PATCH 1/7] Add create2 deployer (WIP). Add typechain (closes #23) --- contracts/.env.example | 30 +- contracts/.eslintignore | 4 + contracts/.eslintrc.js | 24 + contracts/.gitignore | 5 +- contracts/.npmignore | 3 + contracts/.prettierignore | 5 + contracts/.solhint.json | 7 + contracts/.solhintignore | 1 + contracts/README.md | 14 +- contracts/contracts/BLSWallet.sol | 2 +- contracts/contracts/Create2Deployer.sol | 35 + .../hubble-contracts/contracts/libs/BLS.sol | 2 +- contracts/hardhat.config.ts | 104 +- contracts/package.json | 47 +- contracts/scripts/deploy-deployer.ts | 69 + contracts/shared/helpers/Fixture.ts | 13 +- contracts/shared/helpers/TokenHelper.ts | 7 +- contracts/test/deploy-test.ts | 87 + contracts/test/tokenPayment-test.ts | 7 +- contracts/test/walletAction-test.ts | 9 +- contracts/tsconfig.json | 12 + contracts/yarn-error.log | 11866 ++++++++++++++++ contracts/yarn.lock | 4221 ++++-- 23 files changed, 15524 insertions(+), 1050 deletions(-) create mode 100644 contracts/.eslintignore create mode 100644 contracts/.eslintrc.js create mode 100644 contracts/.npmignore create mode 100644 contracts/.prettierignore create mode 100644 contracts/.solhint.json create mode 100644 contracts/.solhintignore create mode 100644 contracts/contracts/Create2Deployer.sol create mode 100644 contracts/scripts/deploy-deployer.ts create mode 100644 contracts/test/deploy-test.ts create mode 100644 contracts/tsconfig.json create mode 100644 contracts/yarn-error.log diff --git a/contracts/.env.example b/contracts/.env.example index 9d8eab23..ae4a3acd 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -1,3 +1,23 @@ +ETHERSCAN_API_KEY= + +ROPSTEN_URL= +RINKEBY_URL= +ARBITRUM_TESTNET_URL=https://rinkeby.arbitrum.io/rpc +ARBITRUM_URL=https://arb1.arbitrum.io/rpc +OPTIMISM_LOCAL_URL=http://localhost:8545 +OPTIMISM_TESETNET_URL=https://kovan.optimism.io +OPTIMISM_URL= + +# Only used for deploying the deployer contract at the same address on any evm network +DEPLOYMENT=false +DEPLOYER_MNEMONIC= +DEPLOYER_SET_INDEX=1 +DEPLOYER_ACCOUNT=0xf5F21252cEaEB40cAfa64D6367Ab902e3E371f3b, +DEPLOYER_CONTRACT_ADDRESS=0x6967b7c29E8B0823a11A5A56Dd7b3973Fd7FBc81 + +# Used for deploying contracts via the deployment contract, and testing +MAIN_MNEMONIC="test test test test test test test test test test test junk" + PRIVATE_KEY_AGG=0000000000000000000000000000000000000000000000000000000000000a99 PRIVATE_KEY_AGG_OKOV= PRIVATE_KEY_AGG_RINKARBY= @@ -7,16 +27,6 @@ PRIVATE_KEY_003=0000000000000000000000000000000000000000000000000000000000000003 PRIVATE_KEY_004=0000000000000000000000000000000000000000000000000000000000000004 PRIVATE_KEY_005=0000000000000000000000000000000000000000000000000000000000000005 - -BLS_SECRET_NUM_1= -BLS_SECRET_NUM_2= -BLS_SECRET_NUM_3= - -LOCAL_BLS_LIBRARY=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 -LOCAL_VERIFICATION_GATEWAY_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 -LOCAL_BLS_EXPANDER_ADDRESS=0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 -LOCAL_ERC20_CONTRACT_ADDRESS= - ARB1_PRECOMPILE_COST_ESTIMATOR_ADDRESS= ARB1_BLS_LIBRARY= ARB1_VERIFICATION_GATEWAY_ADDRESS= diff --git a/contracts/.eslintignore b/contracts/.eslintignore new file mode 100644 index 00000000..85f5562a --- /dev/null +++ b/contracts/.eslintignore @@ -0,0 +1,4 @@ +node_modules +artifacts +cache +coverage diff --git a/contracts/.eslintrc.js b/contracts/.eslintrc.js new file mode 100644 index 00000000..98ce1937 --- /dev/null +++ b/contracts/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + env: { + browser: false, + es2021: true, + mocha: true, + node: true, + }, + plugins: ["@typescript-eslint"], + extends: [ + "standard", + "plugin:prettier/recommended", + "plugin:node/recommended", + ], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 12, + }, + rules: { + "node/no-unsupported-features/es-syntax": [ + "error", + { ignores: ["modules"] }, + ], + }, +}; diff --git a/contracts/.gitignore b/contracts/.gitignore index 0653ef70..fb1104ce 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -2,6 +2,9 @@ .env* !.env.example node_modules +coverage +coverage.json +typechain #Hardhat files artifacts @@ -12,4 +15,4 @@ artifacts-ovm cache-ovm #editor files -.vscode \ No newline at end of file +.vscode diff --git a/contracts/.npmignore b/contracts/.npmignore new file mode 100644 index 00000000..dc037817 --- /dev/null +++ b/contracts/.npmignore @@ -0,0 +1,3 @@ +hardhat.config.ts +scripts +test diff --git a/contracts/.prettierignore b/contracts/.prettierignore new file mode 100644 index 00000000..f268596e --- /dev/null +++ b/contracts/.prettierignore @@ -0,0 +1,5 @@ +node_modules +artifacts +cache +coverage* +gasReporterOutput.json diff --git a/contracts/.solhint.json b/contracts/.solhint.json new file mode 100644 index 00000000..f3e31e8c --- /dev/null +++ b/contracts/.solhint.json @@ -0,0 +1,7 @@ +{ + "extends": "solhint:recommended", + "rules": { + "compiler-version": ["error", "^0.8.0"], + "func-visibility": ["warn", { "ignoreConstructors": true }] + } +} diff --git a/contracts/.solhintignore b/contracts/.solhintignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/contracts/.solhintignore @@ -0,0 +1 @@ +node_modules diff --git a/contracts/README.md b/contracts/README.md index 75a9fe22..844aa270 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -24,8 +24,6 @@ Note: each of these savings is proportional to the number of transactions submit - receive contract wallet address 3. Create contract wallet with existing ECDSA keypair -Note: Depending on the network being used, the address of the deployed PrecompileCostEstimator will need to be set [here](https://github.com/jzaki/bls-wallet/blob/main/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol#L42). #15 will resolve this. - ## See it in action See `extension` @@ -83,7 +81,15 @@ Proposed solution to make use of [BLS](https://github.com/thehubbleproject/hubbl - Run the aggregation server (see `./server`). - build and test contracts - `npx hardhat test` -## Optimism's L2 +Note: Depending on the network being used, the address of the deployed PrecompileCostEstimator will need to be set [here](https://github.com/jzaki/bls-wallet/blob/main/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol#L42). #15 will resolve this. + +(WIP) Deployment of the deployer contract on a network can be done with: +`DEPLOY_DEPLOYER=true yarn hardhat run scripts/deploy-deployer.ts` + +## Arbitrum + + +## Optimism's L2 (paused) - clone https://github.com/ethereum-optimism/optimism - follow instructions (using latest version of docker) - in `opt/`, run script - `docker-compose up` @@ -91,7 +97,7 @@ Proposed solution to make use of [BLS](https://github.com/thehubbleproject/hubbl - L2 - http://localhost:8545 (chainId 420) ## Deploy scripts -Specify network - `npx hardhat run scripts/<#_script.ts> --network optimism` +Specify network - `npx hardhat run scripts/<#_script.ts> --network arbitrum-testnet` # License MIT diff --git a/contracts/contracts/BLSWallet.sol b/contracts/contracts/BLSWallet.sol index 26f4b897..f445b538 100644 --- a/contracts/contracts/BLSWallet.sol +++ b/contracts/contracts/BLSWallet.sol @@ -28,7 +28,7 @@ contract BLSWallet receive() external payable {} fallback() external payable {} - function getPublicKey() external returns (uint256[4] memory) { + function getPublicKey() external view returns (uint256[4] memory) { return publicKey; } diff --git a/contracts/contracts/Create2Deployer.sol b/contracts/contracts/Create2Deployer.sol new file mode 100644 index 00000000..b82f4c76 --- /dev/null +++ b/contracts/contracts/Create2Deployer.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +contract Create2Deployer { + event Deployed(address sender, uint256 salt, address addr); + + function addressFrom( + address sender, + uint256 salt, + bytes calldata code + ) public pure returns ( + address predictedAddress + ) { + predictedAddress = address(uint160(uint(keccak256(abi.encodePacked( + bytes1(0xff), + sender, + salt, + keccak256(abi.encodePacked( + code + )) + ))))); + } + + function deploy(uint256 salt, bytes memory code) public { + address addr; + assembly { + addr := create2(0, add(code, 0x20), mload(code), salt) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + emit Deployed(msg.sender, salt, addr); + } + +} diff --git a/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol b/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol index f74b7e71..341acdef 100644 --- a/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol +++ b/contracts/contracts/lib/hubble-contracts/contracts/libs/BLS.sol @@ -41,7 +41,7 @@ library BLS { // estimator address address private constant COST_ESTIMATOR_ADDRESS = // 0x85C17E7180879a71EDAE76B43E4a85159a7eA601; // rinkarby - 0x5FbDB2315678afecb367f032d93F642f64180aa3; // local hardhat test + 0x6967b7c29E8B0823a11A5A56Dd7b3973Fd7FBc81; // local hardhat test //0x079d8077C465BD0BF0FC502aD2B846757e415661; initial function verifySingle( diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 413ac90d..fffb27f2 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -1,16 +1,17 @@ -require('dotenv').config(); -import { HardhatUserConfig, NetworkUserConfig } from "hardhat/types"; +import * as dotenv from "dotenv"; -// import '@eth-optimism/hardhat-ovm'; - -import "@nomiclabs/hardhat-ethers"; +import { HardhatUserConfig, task } from "hardhat/config"; +import "@nomiclabs/hardhat-etherscan"; import "@nomiclabs/hardhat-waffle"; +import "@typechain/hardhat"; +import "hardhat-gas-reporter"; +import "solidity-coverage"; -import { task } from "hardhat/config"; +dotenv.config(); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async (args, hre) => { +task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { @@ -18,6 +19,25 @@ task("accounts", "Prints the list of accounts", async (args, hre) => { } }); + +// Account used to deploy the deployer contract at the same address on each network +const deployerAccount = { + mnemonic: `${process.env.DEPLOYER_MNEMONIC}`, + initialIndex: Number.parseInt(process.env.DEPLOYER_SET_INDEX!), + count: 1 +}; + +// Accounts used for testing and deploying +const mainAccounts = { + mnemonic: `${process.env.MAIN_MNEMONIC}`, + count: 5 +} + +const accounts = ( + `${process.env.DEPLOYER_DEPLOYMENT}` === `true` + ? deployerAccount : mainAccounts +); + const config: HardhatUserConfig = { solidity: { compilers: [ @@ -53,66 +73,50 @@ const config: HardhatUserConfig = { networks: { hardhat: { initialBaseFeePerGas: 0, // workaround from https://github.com/sc-forks/solidity-coverage/issues/652#issuecomment-896330136 . Remove when that issue is closed. + accounts, }, gethDev: { url: `http://localhost:8545`, - accounts: [ - `0x${process.env.PRIVATE_KEY_AGG}`, - `0x${process.env.PRIVATE_KEY_002}`, - `0x${process.env.PRIVATE_KEY_003}`, - `0x${process.env.PRIVATE_KEY_004}`, - `0x${process.env.PRIVATE_KEY_005}` - ], + accounts, gasPrice: 0 }, - arb1: { //chainId: 42161 - url: `https://arb1.arbitrum.io/rpc`, - accounts: [ - `0x${process.env.PRIVATE_KEY_AGG_ARB1}`, - `0x${process.env.PRIVATE_KEY_002}`, - `0x${process.env.PRIVATE_KEY_003}`, - `0x${process.env.PRIVATE_KEY_004}`, - `0x${process.env.PRIVATE_KEY_005}` - ], - gasPrice: 700000000, + ropsten: { + url: process.env.ROPSTEN_URL || "", + accounts }, - rinkarby: { //chainId: 421611 - url: `https://rinkeby.arbitrum.io/rpc`, - accounts: [ - `0x${process.env.PRIVATE_KEY_AGG_RINKARBY}`, - `0x${process.env.PRIVATE_KEY_002}`, - `0x${process.env.PRIVATE_KEY_003}`, - `0x${process.env.PRIVATE_KEY_004}`, - `0x${process.env.PRIVATE_KEY_005}` - ], + arbitrum_testnet: { //chainId: 421611 + url: process.env.ARBITRUM_TESTNET_URL, + accounts, gasPrice: 1408857682, //287938372, }, - // optimistic: { - // url: `http://localhost:8545`, - // accounts: { - // mnemonic: "test test test test test test test test test test test junk", - // initialIndex: 2, // After optimism deployer, sequencer - // count: 5 - // }, + arbitrum: { //chainId: 42161 + url: process.env.ARBITRUM_URL, + accounts, + gasPrice: 700000000, + }, + // optimistic_local: { + // url: process.env.OPTIMISM_LOCAL_URL, + // accounts, // gasPrice: 0,//15000000, // ovm: true // }, - // optimisticKovan: { - // url: 'https://kovan.optimism.io', - // accounts: [ - // `0x${process.env.PRIVATE_KEY_AGG_OKOV}`, - // `0x${process.env.PRIVATE_KEY_002}`, - // `0x${process.env.PRIVATE_KEY_003}`, - // `0x${process.env.PRIVATE_KEY_004}`, - // `0x${process.env.PRIVATE_KEY_005}` - // ], + // optimistic_testnet: { + // url: process.env.OPTIMISM_TESTNET_URL, + // accounts, // gasPrice: 15000000, // ovm: true // This sets the network as using the ovm and ensure contract will be compiled against that. // } }, + gasReporter: { + enabled: process.env.REPORT_GAS !== undefined, + currency: "USD", + }, + etherscan: { + apiKey: process.env.ETHERSCAN_API_KEY, + }, mocha: { timeout: 120000 - } + } }; export default config; diff --git a/contracts/package.json b/contracts/package.json index 3ed3685d..9b19c944 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -10,20 +10,37 @@ "@openzeppelin/contracts": "^4.3.2" }, "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "@nomiclabs/hardhat-waffle": "^2.0.1", - "@openzeppelin/test-helpers": "^0.5.12", - "@types/chai": "^4.2.15", - "@types/mocha": "^8.2.1", - "@types/node": "^14.14.35", - "axios": "^0.21.1", - "chai": "^4.3.4", - "dotenv": "^8.2.0", - "ethereum-waffle": "^3.3.0", - "ethers": "^5.0.32", - "hardhat": "^2.6.4", - "mcl-wasm": "^0.7.4", - "ts-node": "^9.1.1", - "typescript": "^4.2.3" + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-etherscan": "^2.1.3", + "@nomiclabs/hardhat-waffle": "^2.0.0", + "@openzeppelin/test-helpers": "^0.5.15", + "@typechain/ethers-v5": "^7.0.1", + "@typechain/hardhat": "^2.3.0", + "@types/chai": "^4.2.21", + "@types/mocha": "^9.0.0", + "@types/node": "^16.4.13", + "@typescript-eslint/eslint-plugin": "^4.29.1", + "@typescript-eslint/parser": "^4.29.1", + "chai": "^4.2.0", + "dotenv": "^10.0.0", + "eslint": "^7.29.0", + "eslint-config-prettier": "^8.3.0", + "eslint-config-standard": "^16.0.3", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-promise": "^5.1.0", + "ethereum-waffle": "^3.0.0", + "ethers": "^5.0.0", + "hardhat": "^2.6.7", + "hardhat-gas-reporter": "^1.0.4", + "mcl-wasm": "^0.8.0", + "prettier": "^2.3.2", + "prettier-plugin-solidity": "^1.0.0-beta.13", + "solhint": "^3.3.6", + "solidity-coverage": "^0.7.16", + "ts-node": "^10.1.0", + "typechain": "^5.1.2", + "typescript": "^4.3.5" } } diff --git a/contracts/scripts/deploy-deployer.ts b/contracts/scripts/deploy-deployer.ts new file mode 100644 index 00000000..58bfb061 --- /dev/null +++ b/contracts/scripts/deploy-deployer.ts @@ -0,0 +1,69 @@ +import * as dotenv from "dotenv"; + +// We require the Hardhat Runtime Environment explicitly here. This is optional +// but useful for running the script in a standalone fashion through `node