diff --git a/README.md b/README.md
index 6dfe849..ee7a58d 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@
- A TypeScript implementation that allows dApps to connect and interact with web-based providers.
+ A TypeScript implementation that allows clients to connect and interact with web-based providers.
### Table of contents
@@ -127,8 +127,8 @@ This will compile the Typescript source code into a `dist/` directory.
| Command | Description |
|-----------------------|------------------------------------------------------------------------------------|
| `yarn build` | Builds the source code into the `dist/` directory. |
-| `yarn run docs:build` | Builds the documentation into the `.docs/` directory. |
-| `yarn run docs:serve` | Serves the built documentation from the `.docs/` directory. |
+| `yarn run docs:build` | Builds the documentation into the `.docusaurus/` directory. |
+| `yarn run docs:serve` | Serves the built documentation from the `.docusaurus/` directory. |
| `yarn run docs:start` | Builds and runs the documentation in a development environment with hot reloading. |
| `yarn run lint` | Runs the linter on `.js` and `.ts` files. |
| `yarn run prettier` | Runs the prettier on `.js` and `.ts` files. |
diff --git a/docs/api-reference/avm-web-client.mdx b/docs/api-reference/avm-web-client.mdx
index 7f8dc7e..68851fa 100644
--- a/docs/api-reference/avm-web-client.mdx
+++ b/docs/api-reference/avm-web-client.mdx
@@ -43,6 +43,22 @@ import TOCInline from '@theme/TOCInline';
|--------|-------------|
| `void` | - |
+### `enable([params])`
+
+> Enables to a client with providers. If the ID of the provider and/or network is specified, that provider/network is used, otherwise the default provider is enabled.
+
+#### Parameters
+
+| Name | Type | Required | Default | Description |
+|--------|----------------------------------------|----------|---------|------------------------------------------------------|
+| params | [`IEnableParams`](types#ienableparams) | no | - | Params that specify the provider and/or the network. |
+
+#### Returns
+
+| Type | Description |
+|--------|-------------|
+| `void` | - |
+
### `getConfig()`
> Returns the configuration.
@@ -60,9 +76,25 @@ import TOCInline from '@theme/TOCInline';
#### Parameters
-| Name | Type | Required | Default | Description |
-|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| listener | (`result`?: [`IDiscoverResult`](types#idiscoverresult) \| `null`, `error`?: [`IBaseError`](types#ibaseerror) \| `null`) => (`void` \| `Promise`) \| `null` | yes | - | The callback is called when a response message is received, or null to remove the listener. If the reult was successful, the `error` parameter will be null. |
+| Name | Type | Required | Default | Description |
+|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| listener | (`result`?: [`IDiscoverResult`](types#idiscoverresult) \| `null`, `error`?: [`IBaseError`](types#ibaseerror) \| `null`) => (`void` \| `Promise`) \| `null` | yes | - | The callback is called when a response message is received, or null to remove the listener. If the result was successful, the `error` parameter will be null. |
+
+#### Returns
+
+| Type | Description |
+|--------|-------------|
+| `void` | - |
+
+### `onEnable(listener)`
+
+> Listens to enable messages sent from providers. This will replace any previous set listeners. If null is supplied, the listener will be removed.
+
+#### Parameters
+
+| Name | Type | Required | Default | Description |
+|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| listener | (`result`?: [`IEnableResult`](types#ienableresult) \| `null`, `error`?: [`IBaseError`](types#ibaseerror) \| `null`) => (`void` \| `Promise`) \| `null` | yes | - | The callback is called when a response message is received, or null to remove the listener. If the result was successful, the `error` parameter will be null. |
#### Returns
diff --git a/docs/api-reference/avm-web-provider.mdx b/docs/api-reference/avm-web-provider.mdx
index dd0893f..bfb9e4f 100644
--- a/docs/api-reference/avm-web-provider.mdx
+++ b/docs/api-reference/avm-web-provider.mdx
@@ -53,3 +53,19 @@ import TOCInline from '@theme/TOCInline';
| Type | Description |
|--------|-------------|
| `void` | - |
+
+### `onEnable(listener)`
+
+> Listens to enable messages sent from clients. This will replace any previous set listeners. If null is supplied, the listener will be removed.
+
+#### Parameters
+
+| Name | Type | Required | Default | Description |
+|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|----------------------------------------------------------------------------------------|
+| listener | (`params`?: [`IEnableParams`](types#ienableparams)) => ([`IEnableResult`](types#ienableresult) \| [`Promise`](types#ienableresult)) \| `null` | yes | - | The listener to call when the request message is sent, or null to remove the listener. |
+
+#### Returns
+
+| Type | Description |
+|--------|-------------|
+| `void` | - |
diff --git a/docs/api-reference/types.mdx b/docs/api-reference/types.mdx
index c4693c0..44b7d7d 100644
--- a/docs/api-reference/types.mdx
+++ b/docs/api-reference/types.mdx
@@ -9,36 +9,36 @@ import TOCInline from '@theme/TOCInline';
### `IAVMWebClientConfig`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| debug | `boolean` | no | `false` | Outputs debug information to the console. |
+| Name | Type | Required | Default | Description |
+|-------|-----------|----------|---------|-------------------------------------------|
+| debug | `boolean` | no | `false` | Outputs debug information to the console. |
### `IAVMWebClientInitOptions`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| debug | `boolean` | no | `false` | Outputs debug information to the console. |
+| Name | Type | Required | Default | Description |
+|-------|-----------|----------|---------|-------------------------------------------|
+| debug | `boolean` | no | `false` | Outputs debug information to the console. |
### `IAVMWebProviderConfig`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| providerId | `string` | yes | - | The ID of the provider. |
-| debug | `boolean` | no | `false` | Outputs debug information to the console. |
+| Name | Type | Required | Default | Description |
+|------------|-----------|----------|---------|-------------------------------------------|
+| providerId | `string` | yes | - | The ID of the provider. |
+| debug | `boolean` | no | `false` | Outputs debug information to the console. |
### `IAVMWebProviderInitOptions`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| debug | `boolean` | no | `false` | Outputs debug information to the console. |
+| Name | Type | Required | Default | Description |
+|-------|-----------|----------|---------|-------------------------------------------|
+| debug | `boolean` | no | `false` | Outputs debug information to the console. |
### `IBaseError`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| code | `number` | yes | - | The code of the error. See the [error codes](errors#summary) for more information. |
-| message | `string` | yes | - | A human-readable error message that can be displayed to a user. |
-| providerId | `string` | no | - | The ID of the provider that threw the error. |
+| Name | Type | Required | Default | Description |
+|------------|----------|----------|---------|------------------------------------------------------------------------------------|
+| code | `number` | yes | - | The code of the error. See the [error codes](errors#summary) for more information. |
+| message | `string` | yes | - | A human-readable error message that can be displayed to a user. |
+| providerId | `string` | no | - | The ID of the provider that threw the error. |
:::note
@@ -46,26 +46,49 @@ This is the basic type for an error. For specific details on errors check out th
:::
+### `IAccount`
+
+| Name | Type | Required | Default | Description |
+|--------|----------|----------|---------|-----------------------------------------|
+| addess | `string` | yes | - | The address of the account. |
+| name | `string` | no | - | A human-readable name for this account. |
+
### `IDiscoverParams`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| providerId | `string` | yes | - | The ID of the provider. |
+| Name | Type | Required | Default | Description |
+|------------|----------|----------|---------|-------------------------|
+| providerId | `string` | yes | - | The ID of the provider. |
### `IDiscoverResult`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| host | `string` | no | - | The domain name of the provider. |
-| icon | `string` | no | - | A URI pointing to an image. |
-| name | `string` | yes | - | A human-readable canonical name of the provider. |
-| networks | [`INetworkConfiguration[]`](#inetworkconfiguration) | yes | - | A list of networks available for the provider. |
-| providerId | `string` | yes | - | The ID of the provider. |
+| Name | Type | Required | Default | Description |
+|------------|-----------------------------------------------------|----------|---------|--------------------------------------------------|
+| host | `string` | no | - | The domain name of the provider. |
+| icon | `string` | no | - | A URI pointing to an image. |
+| name | `string` | yes | - | A human-readable canonical name of the provider. |
+| networks | [`INetworkConfiguration[]`](#inetworkconfiguration) | yes | - | A list of networks available for the provider. |
+| providerId | `string` | yes | - | The ID of the provider. |
+
+### `IEnableParams`
+
+| Name | Type | Required | Default | Description |
+|-------------|----------|----------|---------|------------------------------------------------------------------------------|
+| genesisHash | `string` | no | - | The unique identifier for the network that is the hash of the genesis block. |
+| providerId | `string` | no | - | The ID of the provider. |
+
+### `IEnableResult`
+
+| Name | Type | Required | Default | Description |
+|-------------|---------------------------|----------|---------|------------------------------------------------------------------------------|
+| accounts | [`IAccount[]`](#iaccount) | yes | - | A list of accounts authorized accounts on the provider. |
+| genesisHash | `string` | yes | - | The unique identifier for the network that is the hash of the genesis block. |
+| genesisId | `string` | yes | - | A human-readable identifier for the network. |
+| providerId | `string` | yes | - | The ID of the provider. |
### `INetworkConfiguration`
-| Name | Type | Required | Default | Description |
-|------------|-----------|----------|---------|--------------------------------------------------------------|
-| genesisHash | `string` | yes | - | The unique identifier for the network that is the hash of the genesis block. |
-| genesisId | `string` | yes | - | A human-readable identifier for the network. |
-| methods | `string[]` | yes | - | A list of methods available from the provider for the chain. |
+| Name | Type | Required | Default | Description |
+|-------------|------------|----------|---------|------------------------------------------------------------------------------|
+| genesisHash | `string` | yes | - | The unique identifier for the network that is the hash of the genesis block. |
+| genesisId | `string` | yes | - | A human-readable identifier for the network. |
+| methods | `string[]` | yes | - | A list of methods available from the provider for the chain. |
diff --git a/docs/clients/discover-providers.mdx b/docs/clients/discover-providers.mdx
index ee44ab5..39b1f04 100644
--- a/docs/clients/discover-providers.mdx
+++ b/docs/clients/discover-providers.mdx
@@ -15,7 +15,7 @@ Before we can start interacting with a provider, we first need to find out what
## Discovering all providers
-The first thing we want to do, after initialization, is start listening to discover messages:
+The first thing we want to do, after [initialization](getting-started), is start listening to discover messages. The callback passed will be called everytime a `discover` message is responded to by a provider. However, before we receive any `discover` messages we need then broadcast to any providers a request.
- ```js
- // initialized client
- client.onDiscover((result, error) => {
- if (error) {
- console.error('error:', error);
-
- return;
- }
-
- // handle result
- });
- ```
+```js
+// initialized client
+client.onDiscover((result, error) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ host: 'https://awesome-wallet.com',
+ name: 'Awesome Wallet',
+ networks: [
+ {
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ {
+ genesisHash: 'IXnoWtviVVJW5LGivNFc0Dq14V3kqaXuK2u5OQrdVZo=',
+ genesisId: 'voitest-v1',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ ],
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ }
+ */
+});
+
+// broadcast a discover request
+client.discover();
+```
- ```typescript
- import { BaseARC0027Error, IDiscoverResult } from '@agoralabs-sh/avm-web-provider';
-
- // initialized client
- client.onDiscover((result: IDiscoverResult: null, error: BaseARC0027Error | null) => {
- if (error) {
- console.error('error:', error);
-
- return;
- }
-
- // handle result
- });
- ```
-
-
-
-
-The callback passed will be called everytime a `discover` message is responded to by a provider. However, before we receive any `discover` messages we need to broadcast to any providers a request. This can be done by:
-
-
-
-
- ```js
- // initialized client
- client.discover();
- ```
-
-
-
-
- ```typescript
- // initialized client
- client.discover();
- ```
+```typescript
+import { BaseARC0027Error, IDiscoverResult } from '@agoralabs-sh/avm-web-provider';
+
+// initialized client
+client.onDiscover((result: IDiscoverResult: null, error: BaseARC0027Error | null) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ host: 'https://awesome-wallet.com',
+ name: 'Awesome Wallet',
+ networks: [
+ {
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ {
+ genesisHash: 'IXnoWtviVVJW5LGivNFc0Dq14V3kqaXuK2u5OQrdVZo=',
+ genesisId: 'voitest-v1',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ ],
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ }
+ */
+});
+
+// broadcast a discover request
+client.discover();
+```
@@ -99,52 +141,108 @@ As before, let's first add a listener and then broadcast, but this time we will
]}>
- ```js
- const providerId = '02657eaf-be17-4efc-b0a4-19d654b2448e';
-
- // initialized client
- client.onDiscover((result, error) => {
- if (error) {
- console.error('error:', error);
-
- return;
- }
-
- // if the provider is not the specified provider, we can ignore
- if (result.providerId !== providerId) {
- return;
- }
-
- // handle result
- });
- client.discover({ providerId });
- ```
+```js
+const providerId = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized client
+client.onDiscover((result, error) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ host: 'https://awesome-wallet.com',
+ name: 'Awesome Wallet',
+ networks: [
+ {
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ {
+ genesisHash: 'IXnoWtviVVJW5LGivNFc0Dq14V3kqaXuK2u5OQrdVZo=',
+ genesisId: 'voitest-v1',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ ],
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ }
+ */
+});
+
+// broadcast a discover request
+client.discover({ providerId });
+```
- ```typescript
- import { BaseARC0027Error, IDiscoverResult } from '@agoralabs-sh/avm-web-provider';
-
- const providerId: string = '02657eaf-be17-4efc-b0a4-19d654b2448e';
-
- // initialized client
- client.onDiscover((result: IDiscoverResult: null, error: BaseARC0027Error | null) => {
- if (error) {
- console.error('error:', error);
-
- return;
- }
-
- // if the provider is not the specified provider, we can ignore
- if (result?.providerId !== providerId) {
- return;
- }
-
- // handle result
- });
- client.discover({ providerId });
- ```
+```typescript
+import { BaseARC0027Error, IDiscoverResult } from '@agoralabs-sh/avm-web-provider';
+
+const providerId: string = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized client
+client.onDiscover((result: IDiscoverResult: null, error: BaseARC0027Error | null) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ host: 'https://awesome-wallet.com',
+ name: 'Awesome Wallet',
+ networks: [
+ {
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ {
+ genesisHash: 'IXnoWtviVVJW5LGivNFc0Dq14V3kqaXuK2u5OQrdVZo=',
+ genesisId: 'voitest-v1',
+ methods: [
+ 'disable',
+ 'enable',
+ 'post_transactions',
+ 'sign_and_post_transactions',
+ 'sign_transactions',
+ ],
+ },
+ ],
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ }
+ */
+});
+
+// broadcast a discover request
+client.discover({ providerId });
+```
diff --git a/docs/clients/enabling-a-client.mdx b/docs/clients/enabling-a-client.mdx
new file mode 100644
index 0000000..e9ce0dc
--- /dev/null
+++ b/docs/clients/enabling-a-client.mdx
@@ -0,0 +1,313 @@
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import TOCInline from '@theme/TOCInline';
+
+# Enabling A Client
+
+
+
+## Overview
+
+Before we can start interacting with a provider, we need ask the provider to enable the client. This will achieve two things:
+
+* if necessary, it will authorize your client with the provider; and
+* it will get a list of the authorized accounts available to your client.
+
+:::note
+
+It should be safe to call [`enable()`](../../api-reference/avm-web-client#enable) as many times as your client needs; the provider should assume this.
+
+:::
+
+:::caution
+
+The definition of "enabling" for a provider can mean different things to different providers, but it is highly recommended that you first run [`enable()`](../../api-reference/avm-web-client#enable) before attempting any signing/post methods.
+
+:::
+
+## Enabling the client with all providers
+
+After [initialization](getting-started), you can simply call:
+
+
+
+
+```js
+// initialized client
+client.onEnable((result, error) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable();
+```
+
+
+
+
+```typescript
+import type { BaseARC0027Error, IEnableResult } from '@agoralabs-sh/avm-web-provider';
+
+// initialized client
+client.onEnable((result: IEnableResult: null, error: BaseARC0027Error | null) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable();
+```
+
+
+
+
+:::caution
+
+If any providers do not support the `enable` method, then a [`MethodNotSupportedError`](../../api-reference/errors#methodnotsupportederror) will be returned.
+
+:::
+
+## Enabling the client with a specific provider
+
+If you want to target a specific provider, you can simply pass the ID of the provider in the params:
+
+
+
+
+```js
+const providerId = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized client
+client.onEnable((result, error) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable({ providerId });
+ ```
+
+
+
+
+```typescript
+import type { BaseARC0027Error, IEnableResult } from '@agoralabs-sh/avm-web-provider';
+
+ const providerId: string = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized client
+client.onEnable((result: IEnableResult: null, error: BaseARC0027Error | null) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable({ providerId });
+```
+
+
+
+
+## Enabling a client on a specific network
+
+If you want to target a specific network, and any providers support it, you can simply pass the genesis hash of the network in the params:
+
+
+
+
+```js
+const genesisHash = 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=';
+
+// initialized client
+client.onEnable((result, error) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable({ genesisHash });
+```
+
+
+
+
+```typescript
+import type { BaseARC0027Error, IEnableResult } from '@agoralabs-sh/avm-web-provider';
+
+const genesisHash: string = 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=';
+
+// initialized client
+client.onEnable((result: IEnableResult: null, error: BaseARC0027Error | null) => {
+ if (error) {
+ console.error('error:', error);
+
+ return;
+ }
+
+ console.log(result);
+ /*
+ {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ sessionId: 'ab192498-0c63-4028-80fd-f148710611d8',
+ }
+ */
+});
+
+// broadcast an enable request
+client.enable({ genesisHash });
+```
+
+
+
+
+:::caution
+
+If the network and the provider ID is specified, and the provider does not support the network, then a [`NetworkNotSupportedError`](../../api-reference/errors#networknotsupportederror) will be thrown.
+
+:::
diff --git a/docs/clients/index.md b/docs/clients/index.md
index b440ef2..5832233 100644
--- a/docs/clients/index.md
+++ b/docs/clients/index.md
@@ -2,3 +2,4 @@
* [Getting Started](clients/getting-started)
* [Discover Providers](clients/discover-providers)
+* [Enabling A Client](clients/enabling-a-client)
diff --git a/docs/providers/index.md b/docs/providers/index.md
index d2a55fd..98f049d 100644
--- a/docs/providers/index.md
+++ b/docs/providers/index.md
@@ -2,3 +2,4 @@
* [Getting Started](providers/getting-started)
* [Responding To Discover Requests](providers/responding-to-discover-requests)
+* [Responding To Enable Requests](providers/responding-to-enable-requests)
diff --git a/docs/providers/responding-to-enable-requests.mdx b/docs/providers/responding-to-enable-requests.mdx
new file mode 100644
index 0000000..fb01498
--- /dev/null
+++ b/docs/providers/responding-to-enable-requests.mdx
@@ -0,0 +1,150 @@
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import TOCInline from '@theme/TOCInline';
+
+# Responding To Enable Requests
+
+
+
+## Overview
+
+The main purpose of an enable request to is for clients to get a list of authorized accounts. However, it can be used to handle sessioning. While it is not enforced through this SDK, it is heavily recommended.
+
+## Responding to an anonymous request
+
+For clients that have not specified a provider, it means the client would like to enable with all providers. Once our provider object has been initialized, we can simply listen to events and respond:
+
+
+
+
+```js
+// initialized provider
+provider.onEnable((params) => {
+ if (!params || !params.providerId) {
+ return {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ };
+ }
+});
+```
+
+
+
+
+```typescript
+import type { IEnableParams } from '@agoralabs-sh/avm-web-provider';
+
+// initialized provider
+provider.onEnable((params?: IEnableParams) => {
+ if (!params || !params.providerId) {
+ return {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId: '02657eaf-be17-4efc-b0a4-19d654b2448e',
+ };
+ }
+});
+```
+
+
+
+
+## Responding to a specific provider request
+
+The `enable` request allows the client to specify the provider. This is denoted in the supplied `params.providerId` parameter. Providers with the matching ID should respond:
+
+
+
+
+```js
+const providerId = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized provider
+provider.onEnable((params) => {
+ if (!params || params.providerId === providerId) {
+ return {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId,
+ };
+ }
+});
+```
+
+
+
+
+```typescript
+import type { IEnableParams } from '@agoralabs-sh/avm-web-provider';
+
+const providerId: string = '02657eaf-be17-4efc-b0a4-19d654b2448e';
+
+// initialized provider
+provider.onEnable((params?: IEnableParams) => {
+ if (!params || params.providerId === providerId) {
+ return {
+ accounts: [
+ {
+ address: 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address: '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=',
+ genesisId: 'testnet-v1.0',
+ providerId,
+ };
+ }
+});
+```
+
+
+
diff --git a/docs/scripts/sidebars.js b/docs/scripts/sidebars.js
index e56f4c0..b6de1b6 100644
--- a/docs/scripts/sidebars.js
+++ b/docs/scripts/sidebars.js
@@ -4,8 +4,13 @@
const sidebars = {
docs: [
'overview',
+ 'terminology',
{
- items: ['clients/getting-started', 'clients/discover-providers'],
+ items: [
+ 'clients/getting-started',
+ 'clients/discover-providers',
+ 'clients/enabling-a-client',
+ ],
label: 'Clients',
link: {
type: 'doc',
@@ -17,6 +22,7 @@ const sidebars = {
items: [
'providers/getting-started',
'providers/responding-to-discover-requests',
+ 'providers/responding-to-enable-requests',
],
label: 'Providers',
link: {
@@ -25,7 +31,6 @@ const sidebars = {
},
type: 'category',
},
- 'terminology',
{
items: [
'api-reference/avm-web-client',
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 02a70b9..dfe080e 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -18,7 +18,7 @@ const url = 'https://avm-web-provider.agoralabs.sh';
// header
const tagline =
- 'A TypeScript implementation that allows dApps to connect and interact with web-based providers.';
+ 'A TypeScript implementation that allows clients to connect and interact with web-based providers.';
const title = 'AVM Web Provider';
/** @type {import('@docusaurus/types').Config} */
diff --git a/package.json b/package.json
index 260dde9..269922c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@agoralabs-sh/avm-web-provider",
"version": "1.0.0-beta.1",
- "description": "A TypeScript implementation that allows dApps to connect and interact with web-based providers.",
+ "description": "A TypeScript implementation that allows clients to connect and interact with web-based providers.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
@@ -24,7 +24,8 @@
"algosdk",
"arc0027",
"avm",
- "blockchain"
+ "blockchain",
+ "voi"
],
"private": false,
"engines": {
diff --git a/src/controllers/AVMWebClient.test.ts b/src/controllers/AVMWebClient.test.ts
index 14ec7bb..f11014a 100644
--- a/src/controllers/AVMWebClient.test.ts
+++ b/src/controllers/AVMWebClient.test.ts
@@ -8,7 +8,12 @@ import AVMWebProvider from './AVMWebProvider';
import { ARC0027MethodEnum } from '@app/enums';
// types
-import { IAVMWebClientConfig, IDiscoverResult } from '@app/types';
+import {
+ IAVMWebClientConfig,
+ IDiscoverResult,
+ IEnableResult,
+} from '@app/types';
+import { ARC0027MethodNotSupportedError } from '@app/errors';
describe(AVMWebClient.name, () => {
const providerId: string = '02657eaf-be17-4efc-b0a4-19d654b2448e';
@@ -95,4 +100,67 @@ describe(AVMWebClient.name, () => {
client.discover();
});
});
+
+ describe(`${AVMWebClient.name}#enable`, () => {
+ it('should return an error', (done) => {
+ // arrange
+ const expectedError: ARC0027MethodNotSupportedError =
+ new ARC0027MethodNotSupportedError({
+ method: ARC0027MethodEnum.Enable,
+ providerId,
+ });
+
+ provider = AVMWebProvider.init(providerId);
+ client = AVMWebClient.init();
+
+ provider.onEnable(async () => await Promise.reject(expectedError));
+ client.onEnable((result, error) => {
+ // assert
+ expect(result).toBeNull();
+ expect(error).toEqual(expectedError);
+
+ done();
+ });
+
+ // act
+ client.enable();
+ });
+
+ it('should return the account information', (done) => {
+ // arrange
+ const expectedResult: IEnableResult = {
+ accounts: [
+ {
+ address:
+ 'P3AIQVDJ2CTH54KSJE63YWB7IZGS4W4JGC53I6GK72BGZ5BXO2B2PS4M4U',
+ name: 'Wallet-1',
+ },
+ {
+ address:
+ '6GT6EXFDAHZDZYUOPT725ZRWYBZDCEGYT7SYYXGJKRFUAG5B7JMI7DQRNQ',
+ name: 'Wallet-2',
+ },
+ ],
+ genesisHash: randomBytes(32).toString('base64'),
+ genesisId: 'jest-test-v1.0',
+ providerId,
+ };
+
+ provider = AVMWebProvider.init(providerId);
+ client = AVMWebClient.init();
+
+ provider.onEnable(() => expectedResult);
+ client.onEnable((result, error) => {
+ // assert
+ expect(error).toBeNull();
+ expect(result).toBeDefined();
+ expect(result).toEqual(expectedResult);
+
+ done();
+ });
+
+ // act
+ client.enable();
+ });
+ });
});
diff --git a/src/controllers/AVMWebClient.ts b/src/controllers/AVMWebClient.ts
index c576a1a..9238a24 100644
--- a/src/controllers/AVMWebClient.ts
+++ b/src/controllers/AVMWebClient.ts
@@ -19,6 +19,8 @@ import type {
IAVMWebClientInitOptions,
IDiscoverParams,
IDiscoverResult,
+ IEnableParams,
+ IEnableResult,
ISendRequestMessageOptions,
TAVMWebClientListener,
TRequestParams,
@@ -101,6 +103,7 @@ export default class AVMWebClient extends BaseController {
if (listener && this.requestIds.includes(message.data.requestId)) {
switch (message.data.reference) {
case `${createMessageReference(ARC0027MethodEnum.Discover, ARC0027MessageTypeEnum.Response)}`:
+ case `${createMessageReference(ARC0027MethodEnum.Enable, ARC0027MessageTypeEnum.Response)}`:
this.logger.debug(
`${AVMWebClient.name}#${_functionName}: received response message "${JSON.stringify(message.data)}"`
);
@@ -143,6 +146,18 @@ export default class AVMWebClient extends BaseController {
});
}
+ /**
+ * Enables to a client with providers. If the ID of the provider and/or network is specified, that provider/network is
+ * used, otherwise the default provider is enabled.
+ * @param {IEnableParams} params - [optional] params that specify the provider and/or the network.
+ */
+ public enable(params?: IEnableParams): void {
+ return this.sendRequestMessage({
+ method: ARC0027MethodEnum.Enable,
+ params,
+ });
+ }
+
/**
* Listens to discover messages sent from providers. This will replace any previous set listeners. If null is
* supplied, the listener will be removed.
@@ -164,4 +179,26 @@ export default class AVMWebClient extends BaseController {
this.listeners.set(responseReference, listener);
}
+
+ /**
+ * Listens to enable messages sent from providers. This will replace any previous set listeners. If null is supplied,
+ * the listener will be removed.
+ * @param {TAVMWebClientListener | null} listener - callback that is called when a response message
+ * is received, or null to remove the listener.
+ */
+ onEnable(listener: TAVMWebClientListener | null): void {
+ const responseReference: string = createMessageReference(
+ ARC0027MethodEnum.Enable,
+ ARC0027MessageTypeEnum.Response
+ );
+
+ // if the listener is null, delete it from the map
+ if (!listener) {
+ this.listeners.delete(responseReference);
+
+ return;
+ }
+
+ this.listeners.set(responseReference, listener);
+ }
}
diff --git a/src/controllers/AVMWebProvider.test.ts b/src/controllers/AVMWebProvider.test.ts
index e0c7784..c1701e0 100644
--- a/src/controllers/AVMWebProvider.test.ts
+++ b/src/controllers/AVMWebProvider.test.ts
@@ -53,7 +53,7 @@ describe(AVMWebProvider.name, () => {
});
describe(`${AVMWebProvider.name}#onDiscover`, () => {
- it('should return receive the client request', (done) => {
+ it('should receive the client request', (done) => {
// arrange
provider = AVMWebProvider.init(providerId);
client = AVMWebClient.init();
@@ -65,4 +65,18 @@ describe(AVMWebProvider.name, () => {
client.discover();
});
});
+
+ describe(`${AVMWebProvider.name}#onEnable`, () => {
+ it('should receive the client request', (done) => {
+ // arrange
+ provider = AVMWebProvider.init(providerId);
+ client = AVMWebClient.init();
+
+ // assert
+ provider.onEnable(done);
+
+ // act
+ client.enable();
+ });
+ });
});
diff --git a/src/controllers/AVMWebProvider.ts b/src/controllers/AVMWebProvider.ts
index ab76bdb..fae265e 100644
--- a/src/controllers/AVMWebProvider.ts
+++ b/src/controllers/AVMWebProvider.ts
@@ -23,6 +23,8 @@ import type {
IAVMWebProviderInitOptions,
IDiscoverParams,
IDiscoverResult,
+ IEnableParams,
+ IEnableResult,
ISendResponseMessageOptions,
TAVMWebProviderListener,
TResponseResults,
@@ -121,18 +123,27 @@ export default class AVMWebProvider extends BaseController {
const listener: TAVMWebProviderListener | null =
this.listeners.get(message.data.reference) || null;
+ let method: ARC0027MethodEnum | null = null;
if (listener) {
switch (message.data.reference) {
case `${createMessageReference(ARC0027MethodEnum.Discover, ARC0027MessageTypeEnum.Request)}`:
- return await this.sendResponseMessage({
- method: ARC0027MethodEnum.Discover,
- listener,
- requestMessage: message.data,
- });
+ method = ARC0027MethodEnum.Discover;
+ break;
+ case `${createMessageReference(ARC0027MethodEnum.Enable, ARC0027MessageTypeEnum.Request)}`:
+ method = ARC0027MethodEnum.Enable;
+ break;
default:
break;
}
+
+ if (method) {
+ return await this.sendResponseMessage({
+ method,
+ listener,
+ requestMessage: message.data,
+ });
+ }
}
}
@@ -177,4 +188,28 @@ export default class AVMWebProvider extends BaseController | null} listener - the listener to call when the
+ * request message is sent, or null to remove the listener.
+ */
+ onEnable(
+ listener: TAVMWebProviderListener | null
+ ): void {
+ const requestReference: string = createMessageReference(
+ ARC0027MethodEnum.Enable,
+ ARC0027MessageTypeEnum.Request
+ );
+
+ // if the listener is null, delete it from the map
+ if (!listener) {
+ this.listeners.delete(requestReference);
+
+ return;
+ }
+
+ this.listeners.set(requestReference, listener);
+ }
}
diff --git a/src/errors/ARC0027MethodNotSupportedError.ts b/src/errors/ARC0027MethodNotSupportedError.ts
index 7281a11..61a91e0 100644
--- a/src/errors/ARC0027MethodNotSupportedError.ts
+++ b/src/errors/ARC0027MethodNotSupportedError.ts
@@ -13,7 +13,7 @@ interface IOptions {
providerId: string;
}
-export default class SerializableARC0027MethodSupportedError extends BaseARC0027Error {
+export default class ARC0027MethodSupportedError extends BaseARC0027Error {
public readonly code: ARC0027ErrorCodeEnum =
ARC0027ErrorCodeEnum.MethodNotSupportedError;
public readonly data: IData;
diff --git a/src/types/IAccount.ts b/src/types/IAccount.ts
new file mode 100644
index 0000000..b65928e
--- /dev/null
+++ b/src/types/IAccount.ts
@@ -0,0 +1,10 @@
+/**
+ * @property {string} address - the address of the account.
+ * @property {string} name - [optional] a human-readable name for this account.
+ */
+interface IAccount {
+ address: string;
+ name?: string;
+}
+
+export default IAccount;
diff --git a/src/types/IEnableParams.ts b/src/types/IEnableParams.ts
new file mode 100644
index 0000000..701e77b
--- /dev/null
+++ b/src/types/IEnableParams.ts
@@ -0,0 +1,11 @@
+/**
+ * @property {string} genesisHash - [optional] the unique identifier for the network that is the hash of the genesis
+ * block.
+ * @property {string} providerId - [optional] a unique identifier for the provider.
+ */
+interface IEnableParams {
+ genesisHash?: string;
+ providerId?: string;
+}
+
+export default IEnableParams;
diff --git a/src/types/IEnableResult.ts b/src/types/IEnableResult.ts
new file mode 100644
index 0000000..6aec752
--- /dev/null
+++ b/src/types/IEnableResult.ts
@@ -0,0 +1,19 @@
+// types
+import type IAccount from './IAccount';
+
+/**
+ * @property {IAccount[]} accounts - a list of accounts authorized accounts on the provider.
+ * @property {string} genesisHash - the unique identifier for the network that is the hash of the genesis block.
+ * @property {string} genesisId - a human-readable identifier for the network.
+ * @property {string} providerId - a unique identifier for the provider.
+ * @property {string} sessionId - [optional] a unique identifier for the session as defined by the provider.
+ */
+interface IEnableResult {
+ accounts: IAccount[];
+ genesisHash: string;
+ genesisId: string;
+ providerId: string;
+ sessionId?: string;
+}
+
+export default IEnableResult;
diff --git a/src/types/TRequestParams.ts b/src/types/TRequestParams.ts
index 9c16423..7830e86 100644
--- a/src/types/TRequestParams.ts
+++ b/src/types/TRequestParams.ts
@@ -1,6 +1,7 @@
// types
import type IDiscoverParams from './IDiscoverParams';
+import type IEnableParams from './IEnableParams';
-type TRequestParams = IDiscoverParams;
+type TRequestParams = IDiscoverParams | IEnableParams;
export default TRequestParams;
diff --git a/src/types/TResponseResults.ts b/src/types/TResponseResults.ts
index 8cd272a..1dd43cc 100644
--- a/src/types/TResponseResults.ts
+++ b/src/types/TResponseResults.ts
@@ -1,6 +1,7 @@
// types
import type IDiscoverResult from './IDiscoverResult';
+import type IEnableResult from './IEnableResult';
-type TResponseResults = IDiscoverResult;
+type TResponseResults = IDiscoverResult | IEnableResult;
export default TResponseResults;
diff --git a/src/types/index.ts b/src/types/index.ts
index 8136691..ed51c4b 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,3 +1,4 @@
+export type { default as IAccount } from './IAccount';
export type { default as IAVMWebClientConfig } from './IAVMWebClientConfig';
export type { default as IAVMWebClientInitOptions } from './IAVMWebClientInitOptions';
export type { default as IAVMWebProviderConfig } from './IAVMWebProviderConfig';
@@ -6,6 +7,8 @@ export type { default as IBaseConfig } from './IBaseConfig';
export type { default as IBaseResponseMessage } from './IBaseResponseMessage';
export type { default as IDiscoverParams } from './IDiscoverParams';
export type { default as IDiscoverResult } from './IDiscoverResult';
+export type { default as IEnableParams } from './IEnableParams';
+export type { default as IEnableResult } from './IEnableResult';
export type { default as INetworkConfiguration } from './INetworkConfiguration';
export type { default as IRequestMessage } from './IRequestMessage';
export type { default as IResponseMessageWithResult } from './IResponseMessageWithResult';