From afbf565dda006158f6f1397d8ea645fa6d307eff Mon Sep 17 00:00:00 2001 From: Aaron Barnard Date: Tue, 6 Aug 2019 12:01:08 +1000 Subject: [PATCH] Release Version 0.10.0 (#364) * Remove transaction receipt from logs to server * Update docs to include tx receipt * Add documentation on fname minification * Throw human friendly error when a Truffle contract is ID'd as a web3 contract * Support web3.js v1.2.0 * update Assist onboarding to recognize hardware wallets * disable web3 tests temporarily due to non-determinism * Reduce fragility of web3.test.js * Improve error handling for transactions, add notification for low gas error * Revert "Improve error handling for transactions, add notification for low gas error" This reverts commit 787648d436024c2bd205bc54b1c52a67569e23a1. * Improve error handling for transactions, add notification for low gas error * Increment version * Remove nonce from txStallPending message as it hasn't been received from the server, update snapshot * Use try catch to be able to log if txStall custom message received to avoid breaking change * Change version to 0.10.0 --- README.md | 108 +- multidep.json | 8 +- package.json | 2 +- src/__e2e-tests__/index.test.js | 4 +- .../initialization/initialization.test.js | 6 +- .../__snapshots__/index.test.js.snap | 116 +- .../ui-rendering/event-definitions.js | 20 +- .../contract/__snapshots__/index.test.js.snap | 1328 +++++++++++++++++ src/__tests__/js/contract/index.test.js | 2 +- src/__tests__/js/web3.test.js | 28 +- src/js/helpers/events.js | 7 + src/js/helpers/state.js | 3 +- src/js/helpers/utilities.js | 27 +- src/js/helpers/validation.js | 143 +- src/js/helpers/web3.js | 130 +- src/js/helpers/websockets.js | 14 +- src/js/index.js | 19 + src/js/logic/send-transaction.js | 96 +- src/js/logic/user.js | 4 +- src/js/views/content.js | 10 +- src/js/views/event-to-ui.js | 15 +- 21 files changed, 1858 insertions(+), 232 deletions(-) diff --git a/README.md b/README.md index 8b4c3303..db87ecdb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ Takes care of onboarding your users, keeping them informed about transaction status and comprehensive usage analytics with minimal -setup. Supports `web3.js` versions `0.20` and `1.0`, `ethers.js` versions `^4.0.20` and `^5.0-beta-137` +setup. Supports `web3.js` versions `0.20`, `1.0.0-beta`, `1.2.0`, `ethers.js` versions `^4.0.20` and `^5.0-beta-137` -_note: `web3.js` 1.0.0 beta versions 38, 39, 40, 41, 42, 43, 44, 45 have bugs when interacting with MetaMask, we recommend you avoid these versions of `web3.js`_ +_note: `web3.js` 1.0.0-beta versions 38, 39, 40, 41, 42, 43, 44, 45 have bugs when interacting with MetaMask, we recommend you avoid these versions of `web3.js`_ ## Preview @@ -43,7 +43,7 @@ yarn add bnc-assist #### Script Tag The library uses [semantic versioning](https://semver.org/spec/v2.0.0.html). -The current version is 0.9.6. +The current version is 0.10.0. There are minified and non-minified versions. Put this script at the top of your `` @@ -62,13 +62,13 @@ is as follows: ```javascript var bncAssistConfig = { - dappId: apiKey, // [String] The API key created on https://account.blocknative.com + dappId: apiKey, // [String] The API key created on https://account.blocknative.com - networkId: networkId // [Integer] The network ID of the Ethereum network your dapp is deployed on. - // See below for instructions on how to setup for local blockchains. -}; + networkId: networkId // [Integer] The network ID of the Ethereum network your dapp is deployed on. + // See below for instructions on how to setup for local blockchains. +} -var assistInstance = assist.init(bncAssistConfig); +var assistInstance = assist.init(bncAssistConfig) ``` ### Call `onboard` @@ -80,7 +80,8 @@ load. Others may wait until loading certain pages or until a certain button is c In any event, it is as simple as calling: ```javascript -assistInstance.onboard() +assistInstance + .onboard() .then(function(state) { // User has been successfully onboarded and is ready to transact // Will resolve with the current state of the user @@ -120,7 +121,6 @@ var myDecoratedContract = assistInstance.Contract(myContract) // and then replace `myContract` with `myDecoratedContract` // throughout your app // ... - ``` You can then use `myDecoratedContract` instead of `myContract`. @@ -159,6 +159,19 @@ Pass this instance in to the config (even if it is undefined). If the user didn' If you _don't_ include your instantiated Web3 instance in the config, Assist will grab `web3` from the window object if it is available. However this can cause issues as `web3` isn't always added to the window object (ie on some mobile wallets) and the version of `web3` that is usually attached to the window object is `0.20`. So if you happen to be using `1.0` but didn't pass it in, then your contracts won't be decorated correctly. +### Truffle Contracts and minification + +For assist.js to work correctly with Truffle contracts, you must not minify function names (fnames) in your build. + +Instructions on how to disable minification of fnames: + +- [Terser](https://github.com/terser-js/terser#minify-options) +- [Uglify](https://github.com/mishoo/UglifyJS2#minify-options) +- [Webpack terser plugin](https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions) +- [Webpack uglify plugin](https://github.com/webpack-contrib/uglifyjs-webpack-plugin#uglifyoptions) +- [Rollup terser plugin](https://github.com/TrySound/rollup-plugin-terser#options) +- [Rollup uglify plugin](https://github.com/TrySound/rollup-plugin-uglify#options) + ## API Reference ### Config @@ -180,7 +193,8 @@ var config = { txSent: Function, // Transaction has been sent to the network txPending: Function, // Transaction is pending and has been detected in the mempool txSendFail: Function, // Transaction failed to be sent to the network - txStall: Function, // Transaction was sent but not confirmed in the blockchain after 30 secs + txStallPending: Function, // Transaction was sent to the network but has not been detected in the txPool + txStallConfirmed: Function, // Transaction has been detected in the mempool but hasn't been confirmed txFailed: Function, // Transaction failed nsfFail: Function, // User doesn't have enough funds to complete transaction txRepeat: Function, // Warning to user that they might be repeating a transaction @@ -206,7 +220,8 @@ var config = { }, handleNotificationEvent: Function // Called on every tx notification event with a transaction event object timeouts: { - txStall: Number // The number of milliseconds after a transaction has been sent before showing a stall notification if not confirmed in the blockchain + txStallPending: Number // The number of milliseconds after a transaction has been sent before showing a stall notification detected in the mempool + txStallConfirmed: Number // The number of milliseconds after a transaction has been detected in the mempool before showing a stall notification if not confirmed }, recommendedWallets: { desktop: Array, // Array of Objects that define wallets this dapp supports on desktop to users that don't have a wallet @@ -274,7 +289,8 @@ The function that is defined on the `handleNotificationEvent` property of the co to: String, // the address the transaction was sent to value: String // the value of the transaction hash: String // the transaction hash (updated to a new hash if transaction is sped up or cancelled) - originalHash: String // if transaction was sped up or cancelled, the original transaction hash + originalHash: String, // if transaction was sped up or cancelled, the original transaction hash + receipt: Object || undefined // Will be an object on a txConfirmedClient event. Is the receipt object that is received from web3 or ethers }, wallet: { address: String, // the account address of the wallet in use @@ -292,7 +308,7 @@ You can then decide whether you would like a notification to be shown for this e The list of event codes that are included in the object that `handleNotificationEvent` is called with are the same as the list included in the `messages` object that is passed to the config with one addition: ```javascript - txConfirmedClient: String // called when a client confirmation is received from the provider +txConfirmedClient: String // called when a client confirmation is received from the provider ``` This additional event is used to notify transaction confirmation if a `txConfirmed` was not already received. Whichever of `txConfirmed` and `txConfirmedClient` is received first should be used for notification. @@ -325,7 +341,8 @@ Custom transaction messages can be set to override the default messages `Assist` gasPrice: String, // Gas price (wei) hash: String, // The transaction hash nonce: Number, // The transaction nonce - value: String // The value of the transaction (wei) + value: String, // The value of the transaction (wei) + receipt: Object || undefined // Will be an object on txConfirmedClient event }, contract: { // This object will be undefined if it is not a contract transaction @@ -360,13 +377,19 @@ Sometimes you want more granular control over the transaction messages and you h ```javascript // 0.2 style send -myContract.vote(param1, param2, options, callback, {messages: {txPending: () => `Voting for ${param1} in progress`}}) +myContract.vote(param1, param2, options, callback, { + messages: { txPending: () => `Voting for ${param1} in progress` } +}) // 1.0 style send -myContract.vote(param1, param2).send(options, {messages: {txPending: () => `Voting for ${param1} in progress`}}) +myContract.vote(param1, param2).send(options, { + messages: { txPending: () => `Voting for ${param1} in progress` } +}) // Transaction -Transaction(txObject, callback, {messages: {txPending: () => 'Sending ETH...'}}) +Transaction(txObject, callback, { + messages: { txPending: () => 'Sending ETH...' } +}) ``` The `messages` object _must_ always be the _last_ argument provided to the send method for it to be recognized. @@ -377,7 +400,7 @@ You can also add click handler functions to a transaction that will be executed ```javascript myContract.vote(param1, param2, options, callback, { - messages: {txPending: () => `Voting for ${param1} in progress`}, + messages: { txPending: () => `Voting for ${param1} in progress` }, clickHandlers: { txPending: () => route('./votes'), // can specify a click handler for specific event codes which takes precedence onclick: () => console.log('this is the global click handler') // or you can specify a onclick function which will run for every event for this transaction that doesn't have a click handler specified @@ -410,7 +433,7 @@ The available ids for the `networkId` property of the config object: - `4`: rinkeby testnet - `5`: goerli testnet -*The kovan testnet is not supported.* +_The kovan testnet is not supported._ #### Local Networks @@ -433,11 +456,11 @@ state = { accountBalance: String, // User account balance minimumBalance: String, // User has the minimum balance specified in the config userCurrentNetworkId: Number, // Network id of the network the user is currently on - correctNetwork: Boolean, // User is on the network specified in the config + correctNetwork: Boolean // User is on the network specified in the config } ``` -The promises that are returned from calls to `getState` and `onboard` resolve and reject with this `state` object. +The promises that are returned from calls to `getState` and `onboard` resolve and reject with this `state` object. ### Errors @@ -519,6 +542,7 @@ If you would like to define which wallets your dapp works with and recommends to #### Assist currently only supports the following wallets: ##### Desktop + - MetaMask - link: https://metamask.io/img/metamask.png - icon: https://metamask.io/img/metamask.png @@ -527,6 +551,7 @@ If you would like to define which wallets your dapp works with and recommends to - icon: https://images-na.ssl-images-amazon.com/images/I/71Y2mhDkBNL.png ##### Mobile + - Opera Touch - link: https://www.opera.com/mobile/touch - icon: https://apps.goodereader.com/wp-content/uploads/icons/1525044654.png @@ -572,7 +597,8 @@ var assistInstance = assist.init(assistConfig) #### Example ```javascript -assistInstance.onboard() +assistInstance + .onboard() .then(function(state) { // User has been successfully onboarded and is ready to transact }) @@ -639,7 +665,8 @@ const notificationOptions = { #### Example ```javascript -assistInstance.Transaction(txObject) +assistInstance + .Transaction(txObject) .then(txHash => { // Transaction has been sent to the network }) @@ -647,8 +674,8 @@ assistInstance.Transaction(txObject) console.log(error.message) // => 'User has insufficient funds' }) - // you can alternatively pass in a transaction hash to get Assist's notifications for a transaction that has already been sent to the network - assistInstance.Transaction(hash) +// you can alternatively pass in a transaction hash to get Assist's notifications for a transaction that has already been sent to the network +assistInstance.Transaction(hash) ``` ### `getState()` @@ -662,12 +689,11 @@ assistInstance.Transaction(txObject) #### Example ```javascript -assistInstance.getState() - .then(function(state) { - if (state.validBrowser) { - console.log('valid browser') - } - }) +assistInstance.getState().then(function(state) { + if (state.validBrowser) { + console.log('valid browser') + } +}) ``` ### `updateStyle(style)` @@ -678,9 +704,9 @@ assistInstance.getState() ```javascript var style = { - darkMode: Boolean, // Set Assist UI to dark mode - css: String, // Custom css string to overide Assist default styles - notificationsPosition: String || Object, // Defines which corner transaction notifications will be positioned. See 'Notification Positioning' + darkMode: Boolean, // Set Assist UI to dark mode + css: String, // Custom css string to overide Assist default styles + notificationsPosition: String || Object // Defines which corner transaction notifications will be positioned. See 'Notification Positioning' } ``` @@ -708,7 +734,7 @@ Trigger a custom UI notification #### Parameters -`type` - `String`: One of: ['success', 'pending', 'error'] (**Required**) +`type` - `String`: One of: ['success', 'pending', 'error'](**Required**) `message` - `String`: The message to display in the notification. HTML can be embedded in the string. (**Required**) @@ -734,11 +760,17 @@ options.customTimeout defaults: { success: 2000, pending: 5000, error: 5000 } ```javascript // Display a success notification with an embedded link for 5000ms -assistInstance.notify('success', 'Operation was a success! Click here to view more', { customTimeout: 5000 }); +assistInstance.notify( + 'success', + 'Operation was a success! Click here to view more', + { customTimeout: 5000 } +) // Display a pending notification, load data from an imaginary backend // and dismiss the pending notification only when the data is loaded -var dismiss = assistInstance.notify('pending', 'Loading data...', { customTimeout: -1 }); +var dismiss = assistInstance.notify('pending', 'Loading data...', { + customTimeout: -1 +}) myEventEmitter.emit('fetch-data-from-backend') myEventEmitter.on('data-from-backend-loaded', () => { dismiss() diff --git a/multidep.json b/multidep.json index 6e7db0df..b21094c6 100644 --- a/multidep.json +++ b/multidep.json @@ -1,6 +1,12 @@ { "path": "multidep_modules", "versions": { - "web3": ["1.0.0-beta.55", "1.0.0-beta.46", "1.0.0-beta.35", "0.20.6"] + "web3": [ + "1.2.0", + "1.0.0-beta.55", + "1.0.0-beta.46", + "1.0.0-beta.35", + "0.20.6" + ] } } diff --git a/package.json b/package.json index 7debe41f..9e70b1d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bnc-assist", - "version": "0.9.6", + "version": "0.10.0", "description": "Blocknative Assist js library for Dapp developers", "main": "lib/assist.min.js", "scripts": { diff --git a/src/__e2e-tests__/index.test.js b/src/__e2e-tests__/index.test.js index 9743f617..6bacc304 100644 --- a/src/__e2e-tests__/index.test.js +++ b/src/__e2e-tests__/index.test.js @@ -27,7 +27,7 @@ const getTruffleContract = async () => { const getWeb3Contract = async web3 => web3.eth.contract ? web3.eth.contract(abi).at(convertLibAddress) // 0.20 - : new web3.eth.Contract(abi, convertLibAddress) // 1.0.0-beta + : new web3.eth.Contract(abi, convertLibAddress) // 1.x // multidep docs: https://github.com/joliss/node-multidep multidepRequire.forEachVersion('web3', (version, Web3) => { @@ -49,7 +49,7 @@ multidepRequire.forEachVersion('web3', (version, Web3) => { }) const provider = version.includes('0.20') ? new Web3.providers.HttpProvider(`http://localhost:${port}`) // 0.20 - : `ws://localhost:${port}` // 1.0 + : `http://localhost:${port}` // 1.x web3 = new Web3(provider) window.web3 = web3 const config = { dappId: '123', web3, networkId: 5 } diff --git a/src/__integration-tests__/initialization/initialization.test.js b/src/__integration-tests__/initialization/initialization.test.js index cec182fd..5d02dd91 100644 --- a/src/__integration-tests__/initialization/initialization.test.js +++ b/src/__integration-tests__/initialization/initialization.test.js @@ -260,7 +260,8 @@ describe('init is called', () => { txSent: () => {}, txPending: () => {}, txSendFail: () => {}, - txStall: () => {}, + txStallPending: () => {}, + txStallConfirmed: () => {}, txFailed: () => {}, nsfFail: () => {}, txRepeat: () => {}, @@ -285,7 +286,8 @@ describe('init is called', () => { css: '123' }, timeouts: { - txStall: 1 + txStallPending: 1, + txStallConfirmed: 1 } } test(`should not throw`, () => { diff --git a/src/__integration-tests__/ui-rendering/__snapshots__/index.test.js.snap b/src/__integration-tests__/ui-rendering/__snapshots__/index.test.js.snap index a7d8f1c2..8ca5ff95 100644 --- a/src/__integration-tests__/ui-rendering/__snapshots__/index.test.js.snap +++ b/src/__integration-tests__/ui-rendering/__snapshots__/index.test.js.snap @@ -432,10 +432,10 @@ exports[`dom-rendering event activeContract-txSpeedUp should trigger correct DOM " `; -exports[`dom-rendering event activeContract-txStall should trigger correct DOM render [Custom state 0] 1`] = ` +exports[`dom-rendering event activeContract-txStallConfirmed should trigger correct DOM render [Custom state 0] 1`] = ` " -
  • +
    • @@ -444,7 +444,7 @@ exports[`dom-rendering event activeContract-txStall should trigger correct DOM r
      -

      Your transaction ID: 1235 has stalled

      +

      Your transaction ID: 1235 has stalled and hasn't been confirmed

      12:00 AM - @@ -456,10 +456,58 @@ exports[`dom-rendering event activeContract-txStall should trigger correct DOM r

    " `; -exports[`dom-rendering event activeContract-txStall should trigger correct DOM render [Custom state 1] 1`] = ` +exports[`dom-rendering event activeContract-txStallConfirmed should trigger correct DOM render [Custom state 1] 1`] = ` " -
    • +
      • + +
        +
        + You will be notified when this transaction is completed. +
        +
        +
        +
        +

        txStall custom msg

        +

        + 12:00 AM + - + + 606 min + +

        +
        +
      " +`; + +exports[`dom-rendering event activeContract-txStallPending should trigger correct DOM render [Custom state 0] 1`] = ` +" + +
      • + +
        +
        + You will be notified when this transaction is completed. +
        +
        +
        +
        +

        Your transaction has stalled and has not entered the transaction pool

        +

        + 12:00 AM + - + + 606 min + +

        +
        +
      " +`; + +exports[`dom-rendering event activeContract-txStallPending should trigger correct DOM render [Custom state 1] 1`] = ` +" + +
      • @@ -1534,10 +1582,58 @@ exports[`dom-rendering event activeTransaction-txSpeedUp should trigger correct
      " `; -exports[`dom-rendering event activeTransaction-txStall should trigger correct DOM render [Custom state 0] 1`] = ` +exports[`dom-rendering event activeTransaction-txStallConfirmed should trigger correct DOM render [Custom state 0] 1`] = ` +" + +
      • + +
        +
        + You will be notified when this transaction is completed. +
        +
        +
        +
        +

        Your transaction ID: 1235 has stalled and hasn't been confirmed

        +

        + 12:00 AM + - + + 606 min + +

        +
        +
      " +`; + +exports[`dom-rendering event activeTransaction-txStallConfirmed should trigger correct DOM render [Custom state 1] 1`] = ` +" + +
      • + +
        +
        + You will be notified when this transaction is completed. +
        +
        +
        +
        +

        txStall custom msg

        +

        + 12:00 AM + - + + 606 min + +

        +
        +
      " +`; + +exports[`dom-rendering event activeTransaction-txStallPending should trigger correct DOM render [Custom state 0] 1`] = ` " -
      • +
        • @@ -1546,7 +1642,7 @@ exports[`dom-rendering event activeTransaction-txStall should trigger correct DO
          -

          Your transaction ID: 1235 has stalled

          +

          Your transaction has stalled and has not entered the transaction pool

          12:00 AM - @@ -1558,10 +1654,10 @@ exports[`dom-rendering event activeTransaction-txStall should trigger correct DO

        " `; -exports[`dom-rendering event activeTransaction-txStall should trigger correct DOM render [Custom state 1] 1`] = ` +exports[`dom-rendering event activeTransaction-txStallPending should trigger correct DOM render [Custom state 1] 1`] = ` " -
        • +
          • diff --git a/src/__integration-tests__/ui-rendering/event-definitions.js b/src/__integration-tests__/ui-rendering/event-definitions.js index 356f8810..8a5e64e3 100644 --- a/src/__integration-tests__/ui-rendering/event-definitions.js +++ b/src/__integration-tests__/ui-rendering/event-definitions.js @@ -225,13 +225,29 @@ export default { { config: { messages: { txSent: () => 'txSent custom msg' }, style: {} } } ] }, - txStall: { + txStallPending: { categories: ['activeTransaction', 'activeContract'], params: { transaction: mockTxFactory({ nonce: true, startTime: true }) }, customStates: [ initialState, { - config: { messages: { txStall: () => 'txStall custom msg' }, style: {} } + config: { + messages: { txStallPending: () => 'txStall custom msg' }, + style: {} + } + } + ] + }, + txStallConfirmed: { + categories: ['activeTransaction', 'activeContract'], + params: { transaction: mockTxFactory({ nonce: true, startTime: true }) }, + customStates: [ + initialState, + { + config: { + messages: { txStallConfirmed: () => 'txStall custom msg' }, + style: {} + } } ] }, diff --git a/src/__tests__/js/contract/__snapshots__/index.test.js.snap b/src/__tests__/js/contract/__snapshots__/index.test.js.snap index 63329de3..7e9cde95 100644 --- a/src/__tests__/js/contract/__snapshots__/index.test.js.snap +++ b/src/__tests__/js/contract/__snapshots__/index.test.js.snap @@ -10721,3 +10721,1331 @@ Object { }, } `; + +exports[`using web3 1.2.0 Contract is called with a truffle contract it doesn't fail and returns the expected decorated contract 1`] = ` +Object { + "BatchRequest": undefined, + "_jsonInterface": undefined, + "abiModel": undefined, + "events": Object { + "contract": null, + }, + "givenProvider": undefined, + "methods": Object { + "convert(uint256,uint256)": [Function], + "subtract(uint256,uint256)": [Function], + }, + "options": undefined, +} +`; + +exports[`using web3 1.2.0 Contract is called with a web3 contract it doesn't fail and returns the expected decorated contract 1`] = ` +Object { + "BatchRequest": [Function], + "_jsonInterface": Array [ + Object { + "constant": true, + "inputs": Array [], + "name": "name", + "outputs": Array [ + Object { + "name": "", + "type": "bytes32", + }, + ], + "payable": false, + "signature": "0x06fdde03", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [], + "name": "stop", + "outputs": Array [], + "payable": false, + "signature": "0x07da68f5", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "approve", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x095ea7b3", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "owner_", + "type": "address", + }, + ], + "name": "setOwner", + "outputs": Array [], + "payable": false, + "signature": "0x13af4035", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "totalSupply", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x18160ddd", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "transferFrom", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x23b872dd", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "decimals", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x313ce567", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "mint", + "outputs": Array [], + "payable": false, + "signature": "0x40c10f19", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "burn", + "outputs": Array [], + "payable": false, + "signature": "0x42966c68", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "name_", + "type": "bytes32", + }, + ], + "name": "setName", + "outputs": Array [], + "payable": false, + "signature": "0x5ac801fe", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + ], + "name": "balanceOf", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x70a08231", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "stopped", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x75f12b21", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "authority_", + "type": "address", + }, + ], + "name": "setAuthority", + "outputs": Array [], + "payable": false, + "signature": "0x7a9e5e4b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "owner", + "outputs": Array [ + Object { + "name": "", + "type": "address", + }, + ], + "payable": false, + "signature": "0x8da5cb5b", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "symbol", + "outputs": Array [ + Object { + "name": "", + "type": "bytes32", + }, + ], + "payable": false, + "signature": "0x95d89b41", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "burn", + "outputs": Array [], + "payable": false, + "signature": "0x9dc29fac", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "mint", + "outputs": Array [], + "payable": false, + "signature": "0xa0712d68", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "transfer", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0xa9059cbb", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "push", + "outputs": Array [], + "payable": false, + "signature": "0xb753a98c", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "move", + "outputs": Array [], + "payable": false, + "signature": "0xbb35783b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [], + "name": "start", + "outputs": Array [], + "payable": false, + "signature": "0xbe9a6555", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "authority", + "outputs": Array [ + Object { + "name": "", + "type": "address", + }, + ], + "payable": false, + "signature": "0xbf7e214f", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + ], + "name": "approve", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0xdaea85c5", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "guy", + "type": "address", + }, + ], + "name": "allowance", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0xdd62ed3e", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "pull", + "outputs": Array [], + "payable": false, + "signature": "0xf2d5d56b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": undefined, + "inputs": Array [ + Object { + "name": "symbol_", + "type": "bytes32", + }, + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Mint", + "payable": undefined, + "signature": "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Burn", + "payable": undefined, + "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "authority", + "type": "address", + }, + ], + "name": "LogSetAuthority", + "payable": undefined, + "signature": "0x1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada4", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "owner", + "type": "address", + }, + ], + "name": "LogSetOwner", + "payable": undefined, + "signature": "0xce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94", + "type": "event", + }, + Object { + "anonymous": true, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "sig", + "type": "bytes4", + }, + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": true, + "name": "foo", + "type": "bytes32", + }, + Object { + "indexed": true, + "name": "bar", + "type": "bytes32", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + Object { + "indexed": false, + "name": "fax", + "type": "bytes", + }, + ], + "name": "LogNote", + "payable": undefined, + "signature": "0x644843f351d3fba4abcd60109eaff9f54bac8fb8ccf0bab941009c21df21cf31", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "src", + "type": "address", + }, + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Approval", + "payable": undefined, + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "src", + "type": "address", + }, + Object { + "indexed": true, + "name": "dst", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Transfer", + "payable": undefined, + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "type": "event", + }, + ], + "abiModel": undefined, + "events": Object { + "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885": [Function], + "0x1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada4": [Function], + "0x644843f351d3fba4abcd60109eaff9f54bac8fb8ccf0bab941009c21df21cf31": [Function], + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": [Function], + "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5": [Function], + "0xce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94": [Function], + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": [Function], + "Approval": [Function], + "Approval(address,address,uint256)": [Function], + "Burn": [Function], + "Burn(address,uint256)": [Function], + "LogNote": [Function], + "LogNote(bytes4,address,bytes32,bytes32,uint256,bytes)": [Function], + "LogSetAuthority": [Function], + "LogSetAuthority(address)": [Function], + "LogSetOwner": [Function], + "LogSetOwner(address)": [Function], + "Mint": [Function], + "Mint(address,uint256)": [Function], + "Transfer": [Function], + "Transfer(address,address,uint256)": [Function], + "allEvents": [Function], + "contract": null, + }, + "givenProvider": null, + "methods": Object { + "allowance": [Function], + "allowance(address,address)": [Function], + "approve": [Function], + "approve(address)": [Function], + "approve(address,uint256)": [Function], + "authority": [Function], + "authority()": [Function], + "balanceOf": [Function], + "balanceOf(address)": [Function], + "burn": [Function], + "burn(address,uint256)": [Function], + "burn(uint256)": [Function], + "decimals": [Function], + "decimals()": [Function], + "mint": [Function], + "mint(address,uint256)": [Function], + "mint(uint256)": [Function], + "move": [Function], + "move(address,address,uint256)": [Function], + "name": [Function], + "name()": [Function], + "owner": [Function], + "owner()": [Function], + "pull": [Function], + "pull(address,uint256)": [Function], + "push": [Function], + "push(address,uint256)": [Function], + "setAuthority": [Function], + "setAuthority(address)": [Function], + "setName": [Function], + "setName(bytes32)": [Function], + "setOwner": [Function], + "setOwner(address)": [Function], + "start": [Function], + "start()": [Function], + "stop": [Function], + "stop()": [Function], + "stopped": [Function], + "stopped()": [Function], + "symbol": [Function], + "symbol()": [Function], + "totalSupply": [Function], + "totalSupply()": [Function], + "transfer": [Function], + "transfer(address,uint256)": [Function], + "transferFrom": [Function], + "transferFrom(address,address,uint256)": [Function], + }, + "options": Object { + "address": "0x0000000000000000000000000000000000000000", + "jsonInterface": Array [ + Object { + "constant": true, + "inputs": Array [], + "name": "name", + "outputs": Array [ + Object { + "name": "", + "type": "bytes32", + }, + ], + "payable": false, + "signature": "0x06fdde03", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [], + "name": "stop", + "outputs": Array [], + "payable": false, + "signature": "0x07da68f5", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "approve", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x095ea7b3", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "owner_", + "type": "address", + }, + ], + "name": "setOwner", + "outputs": Array [], + "payable": false, + "signature": "0x13af4035", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "totalSupply", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x18160ddd", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "transferFrom", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x23b872dd", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "decimals", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x313ce567", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "mint", + "outputs": Array [], + "payable": false, + "signature": "0x40c10f19", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "burn", + "outputs": Array [], + "payable": false, + "signature": "0x42966c68", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "name_", + "type": "bytes32", + }, + ], + "name": "setName", + "outputs": Array [], + "payable": false, + "signature": "0x5ac801fe", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + ], + "name": "balanceOf", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0x70a08231", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "stopped", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0x75f12b21", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "authority_", + "type": "address", + }, + ], + "name": "setAuthority", + "outputs": Array [], + "payable": false, + "signature": "0x7a9e5e4b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "owner", + "outputs": Array [ + Object { + "name": "", + "type": "address", + }, + ], + "payable": false, + "signature": "0x8da5cb5b", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "symbol", + "outputs": Array [ + Object { + "name": "", + "type": "bytes32", + }, + ], + "payable": false, + "signature": "0x95d89b41", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "burn", + "outputs": Array [], + "payable": false, + "signature": "0x9dc29fac", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "mint", + "outputs": Array [], + "payable": false, + "signature": "0xa0712d68", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "transfer", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0xa9059cbb", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "push", + "outputs": Array [], + "payable": false, + "signature": "0xb753a98c", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "dst", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "move", + "outputs": Array [], + "payable": false, + "signature": "0xbb35783b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [], + "name": "start", + "outputs": Array [], + "payable": false, + "signature": "0xbe9a6555", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [], + "name": "authority", + "outputs": Array [ + Object { + "name": "", + "type": "address", + }, + ], + "payable": false, + "signature": "0xbf7e214f", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "guy", + "type": "address", + }, + ], + "name": "approve", + "outputs": Array [ + Object { + "name": "", + "type": "bool", + }, + ], + "payable": false, + "signature": "0xdaea85c5", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": true, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "guy", + "type": "address", + }, + ], + "name": "allowance", + "outputs": Array [ + Object { + "name": "", + "type": "uint256", + }, + ], + "payable": false, + "signature": "0xdd62ed3e", + "stateMutability": "view", + "type": "function", + }, + Object { + "constant": false, + "inputs": Array [ + Object { + "name": "src", + "type": "address", + }, + Object { + "name": "wad", + "type": "uint256", + }, + ], + "name": "pull", + "outputs": Array [], + "payable": false, + "signature": "0xf2d5d56b", + "stateMutability": "nonpayable", + "type": "function", + }, + Object { + "constant": undefined, + "inputs": Array [ + Object { + "name": "symbol_", + "type": "bytes32", + }, + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Mint", + "payable": undefined, + "signature": "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Burn", + "payable": undefined, + "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "authority", + "type": "address", + }, + ], + "name": "LogSetAuthority", + "payable": undefined, + "signature": "0x1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada4", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "owner", + "type": "address", + }, + ], + "name": "LogSetOwner", + "payable": undefined, + "signature": "0xce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94", + "type": "event", + }, + Object { + "anonymous": true, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "sig", + "type": "bytes4", + }, + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": true, + "name": "foo", + "type": "bytes32", + }, + Object { + "indexed": true, + "name": "bar", + "type": "bytes32", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + Object { + "indexed": false, + "name": "fax", + "type": "bytes", + }, + ], + "name": "LogNote", + "payable": undefined, + "signature": "0x644843f351d3fba4abcd60109eaff9f54bac8fb8ccf0bab941009c21df21cf31", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "src", + "type": "address", + }, + Object { + "indexed": true, + "name": "guy", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Approval", + "payable": undefined, + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "type": "event", + }, + Object { + "anonymous": false, + "constant": undefined, + "inputs": Array [ + Object { + "indexed": true, + "name": "src", + "type": "address", + }, + Object { + "indexed": true, + "name": "dst", + "type": "address", + }, + Object { + "indexed": false, + "name": "wad", + "type": "uint256", + }, + ], + "name": "Transfer", + "payable": undefined, + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "type": "event", + }, + ], + }, +} +`; diff --git a/src/__tests__/js/contract/index.test.js b/src/__tests__/js/contract/index.test.js index a31baace..96e7ece3 100644 --- a/src/__tests__/js/contract/index.test.js +++ b/src/__tests__/js/contract/index.test.js @@ -49,7 +49,7 @@ multidepRequire.forEachVersion('web3', (version, Web3) => { }) const provider = version.includes('0.20') ? new Web3.providers.HttpProvider(`http://localhost:${port}`) - : `ws://localhost${port}` + : `http://localhost${port}` web3 = new Web3(provider) config = { dappId: '123', web3, networkId: 1 } assistInstance = da.init(config) diff --git a/src/__tests__/js/web3.test.js b/src/__tests__/js/web3.test.js index 386839d6..43fa8bfe 100644 --- a/src/__tests__/js/web3.test.js +++ b/src/__tests__/js/web3.test.js @@ -1,5 +1,4 @@ import truffleContract from 'truffle-contract' -import da from '~/js' import abi from '~/__tests__/res/dstoken.json' import { initialState, updateState } from '~/js/helpers/state' import * as websockets from '~/js/helpers/websockets' @@ -18,8 +17,8 @@ const Web3v0p20 = multidepRequire('web3', '0.20.6') const zeroAddress = '0x0000000000000000000000000000000000000000' const initWeb3 = (simpleVersion, Web3) => { - if (simpleVersion === '1.0') { - return new Web3(`ws://localhost:${port}`) + if (simpleVersion === '1.') { + return new Web3(`http://localhost:${port}`) } const provider = new Web3.providers.HttpProvider(`http://localhost:${port}`) return new Web3(provider) @@ -30,7 +29,6 @@ describe(`web3.js tests`, () => { describe(`using web3 ${version}`, () => { describe('assist is initialised correctly', () => { let web3 - let config let simpleVersion beforeEach(() => { jest @@ -39,22 +37,20 @@ describe(`web3.js tests`, () => { jest .spyOn(websockets, 'checkForSocketConnection') .mockImplementation(() => Promise.resolve(true)) - simpleVersion = version.slice(0, 3) + simpleVersion = version.slice(0, 2) web3 = initWeb3(simpleVersion, Web3) - config = { dappId: '123', web3, networkId: 5 } - da.init(config) - }) - afterEach(() => { - // need to close any websocket connection - if (simpleVersion === '1.0') { - web3.currentProvider.connection.close() - } + + updateState({ + web3Instance: web3, + legacyWeb3: simpleVersion === '0.' + }) }) + describe('web3Functions', () => { describe('networkId', () => { test('should return the expected networkId', async () => { const networkId = await web3Functions.networkId(simpleVersion)() - if (simpleVersion === '1.0') expect(networkId).toEqual(5) + if (simpleVersion === '1.') expect(networkId).toEqual(5) else expect(networkId).toEqual('5') // 0.20 returns networkId as a string }) }) @@ -145,7 +141,7 @@ describe(`web3.js tests`, () => { describe('accounts', () => { test(`should return the correct list of accounts`, async () => { const expected = - simpleVersion === '1.0' + simpleVersion === '1.' ? accounts : accounts.map(a => a.toLowerCase()) const res = await web3Functions.accounts(simpleVersion)() @@ -155,7 +151,7 @@ describe(`web3.js tests`, () => { describe('txReceipt', () => { test(`should return the correct receipt`, async () => { const hash = await new Promise(resolve => { - if (simpleVersion === '1.0') { + if (simpleVersion === '1.') { web3.eth .sendTransaction({ from: accounts[0], diff --git a/src/js/helpers/events.js b/src/js/helpers/events.js index ec030c34..8e88735b 100644 --- a/src/js/helpers/events.js +++ b/src/js/helpers/events.js @@ -23,6 +23,13 @@ export function handleEvent(eventObj, modalClickHandlers) { let eventToLog = { ...event } + // remove receipt from what is sent to the server as it causes errors + if (eventToLog.transaction && eventToLog.transaction.receipt) { + const { transaction, ...rest } = eventToLog + const { receipt, ...txDetails } = transaction + eventToLog = { ...rest, transaction: txDetails } + } + // If dealing with a custom notification the logged event // should have it's event and category code changed if (categoryCode === 'userInitiatedNotify') { diff --git a/src/js/helpers/state.js b/src/js/helpers/state.js index 8f67a876..f278d5cb 100644 --- a/src/js/helpers/state.js +++ b/src/js/helpers/state.js @@ -37,7 +37,8 @@ export const initialState = { iframeDocument: null, iframeWindow: null, connectionId: null, - onboardPromise: null + onboardPromise: null, + nodeSynced: true } export let state = { ...initialState } diff --git a/src/js/helpers/utilities.js b/src/js/helpers/utilities.js index f073d427..ad319ee1 100644 --- a/src/js/helpers/utilities.js +++ b/src/js/helpers/utilities.js @@ -132,8 +132,24 @@ export function assistLog(log) { } export function extractMessageFromError(message) { - const str = message.split('"message":')[1] - return str.split('"')[1] + if (message.includes('User denied transaction signature')) { + return { + eventCode: 'txSendFail', + errorMsg: 'User denied transaction signature' + } + } + + if (message.includes('transaction underpriced')) { + return { + eventCode: 'txUnderpriced', + errorMsg: 'Transaction is under priced' + } + } + + return { + eventCode: 'txError', + errorMsg: message + } } export function eventCodeToType(eventCode) { @@ -141,7 +157,8 @@ export function eventCodeToType(eventCode) { case 'txRequest': case 'txPending': case 'txSent': - case 'txStall': + case 'txStallPending': + case 'txStallConfirmed': case 'txSpeedUp': case 'txCancel': case 'pending': @@ -152,6 +169,7 @@ export function eventCodeToType(eventCode) { case 'txRepeat': case 'txAwaitingApproval': case 'txConfirmReminder': + case 'txUnderpriced': case 'error': return 'failed' case 'txConfirmed': @@ -219,7 +237,8 @@ export const timeouts = { checkSocketConnection: 250, waitForResponse: 100, txConfirmReminder: 20000, - txStall: 30000, + txStallPending: 20000, + txStallConfirmed: 60000, changeUI: 305, localhostNetworkCheck: 300, removeElement: 300, diff --git a/src/js/helpers/validation.js b/src/js/helpers/validation.js index 9160955c..6678c58b 100644 --- a/src/js/helpers/validation.js +++ b/src/js/helpers/validation.js @@ -1,5 +1,6 @@ /* eslint-disable import/prefer-default-export */ import ow from 'ow' +import { assistLog } from './utilities' const desktopPosition = ow.optional.string.is( s => @@ -12,72 +13,84 @@ const desktopPosition = ow.optional.string.is( const mobilePosition = ow.optional.string.is(s => s === 'bottom' || s === 'top') export function validateConfig(config) { - ow( - config, - 'config', - ow.object.exactShape({ - networkId: ow.number, - dappId: ow.string, - web3: ow.optional.object, - ethers: ow.optional.object, - mobileBlocked: ow.optional.boolean, - minimumBalance: ow.optional.string, - headlessMode: ow.optional.boolean, - messages: ow.optional.object.exactShape({ - txRequest: ow.optional.function, - txSent: ow.optional.function, - txPending: ow.optional.function, - txSendFail: ow.optional.function, - txStall: ow.optional.function, - txFailed: ow.optional.function, - nsfFail: ow.optional.function, - txRepeat: ow.optional.function, - txAwaitingApproval: ow.optional.function, - txConfirmReminder: ow.optional.function, - txConfirmed: ow.optional.function, - txSpeedUp: ow.optional.function - }), - handleNotificationEvent: ow.optional.function, - images: ow.optional.object.exactShape({ - welcome: ow.optional.object.exactShape({ - src: ow.string, - srcset: ow.string + try { + ow( + config, + 'config', + ow.object.exactShape({ + networkId: ow.number, + dappId: ow.string, + web3: ow.optional.object, + ethers: ow.optional.object, + mobileBlocked: ow.optional.boolean, + minimumBalance: ow.optional.string, + headlessMode: ow.optional.boolean, + messages: ow.optional.object.exactShape({ + txRequest: ow.optional.function, + txSent: ow.optional.function, + txPending: ow.optional.function, + txSendFail: ow.optional.function, + txStallPending: ow.optional.function, + txStallConfirmed: ow.optional.function, + txFailed: ow.optional.function, + nsfFail: ow.optional.function, + txRepeat: ow.optional.function, + txAwaitingApproval: ow.optional.function, + txConfirmReminder: ow.optional.function, + txConfirmed: ow.optional.function, + txSpeedUp: ow.optional.function }), - complete: ow.optional.object.exactShape({ - src: ow.string, - srcset: ow.string - }) - }), - style: ow.optional.object.exactShape({ - darkMode: ow.optional.boolean, - notificationsPosition: ow.any( - desktopPosition, - ow.optional.object.exactShape({ - mobile: mobilePosition, - desktop: desktopPosition - }) - ), - css: ow.optional.string - }), - timeouts: ow.optional.object.exactShape({ - txStall: ow.number - }), - recommendedWallets: ow.optional.object.exactShape({ - desktop: ow.optional.array.ofType( - ow.object.exactShape({ - name: ow.string, - link: ow.string, - icon: ow.string + handleNotificationEvent: ow.optional.function, + images: ow.optional.object.exactShape({ + welcome: ow.optional.object.exactShape({ + src: ow.string, + srcset: ow.string + }), + complete: ow.optional.object.exactShape({ + src: ow.string, + srcset: ow.string }) - ).nonEmpty, - mobile: ow.optional.array.ofType( - ow.object.exactShape({ - name: ow.string, - link: ow.string, - icon: ow.string - }) - ).nonEmpty + }), + style: ow.optional.object.exactShape({ + darkMode: ow.optional.boolean, + notificationsPosition: ow.any( + desktopPosition, + ow.optional.object.exactShape({ + mobile: mobilePosition, + desktop: desktopPosition + }) + ), + css: ow.optional.string + }), + timeouts: ow.optional.object.exactShape({ + txStallPending: ow.optional.number, + txStallConfirmed: ow.optional.number + }), + recommendedWallets: ow.optional.object.exactShape({ + desktop: ow.optional.array.ofType( + ow.object.exactShape({ + name: ow.string, + link: ow.string, + icon: ow.string + }) + ).nonEmpty, + mobile: ow.optional.array.ofType( + ow.object.exactShape({ + name: ow.string, + link: ow.string, + icon: ow.string + }) + ).nonEmpty + }) }) - }) - ) + ) + } catch (error) { + if (error.message.includes('Did not expect property `txStall` to exist')) { + assistLog( + 'txStall events have now been separated in to txStallPending and txStallConfirmed events. Use the new eventCodes for custom messages on those events ' + ) + } else { + throw error + } + } } diff --git a/src/js/helpers/web3.js b/src/js/helpers/web3.js index ff0b585b..25dd3fc4 100644 --- a/src/js/helpers/web3.js +++ b/src/js/helpers/web3.js @@ -9,9 +9,9 @@ errorObj.eventCode = 'initFail' export const web3Functions = { networkId: version => { switch (version) { - case '0.2': + case '0.': return promisify(state.web3Instance.version.getNetwork) - case '1.0': + case '1.': return state.web3Instance.eth.net.getId case 'ethers': return () => @@ -27,10 +27,10 @@ export const web3Functions = { }, bigNumber: version => { switch (version) { - case '0.2': + case '0.': return value => Promise.resolve(state.web3Instance.toBigNumber(formatNumber(value))) - case '1.0': + case '1.': return value => Promise.resolve(state.web3Instance.utils.toBN(formatNumber(value))) case 'ethers': @@ -48,9 +48,9 @@ export const web3Functions = { }, gasPrice: version => { switch (version) { - case '0.2': + case '0.': return promisify(state.web3Instance.eth.getGasPrice) - case '1.0': + case '1.': return state.web3Instance.eth.getGasPrice case 'ethers': return () => @@ -66,7 +66,7 @@ export const web3Functions = { }, contractGas: (version, truffleContract) => { switch (version) { - case '0.2': + case '0.': return ({ contractObj, methodName, overloadKey, args }) => { const contractMethod = getContractMethod({ contractObj, @@ -80,7 +80,7 @@ export const web3Functions = { : promisify(contractMethod.estimateGas)(...args) } - case '1.0': + case '1.': return ({ contractObj, methodName, overloadKey, args, txOptions }) => { const contractMethod = getContractMethod({ contractObj, @@ -102,9 +102,9 @@ export const web3Functions = { }, transactionGas: version => { switch (version) { - case '0.2': + case '0.': return promisify(state.web3Instance.eth.estimateGas) - case '1.0': + case '1.': return state.web3Instance.eth.estimateGas case 'ethers': return txOptions => @@ -120,9 +120,9 @@ export const web3Functions = { }, balance: version => { switch (version) { - case '0.2': + case '0.': return promisify(state.web3Instance.eth.getBalance) - case '1.0': + case '1.': return state.web3Instance.eth.getBalance case 'ethers': return address => @@ -139,9 +139,9 @@ export const web3Functions = { }, accounts: version => { switch (version) { - case '0.2': + case '0.': return promisify(state.web3Instance.eth.getAccounts) - case '1.0': + case '1.': return state.web3Instance.eth.getAccounts case 'ethers': return () => @@ -162,6 +162,7 @@ export const web3Functions = { export function configureWeb3(web3) { if (!web3) { web3 = window.web3 // eslint-disable-line prefer-destructuring + if (!web3) return } // If web3 has been prefaced with the default property, re-assign it @@ -201,37 +202,72 @@ export function configureWeb3(web3) { }) } -export function checkForWallet() { - if (window.ethereum) { - updateState({ - currentProvider: getCurrentProvider(), - validBrowser: true, - web3Wallet: true, - legacyWallet: false, - modernWallet: true - }) - } else if (window.web3 && window.web3.version) { - updateState({ - currentProvider: getCurrentProvider(), - validBrowser: true, - web3Wallet: true, - legacyWallet: true, - modernWallet: false - }) +export async function checkForWallet() { + if ( + state.web3Instance && + state.web3Instance.currentProvider && + typeof state.web3Instance.currentProvider.send === 'function' + ) { + if (typeof state.web3Instance.currentProvider.enable === 'function') { + updateState({ + currentProvider: getCurrentProvider(), + validBrowser: true, + web3Wallet: true, + legacyWallet: false, + modernWallet: true + }) + } else { + const accounts = await getAccounts().catch(handleWeb3Error) + + if (accounts && accounts[0]) { + updateState({ + currentProvider: getCurrentProvider(), + validBrowser: true, + web3Wallet: true, + legacyWallet: true, + modernWallet: false + }) + } else { + updateState({ + web3Wallet: false, + accessToAccounts: false, + walletLoggedIn: false, + walletEnabled: false + }) + } + } } else { - updateState({ - web3Wallet: false, - accessToAccounts: false, - walletLoggedIn: false, - walletEnabled: false - }) + if (window.ethereum) { + updateState({ + currentProvider: getCurrentProvider(), + validBrowser: true, + web3Wallet: true, + legacyWallet: false, + modernWallet: true + }) + } else if (window.web3 && window.web3.version) { + updateState({ + currentProvider: getCurrentProvider(), + validBrowser: true, + web3Wallet: true, + legacyWallet: true, + modernWallet: false + }) + } else { + updateState({ + web3Wallet: false, + accessToAccounts: false, + walletLoggedIn: false, + walletEnabled: false + }) + } } } export function getNetworkId() { const version = state.config.ethers ? 'ethers' - : state.web3Version && state.web3Version.slice(0, 3) + : state.web3Version && state.web3Version.slice(0, 2) return web3Functions .networkId(version)() .then(id => Number(id)) @@ -247,7 +283,7 @@ export function getTransactionParams({ return new Promise(async resolve => { const version = state.config.ethers ? 'ethers' - : state.web3Version && state.web3Version.slice(0, 3) + : state.web3Version && state.web3Version.slice(0, 2) // Sometimes value is in exponent notation and needs to be formatted if (txOptions.value) { @@ -314,7 +350,7 @@ export async function hasSufficientBalance({ return new Promise(async resolve => { const version = state.config.ethers ? 'ethers' - : state.web3Version && state.web3Version.slice(0, 3) + : state.web3Version && state.web3Version.slice(0, 2) const gasCost = gas.mul(gasPrice) @@ -342,11 +378,13 @@ export function getAccountBalance() { return new Promise(async resolve => { const accounts = await getAccounts().catch(handleWeb3Error) + if (!accounts || !accounts[0]) return + updateState({ accountAddress: accounts && accounts[0] }) const version = state.config.ethers ? 'ethers' - : state.web3Version && state.web3Version.slice(0, 3) + : state.web3Version && state.web3Version.slice(0, 2) const balance = await web3Functions .balance(version)(accounts[0]) .catch(handleWeb3Error) @@ -377,7 +415,7 @@ export function getContractMethod({ export function getAccounts() { const version = state.config.ethers ? 'ethers' - : state.web3Version && state.web3Version.slice(0, 3) + : state.web3Version && state.web3Version.slice(0, 2) return web3Functions.accounts(version)() } @@ -396,11 +434,11 @@ export function getCurrentProvider() { const web3 = state.web3Instance if (!web3) { - if (window.ethereum.isMetaMask) { + if (window.ethereum && window.ethereum.isMetaMask) { return 'metamask' } - if (window.ethereum.isDapper) { + if (window.ethereum && window.ethereum.isDapper) { return 'dapper' } @@ -452,6 +490,10 @@ export function getCurrentProvider() { if (web3.currentProvider.connection) { return 'Infura Websocket' } + + if (web3.currentProvider.name === 'trezor') { + return 'trezor' + } } // Poll for a tx receipt diff --git a/src/js/helpers/websockets.js b/src/js/helpers/websockets.js index a3760418..5d10b50b 100644 --- a/src/js/helpers/websockets.js +++ b/src/js/helpers/websockets.js @@ -1,7 +1,7 @@ import { state, updateState } from './state' import { handleEvent } from './events' import { storeItem, getItem } from './storage' -import { timeouts } from './utilities' +import { timeouts, networkName } from './utilities' import { updateTransactionInQueue, getTxObjFromQueue, @@ -66,12 +66,22 @@ export function retryLogEvent(logFunc) { // Handle in coming socket messages export function handleSocketMessage(msg) { - const { status, reason, event, connectionId } = JSON.parse(msg.data) + const { status, reason, event, connectionId, nodeSyncStatus } = JSON.parse( + msg.data + ) const { validApiKey, supportedNetwork } = state if (!validApiKey || !supportedNetwork) { return } + if ( + nodeSyncStatus !== undefined && + nodeSyncStatus.blockchain === 'ethereum' && + nodeSyncStatus.network === networkName(state.config.networkId) + ) { + updateState({ nodeSynced: nodeSyncStatus.synced }) + } + // handle any errors from the server if (status === 'error') { if ( diff --git a/src/js/index.js b/src/js/index.js index 240358bf..ac302fe2 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -452,6 +452,25 @@ function init(config) { // it only needs to be assigned once if (!seenMethods.includes(name)) { const method = contractObj.methods[name] + + /* If the developer has minified constructor names, a truffle contract may + * have incorrectly been identified as a web3 contract and flow would incorrectly + * get here. In this case, 'method' would be undefined. + * Do a quick check to make sure it exists. + */ + if (!method) + throw Error( + 'It looks like some function names that assist.js relies on have been minified in this build, causing it to incorrectly identify a Truffle contract as a web3.js contract.' + + "\nIf you wish to use Truffle contracts with assist.js, you need to disable minification of 'fnames' in your build." + + '\nInstructions for:' + + '\n - Terser: https://github.com/terser-js/terser#minify-options' + + '\n - Uglify: https://github.com/mishoo/UglifyJS2#minify-options' + + '\n - Webpack terser plugin: https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions' + + '\n - Webpack uglify plugin: https://github.com/webpack-contrib/uglifyjs-webpack-plugin#uglifyoptions' + + '\n - Rollup terser plugin: https://github.com/TrySound/rollup-plugin-terser#options' + + '\n - Rollup uglify plugin: https://github.com/TrySound/rollup-plugin-uglify#options' + ) + methodsObj[name] = (...args) => constant ? call({ contractObj, methodName: name, args, truffleContract }) diff --git a/src/js/logic/send-transaction.js b/src/js/logic/send-transaction.js index 60cfc12e..8b88fac2 100644 --- a/src/js/logic/send-transaction.js +++ b/src/js/logic/send-transaction.js @@ -291,8 +291,8 @@ export function onTxHash(id, hash, categoryCode) { } }) - const customStallTimeout = - state.config.timeouts && state.config.timeouts.txStall + const customStallPendingTimeout = + state.config.timeouts && state.config.timeouts.txStallPending // Check if transaction is in txPool after timeout setTimeout(() => { @@ -303,14 +303,11 @@ export function onTxHash(id, hash, categoryCode) { transaction: { status } } = txObj - if ( - state.socketConnection && - (status === 'approved' || status === 'pending') - ) { - updateTransactionInQueue(id, { status: 'stalled' }) + if (state.socketConnection && status === 'approved' && state.nodeSynced) { + updateTransactionInQueue(id, { status: 'stalledPending' }) handleEvent({ - eventCode: 'txStall', + eventCode: 'txStallPending', categoryCode, transaction: txObj.transaction, contract: txObj.contract, @@ -324,7 +321,39 @@ export function onTxHash(id, hash, categoryCode) { } }) } - }, customStallTimeout || timeouts.txStall) + }, customStallPendingTimeout || timeouts.txStallPending) + + const customStallConfirmedTimeout = + state.config.timeouts && state.config.timeouts.txStallConfirmed + + // Check if transaction is still in txPool after timeout + setTimeout(() => { + const txObj = getTxObjFromQueue(id) + if (!txObj) return + + const { + transaction: { status, originalHash } + } = txObj + + // check originalHash to make sure not speedup or cancel + if (state.socketConnection && status === 'pending' && !originalHash) { + updateTransactionInQueue(id, { status: 'stalledConfirmed' }) + + handleEvent({ + eventCode: 'txStallConfirmed', + categoryCode, + transaction: txObj.transaction, + contract: txObj.contract, + inlineCustomMsgs: txObj.inlineCustomMsgs, + wallet: { + provider: state.currentProvider, + address: state.accountAddress, + balance: state.accountBalance, + minimum: state.config.minimumBalance + } + }) + } + }, customStallConfirmedTimeout || timeouts.txStallConfirmed) } async function onTxReceipt(id, categoryCode, receipt) { @@ -357,32 +386,33 @@ async function onTxReceipt(id, categoryCode, receipt) { } function onTxError(id, error, categoryCode) { - const { message } = error - let errorMsg - try { - errorMsg = extractMessageFromError(message) - } catch (error) { - errorMsg = 'User denied transaction signature' - } + const { errorMsg, eventCode } = extractMessageFromError(error.message) - const txObj = updateTransactionInQueue(id, { status: 'rejected' }) + let txObj = getTxObjFromQueue(id) - handleEvent({ - eventCode: - errorMsg === 'transaction underpriced' ? 'txUnderpriced' : 'txSendFail', - categoryCode, - transaction: txObj.transaction, - contract: txObj.contract, - inlineCustomMsgs: txObj.inlineCustomMsgs, - clickHandlers: txObj.clickHandlers, - reason: errorMsg, - wallet: { - provider: state.currentProvider, - address: state.accountAddress, - balance: state.accountBalance, - minimum: state.config.minimumBalance - } - }) + if ( + txObj && + (txObj.transaction.status !== 'confirmed' || + txObj.transaction.status !== 'completed') + ) { + txObj = updateTransactionInQueue(id, { status: 'error' }) + + handleEvent({ + eventCode, + categoryCode, + transaction: txObj.transaction, + contract: txObj.contract, + inlineCustomMsgs: txObj.inlineCustomMsgs, + clickHandlers: txObj.clickHandlers, + reason: errorMsg, + wallet: { + provider: state.currentProvider, + address: state.accountAddress, + balance: state.accountBalance, + minimum: state.config.minimumBalance + } + }) + } removeTransactionFromQueue(id) } diff --git a/src/js/logic/user.js b/src/js/logic/user.js index 63f5cb39..94806d6a 100644 --- a/src/js/logic/user.js +++ b/src/js/logic/user.js @@ -21,7 +21,7 @@ export function checkUserEnvironment() { checkValidBrowser() } - checkForWallet() + await checkForWallet() if (!state.web3Wallet) { if (!state.mobileDevice) { @@ -271,7 +271,7 @@ function checkMinimumBalance() { const { web3Version } = state const version = state.config.ethers ? 'ethers' - : web3Version && web3Version.slice(0, 3) + : web3Version && web3Version.slice(0, 2) const minimum = state.config.minimumBalance || 0 const balance = await getAccountBalance().catch(resolve) diff --git a/src/js/views/content.js b/src/js/views/content.js index 72ad5a12..03f1ecc8 100644 --- a/src/js/views/content.js +++ b/src/js/views/content.js @@ -362,8 +362,10 @@ export const transactionMsgs = { `Your transaction ID: ${transaction.nonce} has started`, txSent: () => `Your transaction has been sent to the network`, txSendFail: () => `You rejected the transaction`, - txStall: ({ transaction }) => - `Your transaction ID: ${transaction.nonce} has stalled`, + txStallPending: () => + 'Your transaction has stalled and has not entered the transaction pool', + txStallConfirmed: ({ transaction }) => + `Your transaction ID: ${transaction.nonce} has stalled and hasn't been confirmed`, txFailed: ({ transaction }) => `Your transaction ID: ${transaction.nonce} has failed`, nsfFail: () => 'You have insufficient funds to complete this transaction', @@ -377,5 +379,7 @@ export const transactionMsgs = { txSpeedUp: ({ transaction }) => `Your transaction ID: ${transaction.nonce} has been sped up`, txCancel: ({ transaction }) => - `Your transaction ID: ${transaction.nonce} is being canceled` + `Your transaction ID: ${transaction.nonce} is being canceled`, + txUnderpriced: () => + 'The gas price for your transaction is too low, try again with a higher gas price' } diff --git a/src/js/views/event-to-ui.js b/src/js/views/event-to-ui.js index a87652d7..0e46049f 100644 --- a/src/js/views/event-to-ui.js +++ b/src/js/views/event-to-ui.js @@ -74,10 +74,12 @@ const eventToUI = { txConfirmReminder: notificationsUI, txConfirmed: notificationsUI, txConfirmedClient: notificationsUI, - txStall: notificationsUI, + txStallPending: notificationsUI, + txStallConfirmed: notificationsUI, txFailed: notificationsUI, txSpeedUp: notificationsUI, - txCancel: notificationsUI + txCancel: notificationsUI, + txUnderpriced: notificationsUI }, activeContract: { txAwaitingApproval: notificationsUI, @@ -88,10 +90,12 @@ const eventToUI = { txConfirmReminder: notificationsUI, txConfirmed: notificationsUI, txConfirmedClient: notificationsUI, - txStall: notificationsUI, + txStallPending: notificationsUI, + txStallConfirmed: notificationsUI, txFailed: notificationsUI, txSpeedUp: notificationsUI, - txCancel: notificationsUI + txCancel: notificationsUI, + txUnderpriced: notificationsUI }, userInitiatedNotify: { success: notificationsUI, @@ -199,7 +203,8 @@ function notificationsUI({ const hasTimer = eventCode === 'txPending' || eventCode === 'txSent' || - eventCode === 'txStall' || + eventCode === 'txStallPending' || + eventCode === 'txStallConfirmed' || eventCode === 'txSpeedUp' || eventCode === 'pending'