diff --git a/package.json b/package.json index a9c49b7..6d49a46 100644 --- a/package.json +++ b/package.json @@ -50,13 +50,10 @@ "dependencies": { "@babel/plugin-proposal-optional-chaining": "7.2.0", "@babel/runtime-corejs2": "7.3.1", - "@omisego/omg-js": "1.2.2", - "@omisego/omg-js-childchain": "1.2.1", - "@omisego/omg-js-rootchain": "1.2.2", - "@omisego/omg-js-util": "1.2.1", - "async": "3.0.1", - "axios": "0.19.0", - "ethers": "4.0.28" + "@omisego/omg-js": "2.0.0-v0.2", + "@omisego/omg-js-childchain": "2.0.0-v0.2", + "@omisego/omg-js-rootchain": "2.0.0-v0.2", + "@omisego/omg-js-util": "2.0.0-v0.2" }, "devDependencies": { "@babel/cli": "7.2.3", diff --git a/src/index.js b/src/index.js index 54efecf..d4a3d33 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,16 @@ -/* global EmbarkJS */ +/* global web3, ethereum */ +import { + confirmTransaction, + normalizeUrl, + selectUtxos, + signTypedData +} from "./utils"; import BigNumber from "bn.js"; import ChildChain from "@omisego/omg-js-childchain"; import RootChain from "@omisego/omg-js-rootchain"; import { transaction } from "@omisego/omg-js-util"; -const ACCOUNT_CONFIG_ERROR = "Blockchain accounts configuration is missing. To use the Embark-OMG plugin, you must configure blockchain accounts to use either a private key file, a private key, or a mnemonic."; -const ACCOUNT_BALANCE_ERROR = "The configured account does not have enough funds. Please make sure this account has Rinkeby ETH."; +const web3Options = { transactionConfirmationBlocks: 1 }; export default class BaseEmbarkOmg { constructor({ pluginConfig, logger }) { @@ -16,57 +21,61 @@ export default class BaseEmbarkOmg { this.addressPrivateKey = ""; this.maxDeposit = 0; - // plugin opts - this.plasmaContractAddress = pluginConfig.PLASMA_CONTRACT_ADDRESS; - //this.web3ProviderUrl = pluginConfig.WEB3_PROVIDER_URL; - this.watcherUrl = pluginConfig.WATCHER_URL; - this.childChainUrl = pluginConfig.CHILDCHAIN_URL; + this.plasmaContractAddress = + pluginConfig.PLASMA_CONTRACT_ADDRESS || + "0x740ecec4c0ee99c285945de8b44e9f5bfb71eea7"; + this.watcherUrl = normalizeUrl( + pluginConfig.WATCHER_URL || "https://watchersamrong.omg.network/" + ); + this.childChainUrl = normalizeUrl( + pluginConfig.CHILDCHAIN_URL || "https://samrong.omg.network/" + ); + this.childChainExplorerUrl = normalizeUrl( + pluginConfig.CHILDCHAIN_EXPLORER_URL || + "https://quest.samrong.omg.network" + ); } - async init(web3) { //}, web3Path) { + async initWeb3() { + if (window.ethereum) { + this.web3 = new Web3(window.ethereum, null, web3Options); + try { + // Request account access + await ethereum.enable(); + return true; + } catch (err) { + // User denied account access :( + console.error(err); + } + } else if (window.web3) { + this.web3 = new Web3(window.web3.currentProvider, null, web3Options); + return true; + } + // No web3... + return false; + } + + async init(web3) { + //}, web3Path) { try { if (this.initing) { const message = "Already intializing the Plasma chain, please wait..."; - //this.logger.error(message); throw new Error(message); } this.initing = true; - // if (!(accounts && accounts.length)) { - // //this.logger.error(ACCOUNT_CONFIG_ERROR); - // throw new Error(ACCOUNT_CONFIG_ERROR); + // if (!(await this.initWeb3())) { + this.web3 = web3; // } - //const { address, privateKey } = accounts[0]; - //this.address = address; - //this.addressPrivateKey = privateKey; - - // this.address = accounts[0]; - - - // init Web3 - // const web3Lib = web3Path ? require(web3Path) : Web3; - // this.web3 = new web3Lib(); - // if (!web3) { - // web3 = EmbarkJS.Blockchain.providers["web3"]; - // } - this.web3 = web3; let accounts = await this.web3.eth.getAccounts(); this.address = accounts.length > 1 ? accounts[1] : accounts[0]; // ignore the first account because it is our deployer account, we want the manually added account - - // if(!this.web3) { - // throw new Error("web3 cannot be found. Please ensure you have the 'embarkjs-connector-web3' plugin installed in your DApp."); - // } - // const web3Provider = new web3Lib.providers.HttpProvider(this.web3ProviderUrl); - //this.web3.setProvider(web3Provider); - // check account balance on the main chain // try { // this.maxDeposit = await this.web3.eth.getBalance(this.address); // if (!this.maxDeposit || new BigNumber(this.maxDeposit).lte(0)) { - // //this.logger.error(ACCOUNT_BALANCE_ERROR); - // throw new Error(ACCOUNT_BALANCE_ERROR); + // throw new Error("The configured account does not have enough funds. Please make sure this account has Rinkeby ETH."); // } // this.maxDeposit = new BigNumber(this.maxDeposit); // } @@ -76,29 +85,30 @@ export default class BaseEmbarkOmg { // set up the Plasma chain this.rootChain = new RootChain(this.web3, this.plasmaContractAddress); - this.childChain = new ChildChain(this.watcherUrl, this.childChainUrl); + this.childChain = new ChildChain(this.watcherUrl); //, this.childChainUrl); // set lifecycle state vars this.initing = false; this.inited = true; - } - catch (e) { + } catch (e) { const message = `Error initializing Plasma chain: ${e}`; - //this.logger.error(message); throw new Error(message); } } async deposit(amount) { + // TODO: Update this to support ERC-20's + const currency = transaction.ETH_CURRENCY; + const approveDeposit = false; + const erc20abi = {}; + if (!this.inited) { const message = "Please wait for the Plasma chain to initialize..."; - // this.logger.error(message); throw new Error(message); } amount = new BigNumber(amount); if (!amount || amount.lte(0)) { const message = "You must deposit more than 0 wei."; - // this.logger.error(message); throw new Error(message); } // if (amount.gt(this.maxDeposit) && this.maxDeposit.gt(0)) { @@ -106,38 +116,64 @@ export default class BaseEmbarkOmg { // this.maxDeposit = await this.web3.eth.getBalance(this.address); // if (amount.gt(this.maxDeposit)) { // const message = `You do not have enough funds for this deposit. Please deposit more funds in to ${this.address} and then try again.`; - // // this.logger.error(message); // throw new Error(message); // } // } - // const DEPOSIT_AMT = "100000"; - this.logger.info(`Depositing ${amount} wei...`); - const depositTx = transaction.encodeDeposit(this.address, amount, transaction.ETH_CURRENCY); - try { - const receipt = await this.rootChain.depositEth(depositTx, amount, { from: this.address });//, privateKey: this.addressPrivateKey }); - this.logger.trace(receipt); - const message = `Successfully deposited ${amount} wei in to the Plasma chain.\nView the transaction: https://rinkeby.etherscan.io/tx/${receipt.transactionHash}`; - // this.logger.info(message); - return message; + // Create the deposit transaction + const depositTx = transaction.encodeDeposit(this.address, amount, currency); + + if (currency === transaction.ETH_CURRENCY) { + this.logger.info(`Depositing ${amount} wei...`); + // ETH deposit + try { + const receipt = await this.rootChain.depositEth(depositTx, amount, { + from: this.address + }); + this.logger.trace(receipt); + const message = `Successfully deposited ${amount} wei in to the Plasma chain.\nView the transaction: https://rinkeby.etherscan.io/tx/${ + receipt.transactionHash + }`; + return message; + } catch (e) { + const message = `Error depositing ${amount} wei: ${e}`; + throw new Error(message); + } } - catch (e) { - const message = `Error depositing ${amount} wei: ${e}`; - // this.logger.error(message); - throw new Error(message); + + // ERC20 token deposit + if (approveDeposit) { + // First approve the plasma contract on the erc20 contract + const erc20 = new this.web3.eth.Contract(erc20abi, currency); + // const approvePromise = Promise.promisify(erc20.approve.sendTransaction) + + // TODO + const gasPrice = 1000000; + const receipt = await erc20.methods + .approve(this.rootChain.plasmaContractAddress, amount) + .send({ from: this.address, gasPrice, gas: 2000000 }); + // Wait for the approve tx to be mined + this.logger.info( + `${amount} erc20 approved: ${ + receipt.transactionHash + }. Waiting for confirmation...` + ); + await confirmTransaction(this.web3, receipt.transactionHash); + this.logger.info(`... ${receipt.transactionHash} confirmed.`); } + + return this.rootChain.depositToken(depositTx, { from: this.address }); } - async send(toAddress, val) { - //const val = "555"; - // const toAddress = "0x38d5beb778b6e62d82e3ba4633e08987e6d0f990"; + async transfer(toAddress, amount) { + // TODO: Update this to support ERC20's + const currency = transaction.ETH_CURRENCY; + const verifyingContract = this.plasmaContractAddress; + + const transferZeroFee = currency !== transaction.ETH_CURRENCY; const utxos = await this.childChain.getUtxos(this.address); - const utxosToSpend = this.selectUtxos(utxos, val, transaction.ETH_CURRENCY); + const utxosToSpend = selectUtxos(utxos, amount, currency, transferZeroFee); if (!utxosToSpend) { - throw new Error(`No utxo big enough to cover the amount ${val}`); - } - val = new BigNumber(val); - if (!val || val.lte(0)) { - throw new Error("Transaction value must be more than 0 wei."); + throw new Error(`No utxo big enough to cover the amount ${amount}`); } const txBody = { @@ -145,72 +181,97 @@ export default class BaseEmbarkOmg { outputs: [ { owner: toAddress, - currency: transaction.ETH_CURRENCY, - amount: val + currency, + amount: amount.toString() } ] }; - const utxoAmnt = new BigNumber(utxosToSpend[0].amount); - if (utxoAmnt.gt(val)) { - // specify the change amount back to yourself - const changeAmnt = utxoAmnt.sub(val); + const bnAmount = new BigNumber(utxosToSpend[0].amount); + if (bnAmount.gt(new BigNumber(amount))) { + // Need to add a 'change' output + const CHANGE_AMOUNT = bnAmount.sub(new BigNumber(amount)); txBody.outputs.push({ owner: this.address, - currency: transaction.ETH_CURRENCY, - amount: changeAmnt + currency, + amount: CHANGE_AMOUNT }); } - try { - const unsignedTx = await this.childChain.createTransaction(txBody); - - const signatures = await this.childChain.signTransaction(unsignedTx);//, [this.addressPrivateKey]); - - const signedTx = await this.childChain.buildSignedTransaction(unsignedTx, signatures); - - const result = await this.childChain.submitTransaction(signedTx); - - const message = `Successfully submitted tx on the child chain: ${JSON.stringify(result)}\nView the transaction: http://quest.ari.omg.network/transaction/${result.txhash}`; - - //this.logger.info(message); - return message; - } - catch (e) { - // this.logger.error(e); - throw e; + if (transferZeroFee && utxosToSpend.length > 1) { + // The fee input can be returned + txBody.outputs.push({ + owner: this.address, + currency: utxosToSpend[utxosToSpend.length - 1].currency, + amount: utxosToSpend[utxosToSpend.length - 1].amount + }); } + + // Get the transaction data + const typedData = transaction.getTypedData(txBody, verifyingContract); + + // We should really sign each input separately but in this we know that they're all + // from the same address, so we can sign once and use that signature for each input. + // + // const sigs = await Promise.all(utxosToSpend.map(input => signTypedData(web3, web3.utils.toChecksumAddress(from), typedData))) + // + const signature = await signTypedData( + this.web3, + this.web3.utils.toChecksumAddress(this.address), + JSON.stringify(typedData) + ); + // const signer = this.web3.utils.toChecksumAddress(this.address); + // const data = JSON.stringify(typedData); + // const signature = this.web3.currentProvider.send("eth_signTypedData_v3", [ + // signer, + // data + // ]); + const sigs = new Array(utxosToSpend.length).fill(signature); + + // Build the signed transaction + const signedTx = this.childChain.buildSignedTransaction(typedData, sigs); + // Submit the signed transaction to the childchain + const result = await this.childChain.submitTransaction(signedTx); + + const message = `Successfully submitted tx on the child chain: ${JSON.stringify( + result + )}\nView the transaction: ${this.childChainExplorerUrl}transaction/${ + result.txhash + }`; + + return message; } async exit(fromAddress) { const utxos = await this.childChain.getUtxos(fromAddress); if (utxos.length <= 0) { const message = `No UTXOs found on the Plasma chain for ${fromAddress}.`; - this.logger.error(message); throw new Error(message); } // NB This only exits the first UTXO. // Selecting _which_ UTXO to exit is left as an exercise for the reader... const errors = []; - utxos.forEach(async (utxo) => { + utxos.forEach(async utxo => { const exitData = await this.childChain.getExitData(utxo); try { let receipt = await this.rootChain.startStandardExit( - exitData.utxo_pos.toString(), + Number(exitData.utxo_pos.toString()), exitData.txbytes, exitData.proof, { from: fromAddress } ); - const message = `Exited UTXO from address ${fromAddress} with value ${utxo.amount}. View the transaction: https://rinkeby.etherscan.io/tx/${receipt.transactionHash}`; - // this.logger.info(message); - return message; - } - catch (e) { - const message = `Error exiting the Plasma chain for UTXO ${JSON.stringify(utxo)}: ${e}`; - // this.logger.error(message); + return `Exited UTXO from address ${fromAddress} with value ${ + utxo.amount + }. View the transaction: https://rinkeby.etherscan.io/tx/${ + receipt.transactionHash + }`; + } catch (e) { + const message = `Error exiting the Plasma chain for UTXO ${JSON.stringify( + utxo + )}: ${e}`; errors.push(message); } }); @@ -222,7 +283,9 @@ export default class BaseEmbarkOmg { selectUtxos(utxos, amount, currency) { const correctCurrency = utxos.filter(utxo => utxo.currency === currency); // Just find the first utxo that can fulfill the amount - const selected = correctCurrency.find(utxo => new BigNumber(utxo.amount).gte(new BigNumber(amount))); + const selected = correctCurrency.find(utxo => + new BigNumber(utxo.amount).gte(new BigNumber(amount)) + ); if (selected) { return [selected]; } diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..76c14c3 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,106 @@ +import BigNumber from "bn.js"; +import { transaction } from "@omisego/omg-js-util"; + +const DEFAULT_INTERVAL = 1000; +const DEFAULT_BLOCKS_TO_WAIT = 1; + +export function confirmTransaction(web3, txnHash, options) { + const interval = options && options.interval ? options.interval : DEFAULT_INTERVAL; + const blocksToWait = options && options.blocksToWait ? options.blocksToWait : DEFAULT_BLOCKS_TO_WAIT; + const transactionReceiptAsync = async function (txnHash, resolve, reject) { + try { + const receipt = await web3.eth.getTransactionReceipt(txnHash); + if (!receipt) { + return setTimeout(function () { + transactionReceiptAsync(txnHash, resolve, reject); + }, interval); + } + if (blocksToWait > 0) { + const resolvedReceipt = await receipt; + if (!resolvedReceipt || !resolvedReceipt.blockNumber) { + return setTimeout(function () { + transactionReceiptAsync(txnHash, resolve, reject); + }, interval); + } + try { + const block = await web3.eth.getBlock(resolvedReceipt.blockNumber); + const current = await web3.eth.getBlock('latest'); + if (current.number - block.number >= blocksToWait) { + const txn = await web3.eth.getTransaction(txnHash); + // eslint-disable-next-line max-depth + if (txn.blockNumber !== null) { + return resolve(resolvedReceipt); + } + return reject(new Error('Transaction with hash: ' + txnHash + ' ended up in an uncle block.')); + } + return setTimeout(function () { + transactionReceiptAsync(txnHash, resolve, reject); + }, interval); + } catch (e) { + setTimeout(function () { + transactionReceiptAsync(txnHash, resolve, reject); + }, interval); + } + } else resolve(receipt); + + } catch (e) { + reject(e); + } + }; + if (Array.isArray(txnHash)) { + const promises = []; + txnHash.forEach(function (oneTxHash) { + promises.push(confirmTransaction(web3, oneTxHash, options)); + }); + return Promise.all(promises); + } + return new Promise(function (resolve, reject) { + transactionReceiptAsync(txnHash, resolve, reject); + }); +} + +export function selectUtxos(utxos, amount, currency, includeFee) { + // Filter by desired currency and sort in descending order + const sorted = utxos + .filter(utxo => utxo.currency === currency) + .sort((a, b) => new BigNumber(b.amount).sub(new BigNumber(a.amount))); + + if (sorted) { + const selected = []; + let currentBalance = new BigNumber(0); + for (let i = 0; i < Math.min(sorted.length, 4); i++) { + selected.push(sorted[i]); + currentBalance.iadd(new BigNumber(sorted[i].amount)); + if (currentBalance.gte(new BigNumber(amount))) { + break; + } + } + + if (currentBalance.gte(new BigNumber(amount))) { + if (includeFee) { + // Find the first ETH utxo (that's not selected) + const ethUtxos = utxos.filter( + utxo => utxo.currency === transaction.ETH_CURRENCY + ); + const feeUtxo = ethUtxos.find(utxo => utxo !== selected); + if (!feeUtxo) { + throw new Error(`Can't find a fee utxo for transaction`); + } else { + selected.push(feeUtxo); + } + } + return selected; + } + } +} + +export function signTypedData (web3, signer, data) { + return web3.currentProvider.send('eth_signTypedData_v3', [signer, data]); +} + +export function normalizeUrl (url) { + if(!url.endsWith("/")) { + url += "/"; + } + return url; +} diff --git a/yarn.lock b/yarn.lock index 2bc6a2a..6a66c73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -694,29 +694,29 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" -"@omisego/omg-js-childchain@1.2.1", "@omisego/omg-js-childchain@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@omisego/omg-js-childchain/-/omg-js-childchain-1.2.1.tgz#7fd83af2e47ae7936fd9743c5a98244c89f64222" - integrity sha512-UuYc0w8xTZPceDUnuWXV46MhPMUmu9+ecTbEh0sd5YSx9N9ie+t2FRikvvTH9g4+GBmQRoI0XCkFBU/pW3SJkA== +"@omisego/omg-js-childchain@2.0.0-v0.2", "@omisego/omg-js-childchain@^2.0.0-v0.2": + version "2.0.0-v0.2" + resolved "https://registry.yarnpkg.com/@omisego/omg-js-childchain/-/omg-js-childchain-2.0.0-v0.2.tgz#d2c2e1af48a8c00a68902db6107e1da824701b86" + integrity sha512-hz9U2xPg/xFbdBxUIqXfDjfA8JKIegMnG757d6b3h3Ot2kGvPL+0GK59JoMYwOG64J5uaco5HZ7NnnGfjQ5Aqw== dependencies: - "@omisego/omg-js-util" "^1.2.1" + "@omisego/omg-js-util" "^2.0.0-v0.2" debug "^4.0.1" json-bigint "^0.3.0" node-fetch "^2.2.0" rlp "^2.1.0" -"@omisego/omg-js-rootchain@1.2.2", "@omisego/omg-js-rootchain@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@omisego/omg-js-rootchain/-/omg-js-rootchain-1.2.2.tgz#630ad267f0ad6b2e44098790be9acb8816413032" - integrity sha512-vgyVfUDnyVeoe0XUv7hM13kHXqdJyEghqHEV07GyTr69QfzbFfTe9jzMceLAb5f+4Y/E5gLgU1Vqlt7lNGctUQ== +"@omisego/omg-js-rootchain@2.0.0-v0.2", "@omisego/omg-js-rootchain@^2.0.0-v0.2": + version "2.0.0-v0.2" + resolved "https://registry.yarnpkg.com/@omisego/omg-js-rootchain/-/omg-js-rootchain-2.0.0-v0.2.tgz#05ebbe6ee4e583a25f26c041a8d52b1084857b8c" + integrity sha512-QRsipPvozaImfO8ifPOh9w/GmOHT9hr9mdBWtRtZ3AqBOru10QG9gHF9vSQTsCDjr0jsAnoqHC/s/wuuDVfvbg== dependencies: - "@omisego/omg-js-util" "^1.2.1" + "@omisego/omg-js-util" "^2.0.0-v0.2" debug "^4.0.1" -"@omisego/omg-js-util@1.2.1", "@omisego/omg-js-util@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@omisego/omg-js-util/-/omg-js-util-1.2.1.tgz#7495f6835681a3096cc54dabb8c0495bc37d22ec" - integrity sha512-14YTB/hycMSgGnZ/SLKiu0KA9qqwc7mTvyGfO6VE2DonX6uDrYRqmbWX0wDnk3A1hWoVLPiqG7CLBNbkOnhsKg== +"@omisego/omg-js-util@2.0.0-v0.2", "@omisego/omg-js-util@^2.0.0-v0.2": + version "2.0.0-v0.2" + resolved "https://registry.yarnpkg.com/@omisego/omg-js-util/-/omg-js-util-2.0.0-v0.2.tgz#30b5882cc8a45446e7206576240caade614c8590" + integrity sha512-J5J5Q2XC7ZkpfQJiXJxii/66Tn3x4rhnhky3BmL++XEBoK6I34wgWMs/7dzsejWNHmmhGv/M/OZb+QBI+HlvlA== dependencies: eth-sig-util "^2.1.1" ethereumjs-util "^6.0.0" @@ -724,19 +724,14 @@ number-to-bn "^1.7.0" rlp "^2.2.2" -"@omisego/omg-js@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@omisego/omg-js/-/omg-js-1.2.2.tgz#3d7b8a179953307f1d34a321730572760f21b4e0" - integrity sha512-nnaL80FEtv+4yAocXV9qyJr3yNOGKdVNFiB2ehIdHuEx3YTy5yPc7+E4RqQSYcCm3iev7GdxTtSd9bSXGZ2lNQ== +"@omisego/omg-js@2.0.0-v0.2": + version "2.0.0-v0.2" + resolved "https://registry.yarnpkg.com/@omisego/omg-js/-/omg-js-2.0.0-v0.2.tgz#cd50f0e2ccc4beca75b0e01b9b1ad2a126ec3103" + integrity sha512-eMAjn50+bX2uyzghlyXbSFV/2tcAA5wqD8Q3pZTXvUT9U6QZBcfsu6fUTV56vNJT8KqAdCl2Rma3PKeB80IB9Q== dependencies: - "@omisego/omg-js-childchain" "^1.2.1" - "@omisego/omg-js-rootchain" "^1.2.2" - "@omisego/omg-js-util" "^1.2.1" - -"@types/node@^10.3.2": - version "10.14.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.7.tgz#1854f0a9aa8d2cd6818d607b3d091346c6730362" - integrity sha512-on4MmIDgHXiuJDELPk1NFaKVUxxCFr37tm8E9yN6rAiF5Pzp/9bBfBHkoexqRiY+hk/Z04EJU9kKEb59YqJ82A== + "@omisego/omg-js-childchain" "^2.0.0-v0.2" + "@omisego/omg-js-rootchain" "^2.0.0-v0.2" + "@omisego/omg-js-util" "^2.0.0-v0.2" abbrev@1: version "1.1.1" @@ -760,11 +755,6 @@ acorn@^5.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= - ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" @@ -880,24 +870,11 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/async/-/async-3.0.1.tgz#dfeb34657d1e63c94c0eee424297bf8a2c9a8182" - integrity sha512-ZswD8vwPtmBZzbn9xyi8XBQWXH3AvOQ43Za1KWYq7JeycrZuUYzx01KvHcVbXltjqH4y0MWrQ33008uLTqXuDw== - atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -axios@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" - integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== - dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" - babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1348,13 +1325,6 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1451,16 +1421,6 @@ electron-to-chromium@^1.3.137: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.139.tgz#17a149701d934bbb91d2aa4ae09e5270c38dc0ff" integrity sha512-8cR7h6doIC/XLgPdsTM3BXpfWLzqrHS6jWrvWLsdZWZWFvVQQUJTbU/wUZsjRGK33OY5ZIiS1n6JbqowuWrmYg== -elliptic@6.3.3: - version "6.3.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" - integrity sha1-VILZZG1UvLif19mU/J4ulWiHbj8= - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - inherits "^2.0.1" - elliptic@^6.4.0, elliptic@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" @@ -1658,22 +1618,6 @@ ethereumjs-util@^6.0.0: safe-buffer "^5.1.1" secp256k1 "^3.0.1" -ethers@4.0.28: - version "4.0.28" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.28.tgz#74d9acb57f4ede3337c8d60476b38d0fe646af01" - integrity sha512-5JTHrPoFLqf+xCAI3pKwXSOgWBSJJoAUdPtPLr1ZlKbSKiIFMkPlRNovmZS3jhIw5sHW1YoVWOaJ6ZR2gKRbwg== - dependencies: - "@types/node" "^10.3.2" - aes-js "3.0.0" - bn.js "^4.4.0" - elliptic "6.3.3" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.4" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - ethjs-util@0.1.6, ethjs-util@^0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" @@ -1796,13 +1740,6 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -1967,14 +1904,6 @@ hash-base@^3.0.0: inherits "^2.0.1" safe-buffer "^5.0.1" -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" @@ -2110,11 +2039,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -2285,11 +2209,6 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== -js-sha3@0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= - js-sha3@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.6.1.tgz#5b89f77a7477679877f58c4a075240934b1f95c0" @@ -3158,11 +3077,6 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scrypt-js@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" - integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== - secp256k1@^3.0.1: version "3.7.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.0.tgz#e85972f847b586cc4b2acd69497d3f80afaa7505" @@ -3212,11 +3126,6 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" - integrity sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48= - sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -3604,11 +3513,6 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" - integrity sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w= - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -3648,11 +3552,6 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -xmlhttprequest@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= - yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"