Skip to content

Commit

Permalink
version 0.9 (#308)
Browse files Browse the repository at this point in the history
* Update snapshots

* update to version 0.8.11

* Release/0.9 (#307)

* add abi check for ethers

* update tests

* add ethers support

* modify variable names in separate args

* fixed getContractMethod calls

* fixed transactionQueue bug

* also fixes txQueue bug

* update getContractMethod to properly create overloaded methods for ethers contracts

* correctly assign from property on txOptions object based on ethers or web3

* updated readme

* Refactor function to remove unwanted notifications

* Add code to call handleNotificationEvent

* Update readme

* Change value to undefined so that default values work correctly

* Add default empty object for proper destructuring

* started work to be compatible with ethers v5

* refactored websocket retry logic to be in websockets.js

* Update tests

* change parameter abi is pulled off of, change to uncheckedsigner

* fixed merge conflicts and updated tests

* Update readme with ethers contract instantiation example

* update getCurrentProvider to allow for ethers

* add logic for different ethers versions

* add unchecked signer for v4 support

* modify eslint config to allow for case declarations

* update docs

* update readme with compatile ethers versions

* add ethers to config validation

* small fix to formatting and wrong declaration

* Fix bignumber bug with contract gas estimate

* Add missing default value for inlineCustomMsgs

* Add handleNotificationEvent and remove truffleContract from config validation

* Add extra provider checksif not using web3

* Make sure nsfFail event is included in handleNotificationEvent

* Add better documentation for handleNotificationEvent

* update to version 0.9

* Update documentation for notification events

* clarification for txConfirmedClient event
  • Loading branch information
cmeisl authored Jun 21, 2019
1 parent 465aeee commit 797acaa
Show file tree
Hide file tree
Showing 23 changed files with 1,315 additions and 955 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ module.exports = {
'no-nested-ternary': 'off',
'import/no-cycle': 'off',
'no-lonely-if': 'off',
'consistent-return': 'off'
'consistent-return': 'off',
'no-case-declarations': 'off'
},
settings: {
'import/resolver': {
Expand Down
122 changes: 107 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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.
setup. Supports `web3.js` versions `0.20` and `1.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`_

Expand Down Expand Up @@ -43,16 +43,16 @@ yarn add bnc-assist
#### Script Tag

The library uses [semantic versioning](https://semver.org/spec/v2.0.0.html).
The current version is 0.8.11.
The current version is 0.9.0.
There are minified and non-minified versions.
Put this script at the top of your `<head>`

```html
<script src="https://assist.blocknative.com/0-8-11/assist.js"></script>
<script src="https://assist.blocknative.com/0-9-0/assist.js"></script>

<!-- OR... -->

<script src="https://assist.blocknative.com/0-8-11/assist.min.js"></script>
<script src="https://assist.blocknative.com/0-9-0/assist.min.js"></script>
```

### Initialize the Library
Expand Down Expand Up @@ -114,6 +114,7 @@ Decorating your contracts is simple:

```javascript
var myContract = new web3.eth.Contract(abi, address)
// Assist can decorate ethers instantiated contracts as well
var myDecoratedContract = assistInstance.Contract(myContract)

// and then replace `myContract` with `myDecoratedContract`
Expand All @@ -130,6 +131,14 @@ To speed things up, you can decorate the contract inline:
var myContract = assistInstance.Contract(new web3.eth.Contract(abi, address))
```

### Ethers Contracts

If you are using `ethers.js` you will need to pass in the `address` and the `abi` to Assist's `Contract` function so that Assist can instantiate it with the `UncheckedJsonRpcSigner`. This is critical for Assist's transaction notifications to work correctly. An example of how to create an ethers contract:

```javascript
var myContract = assistInstance.Contract(address, abi)
```

### Initializing `web3` and including it in the `config`

`web3` isn't a required parameter as you might not have access to a provider to instantiate Web3 with until after the user has been onboarded and has a wallet installed. We recommend instantiating `web3` at the top level of your Dapp once the window object is available like this:
Expand Down Expand Up @@ -161,6 +170,7 @@ var config = {
networkId: Number, // The network id of the Ethereum network your Dapp is working with (REQUIRED)
dappId: String, // The API key supplied to you by Blocknative (REQUIRED)
web3: Object, // The instantiated version of web3 that the Dapp is using
ethers: Object, // Pass in ethers if using instead of web3 (this is required if you are using ethers)
mobileBlocked: Boolean, // Defines if the Dapp works on mobile [false]
minimumBalance: String, // Defines the minimum balance in Wei that a user needs to have to use the Dapp [0]
headlessMode: Boolean, // Turn off Assist UI, but still retain analytics collection [false]
Expand Down Expand Up @@ -194,6 +204,7 @@ var config = {
notificationsPosition: Object || String, // Defines where in the viewport notifications will be positioned. See below: 'Notification Positioning'
css: String // Custom css string to overide Assist default styles
},
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
}
Expand All @@ -216,7 +227,7 @@ By default, `Assist` positions notifications at the `top` of the viewport on mob

```javascript
// Set notifications to bottom on mobile and top right on desktop
const config = {
var config = {
style: {
notificationsPosition: {
desktop: 'topLeft',
Expand All @@ -228,13 +239,70 @@ const config = {

```javascript
// Sets only the desktop position
const config = {
var config = {
style: {
notificationsPosition: 'bottomRight'
}
}
```

### Handling Notifications

If you want more fine grained control over whether Assist's notifications are displayed or you just want to be informed of every event, you can define a function that will be called every time there is a notification event.

The function that is defined on the `handleNotificationEvent` property of the config will be called with the following object:

```javascript
{
categoryCode: String, // event category - List detailed below
eventCode: String, // event type - List detailed below
contract: { // if not a contract method transaction, then this is undefined
methodName: String, // name of the method that was called
parameters: Array, // the parameters the method was called with
},
inlineCustomMsgs: Object | Boolean, // the inline custom messages passed to the transaction
transaction: {
id: String, // internal unique id for the transaction
from: String, // the address the transaction was sent from
gas: String, // the gas limit of the transaction
gasPrice: String, // the gas price of the transaction
to: String, // the address the transaction was sent to
value: String // the value of the transaction
},
wallet: {
address: String, // the account address of the wallet in use
balance: String, // the balance in wei of the wallet in use
minimum: Boolean, // whether the wallet has the minimum balance required (specified in config)
provider: String // the name of the wallet provider
}
}
```

#### `eventCode`

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
```

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.

For documentation on the rest of the event codes see the documentation for the messages parameter of the config object.

#### `categoryCode`

The following list of category codes can be included in the object that `handleNotificationEvent` is called with:

```javascript
activePreflight: String, // called during preflight transaction checks
activeTransaction: String, // called during an active non-contract transaction
activeContract: String // called during an active contract transaction
```

#### Selectively display Notification UI

If you would like Assist to display a notification for the current event, then return a "truthy" value from the `handleNotificationEvent` function. If you don't want a notification to be displayed then just return a "falsy" value.

### Custom Transaction Messages

Expand Down Expand Up @@ -294,6 +362,22 @@ 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.

### Transaction Events

By defining a function and including it in the config on the `handleNotificationEvent` property you can hook in to all of the transaction events within Assist. The function will be called with a transaction event object which has the following properties:

```javascript
{
categoryCode: "activeTransaction"
contract: Object { methodName: "highFive", parameters: (1) […] }
eventCode: "txPending"
inlineCustomMsgs: false
transaction: Object { id: "f64a4c67-f349-4da7-8d6b-55e92525e60b", gas: "24268", gasPrice: "1000000000", … }
}
```

If you want Assist to still go ahead and show the notification, return `true` from the function. If you don't want the notification to display, then return `false`.

### Ethereum Network Ids

The available ids for the `networkId` property of the config object:
Expand Down Expand Up @@ -420,11 +504,13 @@ assistInstance.onboard()
})
```

### `Contract(contractInstance)`
### `Contract(contractInstanceOrAddress [, abi])`

#### Parameters

`contractInstance` - `Object`: Instantiated web3 `contract` object (**Required**)
`contractInstanceOrAddress` - `Object` | `String`: Instantiated web3 `contract` object (**Required**) or an address if you are using `ethers` instead if `web3`

`abi` - `Array`: Abi array if you are using `ethers`

#### Returns

Expand All @@ -433,10 +519,16 @@ A decorated `contract` to be used instead of the original instance
#### Example

```javascript
const myContract = new web3.eth.Contract(abi, address)
const myDecoratedContract = assistInstance.Contract(myContract)

// web3
var myContract = new web3.eth.Contract(abi, address)
var myDecoratedContract = assistInstance.Contract(myContract)
mydecoratedContract.methods.myMethod(params).call()

// OR

// ethers
var myContract = assistInstance.Contract(address, abi)
myContract.myMethod().call()
```

### `Transaction(txObject [, callback] [, inlineCustomMsgs])`
Expand Down Expand Up @@ -494,7 +586,7 @@ assistInstance.getState()
`style` - `Object`: Object containing new style information (**Required**)

```javascript
const style = {
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'
Expand All @@ -505,14 +597,14 @@ const style = {

```javascript
// Enable dark mode and position notifications at the bottom left on desktop
const style = {
var style = {
darkMode: true,
notificationsPosition: 'bottomLeft'
}
assistInstance.updateStyle(style)

// Position notifications at the bottom of the viewport on mobile and set their background to black
const style = {
var style = {
css: `.bn-notification { background: black }`,
notificationsPosition: { mobile: 'bottom' }
}
Expand Down Expand Up @@ -554,7 +646,7 @@ assistInstance.notify('success', 'Operation was a success! Click <a href="https:

// Display a pending notification, load data from an imaginary backend
// and dismiss the pending notification only when the data is loaded
const 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()
Expand Down
2 changes: 2 additions & 0 deletions internals/jestSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Object.defineProperty(window.navigator, 'userAgent', {
// websocket provider we setup to deploy the smart contracts, ignore them
process.on('unhandledRejection', (reason, p) => {
if (
reason.target &&
reason.target.constructor &&
reason.target.constructor.name === 'W3CWebSocket' &&
reason.target.url === `ws://localhost:${ganachePort}` &&
reason.type === 'error'
Expand Down
9 changes: 2 additions & 7 deletions multidep.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
{
"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.0.0-beta.55", "1.0.0-beta.46", "1.0.0-beta.35", "0.20.6"]
}
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bnc-assist",
"version": "0.8.11",
"version": "0.9.0",
"description": "Blocknative Assist js library for Dapp developers",
"main": "lib/assist.min.js",
"scripts": {
Expand Down
17 changes: 5 additions & 12 deletions src/__integration-tests__/websockets/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { WebSocket, Server } from 'mock-socket'
import da from '~/js'
import { state, updateState, initialState } from '~/js/helpers/state'
import * as websockets from '~/js/helpers/websockets'
import * as utilities from '~/js/helpers/utilities'
import * as events from '~/js/helpers/events'

const socketUrl = 'wss://api.blocknative.com/v0'
Expand Down Expand Up @@ -56,29 +55,23 @@ describe('a websocket connection is requested', () => {

describe('socket refuses to connect', () => {
beforeEach(() => {
websockets.openWebsocketConnection()
websockets.openWebsocketConnection().catch(() => {})
mockServer.emit('error')
})
test('state.pendingSocketConnection is set to false', () => {
expect(state.pendingSocketConnection).toEqual(false)
})
})

describe('socket creation throws an error', () => {
beforeEach(() => {
global.WebSocket = null
})
afterEach(() => {
global.WebSocket = WebSocket
})
test('assistLog should be called with the error', () => {
const assistLogSpy = jest
.spyOn(utilities, 'assistLog')
.mockImplementation(() => {})
expect(() => {
websockets.openWebsocketConnection()
}).toThrow()
expect(assistLogSpy).toHaveBeenCalled()
assistLogSpy.mockRestore()
test('openWebsocketConnection should reject', () => {
expect(websockets.openWebsocketConnection()).rejects.toBe(false)
})
})
})
Expand Down Expand Up @@ -264,7 +257,7 @@ describe('assist is connected to a websocket', () => {
contract: 'some-contract',
inlineCustomMsgs: { '1': 'msg' }
}
const payload = { event: { transaction } }
const payload = { event: { transaction, eventCode: 'txConfirmed' } }
let existingTxStatus = 'pending'
let handleEventSpy
beforeEach(() => {
Expand Down
24 changes: 17 additions & 7 deletions src/__tests__/js/contract/index.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import truffleContract from 'truffle-contract'
import { Server } from 'mock-socket'
import abi from '~/__tests__/res/dstoken.json'
import da from '~/js'
import * as web3Helpers from '~/js/helpers/web3'
import { initialState, updateState } from '~/js/helpers/state'
import * as websockets from '~/js/helpers/websockets'
import { state, initialState, updateState } from '~/js/helpers/state'
import convertLibJson from '~/__tests__/res/ConvertLib.json'
import { convertLibAddress, port } from '../../../../internals/ganacheConfig'

Expand Down Expand Up @@ -34,29 +34,39 @@ multidepRequire.forEachVersion('web3', (version, Web3) => {
let assistInstance
let web3
let contract
let mockServer
let config
beforeEach(() => {
mockServer = new Server('ws://localhost:8080')
jest
.spyOn(websockets, 'openWebsocketConnection')
.mockImplementation(() => Promise.resolve(true))
jest
.spyOn(websockets, 'checkForSocketConnection')
.mockImplementation(() => Promise.resolve(true))
updateState({
socket: { send: () => {} },
socketConnection: true,
pendingSocketConnection: false
})
const provider = version.includes('0.20')
? new Web3.providers.HttpProvider(`http://localhost:${port}`)
: `ws://localhost${port}`
web3 = new Web3(provider)
config = { dappId: '123', web3, networkId: 1 }
assistInstance = da.init(config)
})
afterEach(() => {
mockServer.close()
})
const contracts = [
['truffle', getTruffleContract],
['web3', getWeb3Contract]
]
contracts.forEach(([name, getContract]) => {
describe(`with a ${name} contract`, () => {
beforeEach(async () => {
if (name === 'truffle') state.config.truffleContract = true
contract = await getContract(web3)
})
afterEach(() => {
if (name === 'truffle') state.config.truffleContract = false
})
test(`it doesn't fail and returns the expected decorated contract`, () => {
const decoratedContract = assistInstance.Contract(contract)

Expand Down
Loading

0 comments on commit 797acaa

Please sign in to comment.