diff --git a/.env.example b/.env.example index 2419008..79f0525 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,6 @@ ETHERSCAN_API_KEY= POLYGON_MUMBAI_API_KEY= # WALLET -PRIVATE_KEY= DEV_MNEMONIC= # LOCAL FORK @@ -14,4 +13,4 @@ RINKEBY_URL= GOERLI_URL= ROPSTEN_URL= MUMBAI_URL= -REPORT_GAS= \ No newline at end of file +REPORT_GAS= diff --git a/.eslintrc.js b/.eslintrc.js index 16bdcbb..f865a74 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,12 @@ module.exports = { - env: {node: true}, - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], + env: { node: true }, + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "prettier", "mocha"], + rules: { + "prettier/prettier": "error", + "mocha/no-skipped-tests": "error", + "mocha/no-exclusive-tests": "error", + }, root: true, }; diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 6f18170..7be73d1 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -6,38 +6,20 @@ on: pull_request: branches: ['main'] jobs: - build: - + monolith: runs-on: ubuntu-latest - - # strategy: - # matrix: - # node-version: [12.x, 14.x, 16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - + env: + DEV_MNEMONIC: ${{ secrets.DEV_MNEMONIC }} + MUMBAI_URL: ${{secrets.MUMBAI_URL}} + FORK_URL: ${{ secrets.FORK_URL }} steps: - - uses: actions/checkout@v2 - - uses: borales/actions-yarn@v3.0.0 - name: install - with: - cmd: install - - uses: borales/actions-yarn@v3.0.0 - name: compile - with: - cmd: hardhat compile - - uses: borales/actions-yarn@v3.0.0 - name: tests - with: - cmd: hardhat test --network hardhat - env: - FORK_URL: ${{ secrets.FORK_URL }} - DEV_MNEMONIC: ${{ secrets.DEV_MNEMONIC }} - - - uses: borales/actions-yarn@v3.0.0 - name: deploy - with: - cmd: rimraf deployments/mumbai/AludelFactory.json && yarn hardhat deploy --network mumbai --write true --tags templates - env: - DEV_MNEMONIC: ${{ secrets.DEV_MNEMONIC }} - MUMBAI_URL: ${{secrets.MUMBAI_URL}} - DEPLOY_CHAIN: mumbai + - uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: '16' + - run: yarn install --dev + - run: yarn compile + - run: yarn lint-sol + - run: yarn lint-ts + - run: yarn test-ts + - run: rm deployments/mumbai/AludelFactory.json && yarn hardhat deploy --network mumbai --tags templates diff --git a/.solhint.json b/.solhint.json index f3e31e8..8aa553b 100644 --- a/.solhint.json +++ b/.solhint.json @@ -2,6 +2,7 @@ "extends": "solhint:recommended", "rules": { "compiler-version": ["error", "^0.8.0"], - "func-visibility": ["warn", { "ignoreConstructors": true }] + "func-visibility": ["error", { "ignoreConstructors": true }], + "state-visibility": ["error"] } } diff --git a/deploy/AludelFactory.ts b/deploy/AludelFactory.ts index ab7f83f..e7d4ca1 100644 --- a/deploy/AludelFactory.ts +++ b/deploy/AludelFactory.ts @@ -20,6 +20,6 @@ const deployFunc = async function ({ contract: "AludelFactory", deterministicDeployment: false, }); -} +}; deployFunc.tags = ["AludelFactory"]; export default deployFunc; diff --git a/deploy/PowerSwitchFactory.ts b/deploy/PowerSwitchFactory.ts index 9b05c62..60f3c3f 100644 --- a/deploy/PowerSwitchFactory.ts +++ b/deploy/PowerSwitchFactory.ts @@ -16,6 +16,6 @@ const deployFunc = async function ({ contract: "PowerSwitchFactory", deterministicDeployment: false, }); -} +}; deployFunc.tags = ["PowerSwitchFactory"]; export default deployFunc; diff --git a/deploy/RewardPoolFactory.ts b/deploy/RewardPoolFactory.ts index 08dd822..a7a2fb3 100644 --- a/deploy/RewardPoolFactory.ts +++ b/deploy/RewardPoolFactory.ts @@ -16,7 +16,7 @@ const deployFunc = async function ({ contract: "RewardPoolFactory", deterministicDeployment: false, }); -} +}; deployFunc.tags = ["RewardPoolFactory"]; export default deployFunc; diff --git a/deploy/Templates.ts b/deploy/Templates.ts index 5cfa20b..dfac41a 100644 --- a/deploy/Templates.ts +++ b/deploy/Templates.ts @@ -2,12 +2,14 @@ import "@nomiclabs/hardhat-ethers"; import "hardhat-deploy"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -const deployFunc = function ({ - deployments, -}: HardhatRuntimeEnvironment) { +const deployFunc = function ({ deployments }: HardhatRuntimeEnvironment) { deployments.log("running virtual task to configure all templates"); -} +}; deployFunc.tags = ["templates"]; -deployFunc.dependencies = ["GeyserV2Template", "AludelV2Template", "AludelV1Template"]; +deployFunc.dependencies = [ + "GeyserV2Template", + "AludelV2Template", + "AludelV1Template", +]; export default deployFunc; diff --git a/hardhat.config.ts b/hardhat.config.ts index a013d9c..8eb536f 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,28 +1,27 @@ import * as dotenv from "dotenv"; import "@nomiclabs/hardhat-waffle"; -import { HardhatUserConfig, task } from "hardhat/config"; +import { HardhatUserConfig } from "hardhat/config"; import "@nomiclabs/hardhat-etherscan"; import "@typechain/hardhat"; import "hardhat-gas-reporter"; import "solidity-coverage"; -import "hardhat-deploy" +import "hardhat-deploy"; -import "hardhat-contract-sizer" -import "hardhat-storage-layout" -import "./tasks/aludel" +import "hardhat-contract-sizer"; +import "hardhat-storage-layout"; +import "./tasks/aludel"; dotenv.config(); // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more -const forkingUrl = process.env.FORK_URL || '' -const mnemonic = process.env.DEV_MNEMONIC || '' -const privateKey = process.env.PRIVATE_KEY || '' -const rinkebyUrl = process.env.RINKEBY_URL || '' -const goerliUrl = process.env.GOERLI_URL || '' -const infuraKey = process.env.ETHERSCAN_API_KEY || '' -const polyscanApiKey = process.env.POLYGON_MUMBAI_API_KEY || '' +const forkingUrl = process.env.FORK_URL || ""; +const mnemonic = process.env.DEV_MNEMONIC || ""; +const rinkebyUrl = process.env.RINKEBY_URL || ""; +const goerliUrl = process.env.GOERLI_URL || ""; +const infuraKey = process.env.ETHERSCAN_API_KEY || ""; +const polyscanApiKey = process.env.POLYGON_MUMBAI_API_KEY || ""; const config: HardhatUserConfig = { solidity: { @@ -30,68 +29,68 @@ const config: HardhatUserConfig = { settings: { outputSelection: { "*": { - "*": ["storageLayout"], + "*": ["storageLayout"], }, }, - } + }, }, networks: { hardhat: { forking: { url: forkingUrl, - blockNumber: 14169000 + blockNumber: 14169000, }, accounts: { - mnemonic - } + mnemonic, + }, }, ropsten: { url: process.env.ROPSTEN_URL || "", accounts: { - mnemonic + mnemonic, }, live: true, saveDeployments: true, - tags: ['staging'] + tags: ["staging"], }, goerli: { url: goerliUrl, accounts: { - mnemonic + mnemonic, }, live: true, saveDeployments: true, - tags: ['staging'] + tags: ["staging"], }, rinkeby: { url: rinkebyUrl, accounts: { - mnemonic + mnemonic, }, live: true, saveDeployments: true, - tags: ['staging'] + tags: ["staging"], }, mumbai: { - url: process.env.MUMBAI_URL || '', + url: process.env.MUMBAI_URL || "", accounts: { - mnemonic + mnemonic, }, - saveDeployments: true + saveDeployments: true, }, avalanche: { - url: 'https://api.avax.network/ext/bc/C/rpc', + url: "https://api.avax.network/ext/bc/C/rpc", chainId: 43114, accounts: { - mnemonic - } + mnemonic, + }, }, localhost: { - url: 'http://127.0.0.1:8545', + url: "http://127.0.0.1:8545", accounts: { - mnemonic + mnemonic, }, - } + }, }, gasReporter: { enabled: process.env.REPORT_GAS ? true : false, @@ -99,7 +98,7 @@ const config: HardhatUserConfig = { }, namedAccounts: { deployer: { - default: 0 + default: 0, }, dev: { // Default to 1 @@ -112,10 +111,10 @@ const config: HardhatUserConfig = { apiKey: { goerli: infuraKey, rinkeby: infuraKey, - polygonMumbai: polyscanApiKey - } + polygonMumbai: polyscanApiKey, + }, }, - + paths: { artifacts: "./out", sources: "./src/contracts", diff --git a/package.json b/package.json index cbbc510..ccf908d 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,12 @@ "repository": "git@github.com:alchemistcoin/crucible-collection.git", "author": "Ignacio Tirabasso ", "license": "MIT", + "scripts": { + "lint-sol": "git ls-files |grep '\\.sol$' |xargs ./node_modules/.bin/solhint", + "lint-ts": "git ls-files |grep '\\.[tj]s$'| xargs ./node_modules/.bin/eslint", + "compile": "hardhat compile", + "test-ts": "hardhat --network hardhat test" + }, "devDependencies": { "@nomiclabs/hardhat-ethers": "2.0.6", "@nomiclabs/hardhat-etherscan": "3.1.0", @@ -60,7 +66,7 @@ "ds-math": "https://github.com/dapphub/ds-math", "ds-test": "https://github.com/dapphub/ds-test", "ds-token": "https://github.com/dapphub/ds-token", - "forge-std": "https://github.com/foundry-rs/forge-std", - "rimraf": "^3.0.2" + "eslint-plugin-mocha": "^10.1.0", + "forge-std": "https://github.com/foundry-rs/forge-std" } } diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 6ec230b..8c019b7 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -1,45 +1,43 @@ import { ethers, run } from "hardhat"; -const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); async function main() { - - const signer = (await ethers.getSigners())[0] - console.log('Signer:', signer.address) + const signer = (await ethers.getSigners())[0]; + console.log("Signer:", signer.address); // We get the contract to deploy const AludelFactory = await ethers.getContractFactory("AludelFactory"); const factory = await AludelFactory.deploy(); - await factory.deployed() + await factory.deployed(); console.log("AludelFactory deployed to:", factory.address); - + // await factory.deployTransaction.wait(1) - await sleep(150000) + await sleep(150000); // verify source - console.log('Verifying source on etherscan') - await run('verify:verify', { + console.log("Verifying source on etherscan"); + await run("verify:verify", { address: factory.address, constructorArguments: [], - }) + }); const AludelTemplate = await ethers.getContractFactory("Aludel"); const template = await AludelTemplate.deploy(); - await template.deployed() + await template.deployed(); console.log("AludelTemplate deployed to:", template.address); - + // await template.deployTransaction.wait(1) - await sleep(150000) - + await sleep(150000); + // verify source - console.log('Verifying source on etherscan') - await run('verify:verify', { + console.log("Verifying source on etherscan"); + await run("verify:verify", { address: template.address, constructorArguments: [], - }) + }); // add template - await factory.addTemplate(template.address) - + await factory.addTemplate(template.address); } main().catch((error) => { diff --git a/src/contracts/aludel/Aludel.sol b/src/contracts/aludel/Aludel.sol index 39d9e25..4e11852 100644 --- a/src/contracts/aludel/Aludel.sol +++ b/src/contracts/aludel/Aludel.sol @@ -70,8 +70,8 @@ contract Aludel is IAludel, Ownable, Initializable, Powered { EnumerableSet.AddressSet internal _vaultFactorySet; - address _feeRecipient; - uint16 _feeBps; + address private _feeRecipient; + uint16 private _feeBps; struct AludelInitializationParams { address rewardPoolFactory; @@ -1101,4 +1101,4 @@ contract Aludel is IAludel, Ownable, Initializable, Powered { } return newArray; } -} \ No newline at end of file +} diff --git a/src/test/PowerSwitch.t.sol b/src/test/PowerSwitch.t.sol index 57599ab..141ea4d 100644 --- a/src/test/PowerSwitch.t.sol +++ b/src/test/PowerSwitch.t.sol @@ -11,9 +11,9 @@ import { } from "../contracts/powerSwitch/PowerSwitch.sol"; contract PowerSwitchTest is DSTest { - Hevm cheats; + Hevm private cheats; - PowerSwitchFactory powerSwitchFactory; + PowerSwitchFactory private powerSwitchFactory; function setUp() public { cheats = Hevm(HEVM_ADDRESS); diff --git a/src/test/Utils.sol b/src/test/Utils.sol index 6ec242f..c7fb64d 100644 --- a/src/test/Utils.sol +++ b/src/test/Utils.sol @@ -20,30 +20,13 @@ library Utils { public returns (bytes memory) { - // CheatCodes cheats = CheatCodes(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)); - - // bytes32 domainSeparator = keccak256(abi.encode( - // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), - // keccak256('UniversalVault'), - // keccak256('1.0.0'), - // getChainId(), - // crucible - // )); - // bytes32 structHash = keccak256(abi.encode( - // keccak256(abi.encodePacked(method, "(address delegate,address token,uint256 amount,uint256 nonce)")), - // address(delegate), - // address(token), - // amount, - // nonce - // )); - bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", // domain separator hash keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), - keccak256('UniversalVault'), - keccak256('1.0.0'), + keccak256("UniversalVault"), + keccak256("1.0.0"), getChainId(), crucible )), @@ -81,4 +64,4 @@ library Utils { } return sig; } -} \ No newline at end of file +} diff --git a/tasks/aludel.ts b/tasks/aludel.ts index bcdaa39..f3a66a6 100644 --- a/tasks/aludel.ts +++ b/tasks/aludel.ts @@ -1,15 +1,15 @@ import { AbiCoder } from "@ethersproject/abi"; -import { formatEther, getAddress, parseUnits } from "ethers/lib/utils"; +import { formatEther } from "ethers/lib/utils"; import { task } from "hardhat/config"; import "@nomiclabs/hardhat-ethers"; import { parseEther } from "@ethersproject/units"; -import { AddressZero } from "@ethersproject/constants" +import { AddressZero } from "@ethersproject/constants"; -export const ETHER = (amount: number = 1) => parseEther(amount.toString()); -export const DAYS = (days: number = 1) => days * 60 * 60 * 24; +export const ETHER = (amount = 1) => parseEther(amount.toString()); +export const DAYS = (days = 1) => days * 60 * 60 * 24; task("launch-program") - .addParam('templateId', 'address of the template to use') + .addParam("templateId", "address of the template to use") .addParam("aludelFactory", "address of the aludel factory") .addParam("owner", "address of the aludel's owner") .addParam("rewardPool", "address of the reward pool factory") @@ -18,13 +18,19 @@ task("launch-program") .addParam("rewardToken", "address of the reward token") .addParam("rewardScalingFloor", "reward scaling floor amount (in ETH)") .addParam("rewardScalingCeiling", "reward scaling ceiling amount (in ETH)") - .addParam("rewardScalingTime", "duration of the reward scaling period (in days)") - .addParam('name', 'the name of the program') - .addParam('stakingTokenUrl', 'the URL of the staking token') - .addParam('startTime', 'the start time for the program in utc timestamp (seconds)') - .addParam('vaultFactory', 'the initial vault factory to be whitelisted') - .addParam('bonusToken', 'address of one bonus token to be added on launch') - .setAction(async (args, { ethers, run, network }) => { + .addParam( + "rewardScalingTime", + "duration of the reward scaling period (in days)" + ) + .addParam("name", "the name of the program") + .addParam("stakingTokenUrl", "the URL of the staking token") + .addParam( + "startTime", + "the start time for the program in utc timestamp (seconds)" + ) + .addParam("vaultFactory", "the initial vault factory to be whitelisted") + .addParam("bonusToken", "address of one bonus token to be added on launch") + .setAction(async (args, { ethers, network }) => { // log config console.log("Network"); @@ -48,17 +54,17 @@ task("launch-program") "src/contracts/AludelFactory.sol:AludelFactory", args.aludelFactory ); - + // encode init params const params = new AbiCoder().encode( [ - 'address', - 'address', - 'address', - 'address', - 'uint256', - 'uint256', - 'uint256' + "address", + "address", + "address", + "address", + "uint256", + "uint256", + "uint256", ], [ args.rewardPool, @@ -76,7 +82,7 @@ task("launch-program") await factory.launch( args.templateId, args.name, - args.stakingTokenUrl, + args.stakingTokenUrl, args.startTime, args.vaultFactory, [args.bonusToken], // only supports single bonus token @@ -84,16 +90,13 @@ task("launch-program") params ) ).wait(); - - }); - -task('update-template') +task("update-template") .addParam("aludelFactory", "address of the aludel factory") .addParam("template", "address of a template") - .addFlag('disable') - .setAction(async (args, { ethers, run, network }) => { + .addFlag("disable") + .setAction(async (args, { ethers, network }) => { // log config console.log("Network"); @@ -113,22 +116,21 @@ task('update-template') "src/contracts/AludelFactory.sol:AludelFactory", args.aludelFactory ); - - console.log(factory) + + console.log(factory); // deploy minimal proxy using `params` as init params await ( await factory.updateTemplate(args.template, args.disable ? true : false) ).wait(); - - }) + }); task("add-template") .addParam("aludelFactory", "address of the aludel factory") .addParam("template", "address of a template") .addParam("name", "name of the template based on mapping object") - .addFlag('disable', 'to set the template as disabled') - .setAction(async (args, { ethers, run, network }) => { + .addFlag("disable", "to set the template as disabled") + .setAction(async (args, { ethers, network }) => { // log config console.log("Network"); @@ -148,18 +150,20 @@ task("add-template") "src/contracts/AludelFactory.sol:AludelFactory", args.aludelFactory ); - + await ( - await factory.addTemplate(args.template, args.name, args.disabled ? true : false) + await factory.addTemplate( + args.template, + args.name, + args.disabled ? true : false + ) ).wait(); - }); - task("delist-program") .addParam("aludelFactory", "address of the aludel factory") .addParam("program", "address of a program") - .setAction(async (args, { ethers, run, network }) => { + .setAction(async (args, { ethers, network }) => { // log config console.log("Network"); @@ -179,23 +183,26 @@ task("delist-program") "src/contracts/AludelFactory.sol:AludelFactory", args.aludelFactory ); - - // deploy minimal proxy using `params` as init params - await ( - await factory.delistProgram(args.program) - ).wait(); + // deploy minimal proxy using `params` as init params + await (await factory.delistProgram(args.program)).wait(); }); - task("add-program") .addParam("aludelFactory", "address of the aludel factory") .addParam("program", "deployed address of the program") - .addParam("template", "Optional. deployed address of the program's template", AddressZero) - .addParam('name', 'the name of the program') - .addParam('stakingTokenUrl', 'the URL of the staking token') - .addParam('startTime', 'the program start time in utc timestamp format (seconds)') - .setAction(async (args, { ethers, run, network }) => { + .addParam( + "template", + "Optional. deployed address of the program's template", + AddressZero + ) + .addParam("name", "the name of the program") + .addParam("stakingTokenUrl", "the URL of the staking token") + .addParam( + "startTime", + "the program start time in utc timestamp format (seconds)" + ) + .setAction(async (args, { ethers, network }) => { // log config console.log("Network"); @@ -215,16 +222,15 @@ task("add-program") "src/contracts/AludelFactory.sol:AludelFactory", args.aludelFactory ); - + // deploy minimal proxy using `params` as init params await ( await factory.addProgram( args.program, args.template, args.name, - args.stakingTokenUrl, + args.stakingTokenUrl, args.startTime ) ).wait(); - }); diff --git a/test/index.ts b/test/index.ts index d6bc9e6..9596881 100644 --- a/test/index.ts +++ b/test/index.ts @@ -7,12 +7,7 @@ import { network, ethers as hardhatEthers, } from "hardhat"; -import{ - Aludel, - AludelFactory, - Crucible, - MockERC20, -} from "../typechain-types"; +import { Aludel, AludelFactory, Crucible, MockERC20 } from "../typechain-types"; import { DAYS, ETHER, signPermission } from "./utils"; import { AddressZero } from "@ethersproject/constants"; diff --git a/test/utils.ts b/test/utils.ts index 2ce1585..cf1b1b6 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,10 +1,6 @@ import { TypedDataField } from "@ethersproject/abstract-signer"; import { parseEther } from "@ethersproject/units"; -import { - BigNumberish, - Contract, - Wallet, -} from "ethers"; +import { BigNumberish, Contract, Wallet } from "ethers"; import { EthereumProvider } from "hardhat/types"; @@ -42,7 +38,8 @@ export function wrapWithTitle(title: string | undefined, str: string) { const DAY = 60 * 60 * 24; -export const ETHER: (a:number) => BigNumberish = (amount = 1) => parseEther(amount.toString()); +export const ETHER: (a: number) => BigNumberish = (amount = 1) => + parseEther(amount.toString()); export const DAYS = (days = 1) => days * DAY; export const signPermission = async ( diff --git a/yarn.lock b/yarn.lock index 9ebd860..fc90900 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3426,6 +3426,14 @@ eslint-plugin-import@2.26.0: resolve "^1.22.0" tsconfig-paths "^3.14.1" +eslint-plugin-mocha@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.1.0.tgz#69325414f875be87fb2cb00b2ef33168d4eb7c8d" + integrity sha512-xLqqWUF17llsogVOC+8C6/jvQ+4IoOREbN7ZCHuOHuD6cT5cDD4h7f2LgsZuzMAiwswWE21tO7ExaknHVDrSkw== + dependencies: + eslint-utils "^3.0.0" + rambda "^7.1.0" + eslint-plugin-node@11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" @@ -6851,6 +6859,11 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +rambda@^7.1.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.3.0.tgz#90e440ead53030a216093865d8d97997a80868ca" + integrity sha512-RFVofZYaG2TaVcxjnM0ejdVWf/59rFq1f57OGnjP3GT/bthzFw0GVr5rkP9PKbVlEuF/Y7bOVPLfiiYfxq/EWQ== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"