From 18aa599c11ff102b53a2fff8f1e6f4df32aebee5 Mon Sep 17 00:00:00 2001 From: Geoff Hayes Date: Fri, 24 Apr 2020 10:44:29 -0700 Subject: [PATCH] Add Token Deployment Script (#34) * Add Token Deployment Script This patch adds saddle scripts to deploy, verify and match a cToken from a JSON configuration passed in on the command line. The goal is to make life very easy for deployment, specifically with builds from release versions of the Compound Protocol. Note: this does not _force_ developers to use release versions, but it means that developers can choose to deploy from versions of Compound that were audited. I've added significant usage notes to the README. * Add Docker Builds This patch adds Docker builds to our CI pipeline. This is the last step in letting the community run verified deployments. Every time a commit is pushed, an image and built and pushed to Docker Hub tagged with the commit (and if the commit is tagged, that will be included as a tag for Docker Hub as well). --- .circleci/config.yml | 31 +++++ .dockerignore | 4 +- .gitignore | 3 +- README.md | 85 ++++++++++++ package.json | 2 +- saddle.config.js | 7 +- script/saddle/deployToken.js | 67 ++++++++++ script/saddle/matchToken.js | 45 +++++++ script/saddle/support/tokenConfig.js | 83 ++++++++++++ script/saddle/verifyToken.js | 53 ++++++++ yarn.lock | 189 ++++++++++++++++++++++++++- 11 files changed, 560 insertions(+), 9 deletions(-) create mode 100644 script/saddle/deployToken.js create mode 100644 script/saddle/matchToken.js create mode 100644 script/saddle/support/tokenConfig.js create mode 100644 script/saddle/verifyToken.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 9a50577b3..cfc346165 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -158,6 +158,33 @@ jobs: at: ~/repo - run: yarn run lint + docker: + docker: + - image: cimg/go:1.13 + steps: + - run: | + if [ -z "$DOCKER_USER" -o -z "$DOCKER_PASS" -o -z "$DOCKER_REPO" ]; then + echo "No DOCKER_REPO, DOCKER_USER or DOCKER_PASS, skipping Docker build..." + circleci-agent step halt + fi + - checkout + - setup_remote_docker: + docker_layer_caching: true + - run: | + echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin + + set -x + + IMAGE_NAME=${CIRCLE_PROJECT_USERNAME/-/}/$CIRCLE_PROJECT_REPONAME + COMMIT_TAG=$(git rev-parse --short HEAD) + docker build -t $IMAGE_NAME:$COMMIT_TAG . + docker push $IMAGE_NAME:$COMMIT_TAG + + if [ -n "$CIRCLE_TAG" ]; then + docker build -t $IMAGE_NAME:$CIRCLE_TAG . + docker push $IMAGE_NAME:$CIRCLE_TAG + fi + workflows: version: 2 build-test-and-deploy: @@ -166,3 +193,7 @@ workflows: - coverage - lint - verify + - docker: + filters: + tags: + only: /^v.*/ diff --git a/.dockerignore b/.dockerignore index 8f2379b97..e2d71b64e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -35,4 +35,6 @@ junit.xml .build .last_confs .git -script/certora \ No newline at end of file +script/certora +.saddle_history +.circleci diff --git a/.gitignore b/.gitignore index 4418d2283..d7ee7709d 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,5 @@ scenario/.tscache tests/scenarios/ junit.xml .build -.last_confs \ No newline at end of file +.last_confs +.saddle_history diff --git a/README.md b/README.md index 9d73961fa..f6b42aa56 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,91 @@ This command will start a saddle console conencted to Goerli testnet (see [Saddl '10000000000000000000000000' ``` +Deploying a CToken from Source +------------------------------ + +Note: you will need to set `~/.ethereum/` with your private key or assign your private key to the environment variable `ACCOUNT`. + +Note: for all sections including Etherscan verification, you must set the `ETHERSCAN_API_KEY` to a valid API Key from [Etherscan](https://etherscan.io/apis). + +To deploy a new cToken, you can run the `token:deploy`. command, as follows. If you set `VERIFY=true`, the script will verify the token on Etherscan as well. The JSON here is the token config JSON, which should be specific to the token you wish to list. + +```bash +npx saddle -n rinkeby script token:deploy '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' +``` + +If you only want to verify an existing token an Etherscan, make sure `ETHERSCAN_API_KEY` is set and run `token:verify` with the first argument as the token address and the second as the token config JSON: + +```bash +npx saddle -n rinkeby script token:verify 0x19B674715cD20626415C738400FDd0d32D6809B6 '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' +``` + +Finally, to see if a given deployment matches this version of the Compound Protocol, you can run `token:match` with a token address and token config: + +```bash +npx saddle -n rinkeby script token:match 0x19B674715cD20626415C738400FDd0d32D6809B6 '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' +``` + +## Deploying a CToken from Docker Build +--------------------------------------- + +To deploy a specific version of the Compound Protocol, you can use the `token:deploy` script through Docker: + +```bash +docker run --env ETHERSCAN_API_KEY --env VERIFY=true --env ACCOUNT=0x$(cat ~/.ethereum/rinkeby) compoundfinance/compound-protocol:latest npx saddle -n rinkeby script token:deploy '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' +``` + +To match a deployed contract against a given version of the Compound Protocol, you can run `token:match` through Docker, passing a token address and config: + +```bash +docker run --env ACCOUNT=0x$(cat ~/.ethereum/rinkeby) compoundfinance/compound-protocol:latest npx saddle -n rinkeby script token:match 0xF1BAd36CB247C82Cb4e9C2874374492Afb50d565 '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' +``` + Discussion ---------- diff --git a/package.json b/package.json index 37efe9631..e333f59b4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "solparse": "^2.2.8" }, "dependencies": { - "eth-saddle": "0.1.10" + "eth-saddle": "0.1.17" }, "resolutions": { "scrypt.js": "https://registry.npmjs.org/@compound-finance/ethereumjs-wallet/-/ethereumjs-wallet-0.6.3.tgz", diff --git a/saddle.config.js b/saddle.config.js index 00298e516..5a941681d 100644 --- a/saddle.config.js +++ b/saddle.config.js @@ -139,7 +139,7 @@ module.exports = { web3: { gas: [ {env: "GAS"}, - {default: "4600000"} + {default: "5600000"} ], gas_price: [ {env: "GAS_PRICE"}, @@ -235,5 +235,10 @@ module.exports = { 'Contracts': value }, null, 4)); }); + }, + scripts: { + 'token:deploy': "script/saddle/deployToken.js", + 'token:verify': "script/saddle/verifyToken.js", + 'token:match': "script/saddle/matchToken.js" } } diff --git a/script/saddle/deployToken.js b/script/saddle/deployToken.js new file mode 100644 index 000000000..4d1908537 --- /dev/null +++ b/script/saddle/deployToken.js @@ -0,0 +1,67 @@ +let { loadConf } = require('./support/tokenConfig'); + +function printUsage() { + console.log(` +usage: npx saddle script token:deploy {tokenConfig} + +note: pass VERIFY=true and ETHERSCAN_API_KEY= to verify contract on Etherscan + +example: + +npx saddle -n rinkeby script token:deploy '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' + `); +} + +function sleep(timeout) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, timeout); + }); +} + +(async function() { + if (args.length !== 1) { + return printUsage(); + } + + let conf = loadConf(args[0], addresses); + if (!conf) { + return printUsage(); + } + + console.log(`Deploying cToken with ${JSON.stringify(conf)}`); + + let deployArgs = [conf.underlying, conf.comptroller, conf.interestRateModel, conf.initialExchangeRateMantissa.toString(), conf.name, conf.symbol, conf.decimals, conf.admin]; + let contract = await saddle.deploy('CErc20Immutable', deployArgs); + + console.log(`Deployed contract to ${contract._address}`); + + if (env['VERIFY']) { + const etherscanApiKey = env['ETHERSCAN_API_KEY']; + if (etherscanApiKey === undefined || etherscanApiKey.length === 0) { + throw new Error(`ETHERSCAN_API_KEY must be set if using VERIFY flag...`); + } + + console.log(`Sleeping for 30 seconds then verifying contract on Etherscan...`); + await sleep(30000); // Give Etherscan time to learn about contract + console.log(`Now verifying contract on Etherscan...`); + + await saddle.verify(etherscanApiKey, contract._address, 'CErc20Immutable', deployArgs, 0); + console.log(`Contract verified at https://${network}.etherscan.io/address/${contract._address}`); + } + + return { + ...conf, + address: contract._address + }; +})(); diff --git a/script/saddle/matchToken.js b/script/saddle/matchToken.js new file mode 100644 index 000000000..045019034 --- /dev/null +++ b/script/saddle/matchToken.js @@ -0,0 +1,45 @@ +let { loadAddress, loadConf } = require('./support/tokenConfig'); + +function printUsage() { + console.log(` +usage: npx saddle script token:match address {tokenConfig} + +This checks to see if the deployed byte-code matches this version of the Compound Protocol. + +example: + +npx saddle -n rinkeby script token:match 0x19B674715cD20626415C738400FDd0d32D6809B6 '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' + `); +} + +(async function() { + if (args.length !== 2) { + return printUsage(); + } + + let address = loadAddress(args[0], addresses); + let conf = loadConf(args[1], addresses); + if (!conf) { + return printUsage(); + } + + console.log(`Matching cToken at ${address} with ${JSON.stringify(conf)}`); + + let deployArgs = [conf.underlying, conf.comptroller, conf.interestRateModel, conf.initialExchangeRateMantissa.toString(), conf.name, conf.symbol, conf.decimals, conf.admin]; + + await saddle.match(address, 'CErc20Immutable', deployArgs); + + return { + ...conf, + address + }; +})(); diff --git a/script/saddle/support/tokenConfig.js b/script/saddle/support/tokenConfig.js new file mode 100644 index 000000000..aa8cd2544 --- /dev/null +++ b/script/saddle/support/tokenConfig.js @@ -0,0 +1,83 @@ + +function getRaw(config, key, required=true) { + let value = config[key]; + if (!value) { + throw new Error(`Config missing required key \`${key}\``); + } + return value; +} + +function getString(config, key, required=true) { + let value = getRaw(config, key, required); + if (value === "" && required) { + throw new Error(`Config missing required key \`${key}\``); + } + return value || ""; +} + +function loadAddress(value, addresses, errorMessage=null) { + if (value.startsWith("$")) { + let contract = value.slice(1,); + let address = addresses[contract]; + if (!address) { + throw new Error(`Cannot find deploy address for \`${contract}\``); + } + return address; + } else if (value.startsWith("0x")) { + return value; + } else { + throw new Error(errorMessage || `Invalid address \`${value}\``); + } +} + +function getAddress(addresses, config, key, required=true) { + let value = getString(config, key, required); + return loadAddress( + value, + addresses, + `Invalid address for \`${key}\`=${value}`, + required + ); +} + +function getNumber(config, key, required=true) { + let value = getRaw(config, key, required); + let result = Number(value); + if (Number.isNaN(result)) { + throw new Error(`Invalid number for \`${key}\`=${value}`); + } else { + return Number(result); + } +} + +function loadConf(configArg, addresses) { + let config; + if (!configArg) { + return null; + } + + try { + config = JSON.parse(configArg) + } catch (e) { + console.log(); + console.error(e); + return null; + } + const conf = { + underlying: getAddress(addresses, config, 'underlying'), + comptroller: getAddress(addresses, config, 'comptroller'), + interestRateModel: getAddress(addresses, config, 'interestRateModel'), + initialExchangeRateMantissa: getNumber(config, 'initialExchangeRateMantissa'), + name: getString(config, 'name'), + symbol: getString(config, 'symbol'), + decimals: getNumber(config, 'decimals'), + admin: getAddress(addresses, config, 'admin'), + }; + + return conf; +} + +module.exports = { + loadAddress, + loadConf +}; diff --git a/script/saddle/verifyToken.js b/script/saddle/verifyToken.js new file mode 100644 index 000000000..3b964a566 --- /dev/null +++ b/script/saddle/verifyToken.js @@ -0,0 +1,53 @@ +let { loadAddress, loadConf } = require('./support/tokenConfig'); + +function printUsage() { + console.log(` +usage: npx saddle script token:verify {tokenAddress} {tokenConfig} + +note: $ETHERSCAN_API_KEY environment variable must be set to an Etherscan API Key. + +example: + +npx saddle -n rinkeby script token:verify 0x19B674715cD20626415C738400FDd0d32D6809B6 '{ + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "comptroller": "$Comptroller", + "interestRateModel": "$Base200bps_Slope3000bps", + "initialExchangeRateMantissa": "2.0e18", + "name": "Compound Kyber Network Crystal", + "symbol": "cKNC", + "decimals": "8", + "admin": "$Timelock" +}' + `); +} + +(async function() { + if (args.length !== 2) { + return printUsage(); + } + + let address = loadAddress(args[0], addresses); + let conf = loadConf(args[1], addresses); + if (!conf) { + return printUsage(); + } + let etherscanApiKey = env['ETHERSCAN_API_KEY']; + if (!etherscanApiKey) { + console.error("Missing required $ETHERSCAN_API_KEY env variable."); + return printUsage(); + } + + console.log(`Verifying cToken at ${address} with ${JSON.stringify(conf)}`); + + let deployArgs = [conf.underlying, conf.comptroller, conf.interestRateModel, conf.initialExchangeRateMantissa.toString(), conf.name, conf.symbol, conf.decimals, conf.admin]; + + // TODO: Make sure we match optimizations count, etc + await saddle.verify(etherscanApiKey, address, 'CErc20Immutable', deployArgs, 200, undefined); + + console.log(`Contract verified at https://${network}.etherscan.io/address/${address}`); + + return { + ...conf, + address + }; +})(); diff --git a/yarn.lock b/yarn.lock index adaef1585..4995ca918 100644 --- a/yarn.lock +++ b/yarn.lock @@ -692,6 +692,16 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@jest/types@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.3.0.tgz#88f94b277a1d028fd7117bc1f74451e0fc2131e7" + integrity sha512-UkaDNewdqXAmCDbN2GlUM6amDKS78eCqiw/UmF5nE0mmLTd6moJkiZJML/X52Ke3LH7Swhw883IRXq8o9nWjVw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@ledgerhq/devices@^4.78.0": version "4.78.0" resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-4.78.0.tgz#149b572f0616096e2bd5eb14ce14d0061c432be6" @@ -761,6 +771,27 @@ resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-4.72.0.tgz#43df23af013ad1135407e5cf33ca6e4c4c7708d5" integrity sha512-o+TYF8vBcyySRsb2kqBDv/KMeme8a2nwWoG+lAWzbDmWfb2/MrVWYCVYDYvjXdSoI/Cujqy1i0gIDrkdxa9chA== +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -820,6 +851,11 @@ dependencies: "@types/node" "*" +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/ethereum-protocol@*": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/ethereum-protocol/-/ethereum-protocol-1.0.0.tgz#416e3827d5fdfa4658b0045b35a008747871b271" @@ -923,6 +959,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^15.0.0": + version "15.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" + integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== + dependencies: + "@types/yargs-parser" "*" + "@web3-js/scrypt-shim@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc" @@ -1076,6 +1119,11 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -1088,6 +1136,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + any-promise@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -2017,7 +2073,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@~3.0.2: +braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2332,6 +2388,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -2466,11 +2530,23 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + colors@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -2950,6 +3026,11 @@ diff-sequences@^24.9.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== +diff-sequences@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" + integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== + diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" @@ -3379,10 +3460,10 @@ eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: json-rpc-random-id "^1.0.0" xtend "^4.0.1" -eth-saddle@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/eth-saddle/-/eth-saddle-0.1.10.tgz#b51cb72029d1505b101f4bd0ff8dabccde1d9fd9" - integrity sha512-VGhIzXv0M4GpQsW5EVj734AZmn7TNYCrqvK8LIq9ozMI/xGHIxxp/Mt0TZwdxQPyrJpCLHeOKcoghqacKwD2Lw== +eth-saddle@0.1.17: + version "0.1.17" + resolved "https://registry.yarnpkg.com/eth-saddle/-/eth-saddle-0.1.17.tgz#54c7bf89970739f0154b382cfbdda9ccdae314f5" + integrity sha512-o+ZhnasyFmlBtmeAI8MV/pnCPtjxnkJ058qQ9H0k27Ew6f+Aj7k/k0HuEElCMkczELTa57UJIv0nZqjCVNARxw== dependencies: "@0x/sol-tracing-utils" "^7.0.3" "@0x/subproviders" "^6.0.0" @@ -3390,9 +3471,11 @@ eth-saddle@0.1.10: "@types/jest" "^24.0.15" ethereumjs-tx "2.1.2" ethereumjs-util "5.2.0" + fast-glob "^3.2.2" ganache-core "^2.9.1" jest "^24.9.0" jest-cli "^24.9.0" + jest-diff "^25.3.0" jest-junit "^6.4.0" ts-jest "^24.0.2" typescript "^3.5.1" @@ -3954,6 +4037,18 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-glob@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@2.x: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -3974,6 +4069,13 @@ fast-safe-stringify@^2.0.6: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== +fastq@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801" + integrity sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -4319,6 +4421,13 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + glob-parent@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" @@ -4482,6 +4591,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" @@ -5202,6 +5316,16 @@ jest-diff@^24.3.0, jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" +jest-diff@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.3.0.tgz#0d7d6f5d6171e5dacde9e05be47b3615e147c26f" + integrity sha512-vyvs6RPoVdiwARwY4kqFWd4PirPLm2dmmkNzKqo38uZOzJvLee87yzDjIZLmY1SjM3XR5DwsUH+cdQ12vgqi1w== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.6" + jest-get-type "^25.2.6" + pretty-format "^25.3.0" + jest-docblock@^24.3.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" @@ -5248,6 +5372,11 @@ jest-get-type@^24.9.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== +jest-get-type@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" + integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== + jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" @@ -6166,6 +6295,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + merkle-patricia-tree@2.3.2, merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" @@ -6223,6 +6357,14 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -6944,6 +7086,11 @@ picomatch@^2.0.4: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.1.tgz#ecdfbea7704adb5fe6fb47f9866c4c0e15e905c5" integrity sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA== +picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -7061,6 +7208,16 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" +pretty-format@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.3.0.tgz#d0a4f988ff4a6cd350342fdabbb809aeb4d49ad5" + integrity sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA== + dependencies: + "@jest/types" "^25.3.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -7271,6 +7428,11 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^16.12.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-is@^16.8.4: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" @@ -7564,6 +7726,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -7598,6 +7765,11 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + rustbn.js@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" @@ -8307,6 +8479,13 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + swarm-js@0.1.39: version "0.1.39" resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.39.tgz#79becb07f291d4b2a178c50fee7aa6e10342c0e8"