@txnlab/use-wallet 1.3.2 → 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +509 -188
  2. package/dist/cjs/index.js +234 -129
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/jest.config.d.ts +7 -0
  5. package/dist/cjs/src/clients/algosigner/client.d.ts +3 -3
  6. package/dist/cjs/src/clients/algosigner/types.d.ts +2 -8
  7. package/dist/cjs/src/clients/base/base.d.ts +3 -2
  8. package/dist/cjs/src/clients/base/index.d.ts +2 -2
  9. package/dist/cjs/src/clients/daffi/client.d.ts +5 -4
  10. package/dist/cjs/src/clients/daffi/types.d.ts +5 -7
  11. package/dist/cjs/src/clients/defly/client.d.ts +6 -5
  12. package/dist/cjs/src/clients/defly/types.d.ts +5 -7
  13. package/dist/cjs/src/clients/exodus/client.d.ts +6 -5
  14. package/dist/cjs/src/clients/exodus/types.d.ts +5 -10
  15. package/dist/cjs/src/clients/index.d.ts +1 -1
  16. package/dist/cjs/src/clients/kmd/client.d.ts +4 -5
  17. package/dist/cjs/src/clients/kmd/types.d.ts +4 -9
  18. package/dist/cjs/src/clients/mnemonic/client.d.ts +4 -5
  19. package/dist/cjs/src/clients/mnemonic/types.d.ts +2 -9
  20. package/dist/cjs/src/clients/myalgo/client.d.ts +6 -5
  21. package/dist/cjs/src/clients/myalgo/types.d.ts +10 -12
  22. package/dist/cjs/src/clients/pera/client.d.ts +6 -5
  23. package/dist/cjs/src/clients/pera/types.d.ts +5 -7
  24. package/dist/cjs/src/clients/{walletconnect → walletconnect2}/client.d.ts +8 -7
  25. package/dist/cjs/src/clients/walletconnect2/constants.d.ts +6 -0
  26. package/dist/cjs/src/clients/walletconnect2/index.d.ts +2 -0
  27. package/dist/cjs/src/clients/walletconnect2/types.d.ts +37 -0
  28. package/dist/cjs/src/clients/walletconnect2/utils.d.ts +2 -0
  29. package/dist/cjs/src/hooks/index.d.ts +1 -0
  30. package/dist/cjs/src/hooks/useInitializeProviders.d.ts +9 -0
  31. package/dist/cjs/src/hooks/useInitializeProviders.test.d.ts +4 -0
  32. package/dist/cjs/src/hooks/useWallet.d.ts +4 -13
  33. package/dist/cjs/src/hooks/useWallet.test.d.ts +4 -0
  34. package/dist/cjs/src/index.d.ts +1 -1
  35. package/dist/cjs/src/store/state/clientStore.d.ts +2 -23
  36. package/dist/cjs/src/testUtils/createWrapper.d.ts +6 -0
  37. package/dist/cjs/src/testUtils/mockAccounts.d.ts +3 -0
  38. package/dist/cjs/src/testUtils/mockClients.d.ts +33 -0
  39. package/dist/cjs/src/types/index.d.ts +1 -0
  40. package/dist/cjs/src/types/node.d.ts +2 -1
  41. package/dist/cjs/src/types/providers.d.ts +71 -0
  42. package/dist/cjs/src/types/wallet.d.ts +5 -3
  43. package/dist/cjs/src/utils/clearAccounts.d.ts +1 -1
  44. package/dist/cjs/src/utils/encodeNFDTransactionArray.spec.d.ts +1 -0
  45. package/dist/cjs/src/utils/initializeProviders.d.ts +2 -12
  46. package/dist/cjs/src/utils/initializeProviders.test.d.ts +4 -0
  47. package/dist/cjs/src/utils/providers.d.ts +1 -1
  48. package/dist/cjs/src/utils/providers.spec.d.ts +1 -0
  49. package/dist/cjs/src/utils/reconnectProviders.d.ts +1 -5
  50. package/dist/cjs/src/utils/reconnectProviders.test.d.ts +1 -0
  51. package/dist/cjs/src/utils/types.d.ts +2 -0
  52. package/dist/esm/index.js +234 -130
  53. package/dist/esm/jest.config.d.ts +7 -0
  54. package/dist/esm/src/clients/algosigner/client.d.ts +3 -3
  55. package/dist/esm/src/clients/algosigner/types.d.ts +2 -8
  56. package/dist/esm/src/clients/base/base.d.ts +3 -2
  57. package/dist/esm/src/clients/base/index.d.ts +2 -2
  58. package/dist/esm/src/clients/daffi/client.d.ts +5 -4
  59. package/dist/esm/src/clients/daffi/types.d.ts +5 -7
  60. package/dist/esm/src/clients/defly/client.d.ts +6 -5
  61. package/dist/esm/src/clients/defly/types.d.ts +5 -7
  62. package/dist/esm/src/clients/exodus/client.d.ts +6 -5
  63. package/dist/esm/src/clients/exodus/types.d.ts +5 -10
  64. package/dist/esm/src/clients/index.d.ts +1 -1
  65. package/dist/esm/src/clients/kmd/client.d.ts +4 -5
  66. package/dist/esm/src/clients/kmd/types.d.ts +4 -9
  67. package/dist/esm/src/clients/mnemonic/client.d.ts +4 -5
  68. package/dist/esm/src/clients/mnemonic/types.d.ts +2 -9
  69. package/dist/esm/src/clients/myalgo/client.d.ts +6 -5
  70. package/dist/esm/src/clients/myalgo/types.d.ts +10 -12
  71. package/dist/esm/src/clients/pera/client.d.ts +6 -5
  72. package/dist/esm/src/clients/pera/types.d.ts +5 -7
  73. package/dist/esm/src/clients/{walletconnect → walletconnect2}/client.d.ts +8 -7
  74. package/dist/esm/src/clients/walletconnect2/constants.d.ts +6 -0
  75. package/dist/esm/src/clients/walletconnect2/index.d.ts +2 -0
  76. package/dist/esm/src/clients/walletconnect2/types.d.ts +37 -0
  77. package/dist/esm/src/clients/walletconnect2/utils.d.ts +2 -0
  78. package/dist/esm/src/hooks/index.d.ts +1 -0
  79. package/dist/esm/src/hooks/useInitializeProviders.d.ts +9 -0
  80. package/dist/esm/src/hooks/useInitializeProviders.test.d.ts +4 -0
  81. package/dist/esm/src/hooks/useWallet.d.ts +4 -13
  82. package/dist/esm/src/hooks/useWallet.test.d.ts +4 -0
  83. package/dist/esm/src/index.d.ts +1 -1
  84. package/dist/esm/src/store/state/clientStore.d.ts +2 -23
  85. package/dist/esm/src/testUtils/createWrapper.d.ts +6 -0
  86. package/dist/esm/src/testUtils/mockAccounts.d.ts +3 -0
  87. package/dist/esm/src/testUtils/mockClients.d.ts +33 -0
  88. package/dist/esm/src/types/index.d.ts +1 -0
  89. package/dist/esm/src/types/node.d.ts +2 -1
  90. package/dist/esm/src/types/providers.d.ts +71 -0
  91. package/dist/esm/src/types/wallet.d.ts +5 -3
  92. package/dist/esm/src/utils/clearAccounts.d.ts +1 -1
  93. package/dist/esm/src/utils/encodeNFDTransactionArray.spec.d.ts +1 -0
  94. package/dist/esm/src/utils/initializeProviders.d.ts +2 -12
  95. package/dist/esm/src/utils/initializeProviders.test.d.ts +4 -0
  96. package/dist/esm/src/utils/providers.d.ts +1 -1
  97. package/dist/esm/src/utils/providers.spec.d.ts +1 -0
  98. package/dist/esm/src/utils/reconnectProviders.d.ts +1 -5
  99. package/dist/esm/src/utils/reconnectProviders.test.d.ts +1 -0
  100. package/dist/esm/src/utils/types.d.ts +2 -0
  101. package/dist/index.d.ts +239 -254
  102. package/package.json +15 -18
  103. package/dist/cjs/src/clients/walletconnect/constants.d.ts +0 -2
  104. package/dist/cjs/src/clients/walletconnect/index.d.ts +0 -2
  105. package/dist/cjs/src/clients/walletconnect/types.d.ts +0 -55
  106. package/dist/esm/src/clients/walletconnect/constants.d.ts +0 -2
  107. package/dist/esm/src/clients/walletconnect/index.d.ts +0 -2
  108. package/dist/esm/src/clients/walletconnect/types.d.ts +0 -55
package/README.md CHANGED
@@ -1,115 +1,208 @@
1
- # @TxnLab/use-wallet
1
+ # @txnlab/use-wallet
2
2
 
3
- React hooks for using Algorand compatible wallets with web applications. Flexible and extensible, `use-wallet` supports a variety of wallets and connection protocols. It also provides a simple interface for connecting, disconnecting, switching between accounts and signing transactions.
3
+ `@txnlab/use-wallet` is a React library that provides a simplified, consistent interface for integrating multiple Algorand wallets into your decentralized applications (dApps).
4
4
 
5
- ## Supported Providers
5
+ ## Overview
6
6
 
7
- - [Pera](https://perawallet.app/)
8
- - [MyAlgo](https://wallet.myalgo.com/home)
9
- - [Defly](https://defly.app)
10
- - [AlgoSigner](https://www.purestake.com/technology/algosigner)
11
- - [Exodus](https://www.exodus.com)
12
- - [WalletConnect](https://walletconnect.com)
13
- - [Daffi](https://www.daffi.me/)
14
- - [KMD](https://developer.algorand.org/docs/rest-apis/kmd)
7
+ With the `useWallet` hook and utility functions, you can:
15
8
 
16
- ## Demo
9
+ - Easily add or remove wallet support with a few lines of code
10
+ - Configure each wallet provider as needed for your application
11
+ - Allow users to easily switch between active accounts and wallet providers
12
+ - Sign and send transactions
13
+ - Restore sessions for returning users
17
14
 
18
- Preview a basic implementation in [Storybook](https://txnlab.github.io/use-wallet) or check out [this example](https://github.com/gabrielkuettel/use-wallet-example).
15
+ This library supports most Algorand wallet providers, including Defly, Pera, Daffi, and Exodus (see [Supported Wallet Providers](#supported-wallet-providers) for the full list).
19
16
 
20
- ## Quick Start
17
+ <!-- It provides an abstraction layer that handles the initialization, connection, and transaction signing logic, eliminating the need to interact with each wallet's individual API. -->
21
18
 
22
- ### Yarn
19
+ As of version 2.x it includes [WalletConnect 2.0 support](#walletconnect-20-support).
23
20
 
24
- ```bash
25
- yarn add @txnlab/use-wallet
26
- ```
21
+ ## Table of Contents
22
+
23
+ - [Live Examples](#live-examples)
24
+ - [Installation](#installation)
25
+ - [Initializing Providers](#initializing-providers)
26
+ - [The `useWallet` Hook](#the-usewallet-hook)
27
+ - [Type Definitions](#type-definitions)
28
+ - [Connect Menu](#connect-menu)
29
+ - [Displaying Account Details](#displaying-account-details)
30
+ - [Signing and Sending Transactions](#signing-and-sending-transactions)
31
+ - [Checking Connection Status](#checking-connection-status)
32
+ - [Supported Wallet Providers](#supported-wallet-providers)
33
+ - [Legacy Wallet Support](#legacy-wallet-support)
34
+ - [Provider Configuration](#provider-configuration)
35
+ - [Default configuration](#default-configuration)
36
+ - [Node configuration](#node-configuration)
37
+ - [Customize provider support](#customize-provider-support)
38
+ - [Provider objects](#provider-objects)
39
+ - [Static imports](#static-imports)
40
+ - [WalletConnect 2.0 Support](#walletconnect-20-support)
41
+ - [Migration Guide](#migration-guide)
42
+ - [Local Development](#local-development)
43
+ - [Used By](#used-by)
44
+ - [License](#license)
45
+
46
+ ## Live Examples
47
+
48
+ **Storybook demo** - https://txnlab.github.io/use-wallet
49
+
50
+ **Next.js example**
51
+
52
+ - Demo - https://next-use-wallet.vercel.app/
53
+ - Code - https://github.com/TxnLab/next-use-wallet
27
54
 
28
- Install peer dependencies (if needed)
55
+ **NFDomains** - https://app.nf.domains/
56
+
57
+ ## Installation
58
+
59
+ Since this library uses React Hooks, your app will need to be using React 16.8 or higher.
60
+
61
+ First, install the library
29
62
 
30
63
  ```bash
31
- yarn add algosdk @blockshake/defly-connect @perawallet/connect @randlabs/myalgo-connect @walletconnect/client algorand-walletconnect-qrcode-modal @json-rpc-tools/utils @daffiwallet/connect
64
+ npm install @txnlab/use-wallet
32
65
  ```
33
66
 
34
- ### NPM
67
+ If you haven't already, install the Algorand JS SDK
35
68
 
36
69
  ```bash
37
- npm install @txnlab/use-wallet
70
+ npm install algosdk
38
71
  ```
39
72
 
40
- Install peer dependencies (if needed)
73
+ Finally, install the peer dependencies for the wallets you wish to support. To use the default configuration:
41
74
 
42
75
  ```bash
43
- npm install algosdk @blockshake/defly-connect @perawallet/connect @randlabs/myalgo-connect @walletconnect/client algorand-walletconnect-qrcode-modal @json-rpc-tools/utils @daffiwallet/connect
76
+ npm install @perawallet/connect @blockshake/defly-connect @daffiwallet/connect
44
77
  ```
45
78
 
46
- ### Set up the Wallet Provider
79
+ Replace `npm install` with `yarn add` or `pnpm add` in the commands above, depending on your preferred package manager.
80
+
81
+ ## Initializing Providers
47
82
 
48
- In `app.js`, initialize the Wallet Provider so that the `useWallet` hook can be used in the child components, and use the `reconnectProviders` function to restore sessions for users returning to the app.
83
+ In the root of your app, initialize the `WalletProvider` with the `useInitializeProviders` hook.
84
+
85
+ This example initializes `useWallet` with the default configuration options. See [Provider Configuration](#provider-configuration) for more options.
49
86
 
50
87
  ```jsx
51
88
  import React from 'react'
52
- import { reconnectProviders, initializeProviders, WalletProvider } from '@txnlab/use-wallet'
53
-
54
- const walletProviders = initializeProviders()
89
+ import { WalletProvider, useInitializeProviders } from '@txnlab/use-wallet'
55
90
 
56
91
  export default function App() {
57
- // Reconnect the session when the user returns to the dApp
58
- React.useEffect(() => {
59
- reconnectProviders(walletProviders)
60
- }, [])
92
+ // default configuration
93
+ const providers = useInitializeProviders()
94
+
95
+ return (
96
+ <WalletProvider value={providers}>
97
+ <div className="App">{/* ... */}</div>
98
+ </WalletProvider>
99
+ )
100
+ }
101
+ ```
61
102
 
62
- return <WalletProvider value={walletProviders}>...</WalletProvider>
103
+ ## The `useWallet` Hook
104
+
105
+ The `useWallet` hook is used to access wallet provider and account state, send unsigned transactions to be signed, and send signed transactions to the node from anywhere in your app. It returns an object with the following properties:
106
+
107
+ - `providers` - Array of wallet providers that have been initialized (see `Provider` in [Type Definitions](#type-definitions))
108
+ - `activeAccount` - The currently active account in the active provider (see `Account` in [Type Definitions](#type-definitions))
109
+ - `connectedAccounts` - Array of accounts from all connected wallet providers
110
+ - `connectedActiveAccounts` - Array of accounts from the active wallet provider
111
+ - `activeAddress` - The address of `activeAccount`
112
+ - `status`, `isReady`, `isActive` - The current connection status, see [Check connection status](#check-connection-status)
113
+ - `signTransactions` - Function that sends unsigned transactions to active wallet provider for signature
114
+ - `sendTransactions` - Function that sends signed transactions to the node
115
+ - `groupTransactionsBySender` - Utility function that groups transactions by sender address
116
+ - `getAddress` - Utility function that returns the address of the `activeAccount`
117
+ - `getAccountInfo` - Utility function that fetches `activeAccount` account information from the node
118
+ - `getAssets` - Utility function that fetches `activeAccount` asset info/balances from the node
119
+ - `signer` - Function used by the [KMD](#kmd-algorand-key-management-daemon) provider to sign transactions
120
+
121
+ ## Type Definitions
122
+
123
+ ### `Provider`
124
+
125
+ ```ts
126
+ type Provider = {
127
+ accounts: Account[]
128
+ isActive: boolean
129
+ isConnected: boolean
130
+ connect: () => Promise<void>
131
+ disconnect: () => Promise<void>
132
+ reconnect: () => Promise<void>
133
+ setActiveProvider: () => void
134
+ setActiveAccount: (account: string) => void
135
+ metadata: Metadata
63
136
  }
64
137
  ```
65
138
 
66
- The `reconnectProviders` function is used to restore session states of wallets that rely on the `WalletConnect` protocol.
139
+ Each provider has two connection states: `isConnected` and `isActive`.
140
+
141
+ `isConnected` means that the user has authorized the provider in the app. Multiple providers can be connected at the same time.
67
142
 
68
- By default, all of the supported providers except for `KMD` are returned by `useConnectWallet`. An array can be passed to `initializeProviders` to determine which providers your dApp supports, as shown below.
143
+ `isActive` means that the provider is currently active and will be used to sign and send transactions.
69
144
 
70
- ```jsx
71
- import { initializeProviders, PROVIDER_ID } from '@txnlab/use-wallet'
145
+ ### `Account`
72
146
 
73
- const walletProviders = initializeProviders([PROVIDER_ID.KMD_WALLET, PROVIDER_ID.WALLET_CONNECT])
147
+ ```ts
148
+ interface Account {
149
+ providerId: PROVIDER_ID
150
+ name: string
151
+ address: string
152
+ authAddr?: string
153
+ }
74
154
  ```
75
155
 
76
- For more configuration options, see [Provider Configuration](#provider-configuration).
156
+ The `activeAccount` is the account that will be used to sign and send transactions.
77
157
 
78
- ### Connect
158
+ To get the currently active wallet provider, read the `providerId` property of `activeAccount`.
79
159
 
80
- Map through the `providers` object to list the providers and enable users to connect.
160
+ ## Connect Menu
161
+
162
+ In your app's UI you will need a menu for the user to `connect` or `disconnect` wallet providers, `setActiveProvider`, and `setActiveAccount`.
163
+
164
+ This is a bare-bones example for demonstration purposes. For a styled example, see https://app.nf.domains/
81
165
 
82
166
  ```jsx
83
167
  import React from 'react'
84
168
  import { useWallet } from '@txnlab/use-wallet'
85
169
 
86
- export default function Connect() {
170
+ export default function ConnectMenu() {
87
171
  const { providers, activeAccount } = useWallet()
88
172
 
89
- // Map through the providers.
90
- // Render account information and "connect", "set active", and "disconnect" buttons.
91
- // Finally, map through the `accounts` property to render a dropdown for each connected account.
173
+ // 1. Map over `providers` array
174
+ // 2. Show the provider name/icon and "Connect", "Set Active", and "Disconnect" buttons
175
+ // 3. If active, map `provider.accounts` to render a select menu of connected accounts
176
+
92
177
  return (
93
178
  <div>
94
179
  {providers?.map((provider) => (
95
- <div key={'provider-' + provider.metadata.id}>
180
+ <div key={provider.metadata.id}>
96
181
  <h4>
97
- <img width={30} height={30} alt="" src={provider.metadata.icon} />
182
+ <img
183
+ width={30}
184
+ height={30}
185
+ alt={`${provider.metadata.name} icon`}
186
+ src={provider.metadata.icon}
187
+ />
98
188
  {provider.metadata.name} {provider.isActive && '[active]'}
99
189
  </h4>
190
+
100
191
  <div>
101
- <button onClick={provider.connect} disabled={provider.isConnected}>
192
+ <button type="button" onClick={provider.connect} disabled={provider.isConnected}>
102
193
  Connect
103
194
  </button>
104
- <button onClick={provider.disconnect} disabled={!provider.isConnected}>
195
+ <button type="button" onClick={provider.disconnect} disabled={!provider.isConnected}>
105
196
  Disconnect
106
197
  </button>
107
198
  <button
199
+ type="button"
108
200
  onClick={provider.setActiveProvider}
109
201
  disabled={!provider.isConnected || provider.isActive}
110
202
  >
111
203
  Set Active
112
204
  </button>
205
+
113
206
  <div>
114
207
  {provider.isActive && provider.accounts.length && (
115
208
  <select
@@ -132,27 +225,51 @@ export default function Connect() {
132
225
  }
133
226
  ```
134
227
 
135
- Each provider has two connection states: `isConnected` and `isActive`.
228
+ ## Displaying Account Details
136
229
 
137
- `isConnected` means that the user has authorized the provider to talk to the dApp. The connection flow does not need to be restarted when switching to this wallet from a different one.
230
+ The `activeAccount` object can be used to display details for the currently active account.
138
231
 
139
- `isActive` indicates that the provider is currently active and will be used to sign and send transactions when using the `useWallet` hook.
232
+ ```jsx
233
+ import React from 'react'
234
+ import { useWallet } from '@txnlab/use-wallet'
140
235
 
141
- The `activeAccount` is the primary account that is currently active and will be used to sign and send transactions.
236
+ export default function Account() {
237
+ const { activeAccount } = useWallet()
142
238
 
143
- ### Sign and send transactions
239
+ if (!activeAccount) {
240
+ return <p>No account active.</p>
241
+ }
144
242
 
145
- Construct a transaction using `algosdk`, and sign and send the transaction using the `signTransactions` and `sendTransactions` functions provided by the `useWallet` hook.
243
+ return (
244
+ <div>
245
+ <h4>Active Account</h4>
246
+ <p>
247
+ Name: <span>{activeAccount.name}</span>
248
+ </p>
249
+ <p>
250
+ Address: <span>{activeAccount.address}</span>
251
+ </p>
252
+ <p>
253
+ Provider: <span>{activeAccount.providerId}</span>
254
+ </p>
255
+ </div>
256
+ )
257
+ }
258
+ ```
259
+
260
+ ## Signing and Sending Transactions
261
+
262
+ Here is an example of a signing and sending simple pay transaction using `signTransactions` and `sendTransactions`.
146
263
 
147
264
  ```jsx
148
265
  import React from 'react'
266
+ import algosdk from 'algosdk'
149
267
  import {
150
268
  useWallet,
151
269
  DEFAULT_NODE_BASEURL,
152
270
  DEFAULT_NODE_TOKEN,
153
271
  DEFAULT_NODE_PORT
154
272
  } from '@txnlab/use-wallet'
155
- import algosdk from 'algosdk'
156
273
 
157
274
  const algodClient = new algosdk.Algodv2(DEFAULT_NODE_TOKEN, DEFAULT_NODE_BASEURL, DEFAULT_NODE_PORT)
158
275
 
@@ -160,28 +277,29 @@ export default function Transact() {
160
277
  const { activeAddress, signTransactions, sendTransactions } = useWallet()
161
278
 
162
279
  const sendTransaction = async (from?: string, to?: string, amount?: number) => {
163
- if (!from || !to || !amount) {
164
- throw new Error('Missing transaction params.')
280
+ try {
281
+ if (!from || !to || !amount) {
282
+ throw new Error('Missing transaction params.')
283
+ }
284
+
285
+ const suggestedParams = await algodClient.getTransactionParams().do()
286
+
287
+ const transaction = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
288
+ from,
289
+ to,
290
+ amount,
291
+ suggestedParams
292
+ })
293
+
294
+ const encodedTransaction = algosdk.encodeUnsignedTransaction(transaction)
295
+ const signedTransactions = await signTransactions([encodedTransaction])
296
+ const waitRoundsToConfirm = 4
297
+ const { id } = await sendTransactions(signedTransactions, waitRoundsToConfirm)
298
+
299
+ console.log('Successfully sent transaction. Transaction ID: ', id)
300
+ } catch (error) {
301
+ console.error(error)
165
302
  }
166
-
167
- const suggestedParams = await algodClient.getTransactionParams().do()
168
-
169
- const transaction = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
170
- from,
171
- to,
172
- amount,
173
- suggestedParams
174
- })
175
-
176
- const encodedTransaction = algosdk.encodeUnsignedTransaction(transaction)
177
-
178
- const signedTransactions = await signTransactions([encodedTransaction])
179
-
180
- const waitRoundsToConfirm = 4
181
-
182
- const { id } = await sendTransactions(signedTransactions, waitRoundsToConfirm)
183
-
184
- console.log('Successfully sent transaction. Transaction ID: ', id)
185
303
  }
186
304
 
187
305
  if (!activeAddress) {
@@ -190,10 +308,7 @@ export default function Transact() {
190
308
 
191
309
  return (
192
310
  <div>
193
- <button
194
- onClick={() => sendTransaction(activeAddress, activeAddress, 1000)}
195
- className="button"
196
- >
311
+ <button type="button" onClick={() => sendTransaction(activeAddress, activeAddress, 1000)}>
197
312
  Sign and send transactions
198
313
  </button>
199
314
  </div>
@@ -201,41 +316,42 @@ export default function Transact() {
201
316
  }
202
317
  ```
203
318
 
204
- ### Display account details
205
-
206
- The `activeAccount` object can be used to display details for the currently active account. For convenience, the `activeAddress` property shows the currently active address.
319
+ ### signTransactions
207
320
 
208
321
  ```jsx
209
- import React from 'react'
210
- import { useWallet } from '@txnlab/use-wallet'
322
+ const signTransactions: (
323
+ transactions: Uint8Array[] | Uint8Array[][],
324
+ indexesToSign?: number[],
325
+ returnGroup?: boolean // defaults to true
326
+ ) => Promise<Uint8Array[]>
327
+ ```
211
328
 
212
- export default function Account() {
213
- const { activeAccount } = useWallet()
329
+ The `signTransactions` function will accept an array of transactions or an array of transaction groups.
214
330
 
215
- if (!activeAccount) {
216
- return <p>No account active.</p>
217
- }
331
+ You can optionally specify which transactions should be signed by providing an array of indexes as the second argument, `indexesToSign`.
218
332
 
219
- return (
220
- <div>
221
- <h4>Active Account</h4>
222
- <p>
223
- Name: <span>{activeAccount.name}</span>
224
- </p>
225
- <p>
226
- Address: <span>{activeAccount.address}</span>
227
- </p>
228
- <p>
229
- Provider: <span>{activeAccount.providerId}</span>
230
- </p>
231
- </div>
232
- )
233
- }
333
+ By setting `returnGroup` to `false`, the returned promise will resolve to an array of signed transactions only. Otherwise it will return flat array of all transactions by default.
334
+
335
+ ### sendTransactions
336
+
337
+ ```jsx
338
+ const sendTransactions: (
339
+ signedTransactions: Uint8Array[],
340
+ waitRoundsToConfirm?: number
341
+ ) => Promise<PendingTransactionResponse & { id: string }>
234
342
  ```
235
343
 
236
- ### Check connection status
344
+ If `signTransactions` is successful, the returned array of transactions can be passed to `sendTransactions` to be sent to the network.
237
345
 
238
- The `isActive` and `isReady` properties can be used to check the status of the wallets. The `isActive` property determines whether or not an account is currently active. The `isReady` property shows if `use-wallet` has mounted and successfully read the connection status from the providers. These properties are useful when setting up client side access restrictions, for example, by redirecting a user if no wallet is active, as shown below.
346
+ It will wait for confirmation before resolving the promise. Use the optional argument `waitRoundsToConfirm` to indicate how many rounds to wait for confirmation.
347
+
348
+ The promise will resolve to an object containing the transaction `id` and the [`PendingTransactionResponse`](https://developer.algorand.org/docs/rest-apis/algod/#pendingtransactionresponse) from the Algorand REST API.
349
+
350
+ ## Checking Connection Status
351
+
352
+ The `isActive` and `isReady` properties can be used to check the status of the wallet providers. The `isActive` property determines whether or not an account is currently active. The `isReady` property indicates whether `use-wallet` has mounted and successfully read the connection status from the providers.
353
+
354
+ These properties are useful when setting up client side access restrictions, for example, by redirecting a user if no wallet provider `isActive`, as shown below.
239
355
 
240
356
  ```jsx
241
357
  const { isActive, isReady } = useWallet()
@@ -251,107 +367,311 @@ useEffect(() => {
251
367
  })
252
368
  ```
253
369
 
370
+ ## Supported Wallet Providers
371
+
372
+ ### Pera Wallet
373
+
374
+ - Website - https://perawallet.app/
375
+ - Download Pera Mobile - [iOS](https://apps.apple.com/us/app/algorand-wallet/id1459898525) / [Android](https://play.google.com/store/apps/details?id=com.algorand.android)
376
+ - Pera Web Wallet - https://web.perawallet.app/
377
+ - Pera Connect - https://github.com/perawallet/connect
378
+
379
+ ### Defly Wallet
380
+
381
+ - Website - https://defly.app/
382
+ - Download Defly Wallet - [iOS](https://apps.apple.com/us/app/defly/id1602672723) / [Android](https://play.google.com/store/apps/details?id=io.blockshake.defly.app)
383
+ - Defly Connect - https://github.com/blockshake-io/defly-connect
384
+
385
+ ### Daffi Wallet
386
+
387
+ - Website - https://www.daffi.me/
388
+ - Download Daffi Wallet - [iOS](https://apps.apple.com/kn/app/daffiwallet/id1659597876) / [Android](https://play.google.com/store/apps/details?id=me.daffi.daffi_wallet)
389
+ - Daffi Connect - https://github.com/RDinitiativ/daffiwallet_connect
390
+
391
+ ### WalletConnect
392
+
393
+ - Website - https://walletconnect.com/
394
+ - Documentation - https://docs.walletconnect.com/
395
+ - WalletConnect Cloud - https://cloud.walletconnect.com/
396
+ - Web3Modal - https://web3modal.com/
397
+
398
+ ### Exodus Wallet
399
+
400
+ - Website - https://www.exodus.com/
401
+ - Download - https://www.exodus.com/download/
402
+
403
+ ### KMD (Algorand Key Management Daemon)
404
+
405
+ - Documentation - https://developer.algorand.org/docs/rest-apis/kmd
406
+
407
+ ## Legacy Wallet Support
408
+
409
+ Support for these wallets will be removed in a future release.
410
+
411
+ ### AlgoSigner
412
+
413
+ - GitHub - https://github.com/PureStake/algosigner
414
+ - EOL Press Release - https://www.algorand.foundation/news/algosigner-support-ending
415
+
416
+ ### MyAlgo
417
+
418
+ - Website - https://wallet.myalgo.com/home
419
+ - FAQ - https://wallet.myalgo.com/home#faq
420
+
254
421
  ## Provider Configuration
255
422
 
256
- The `initializeProviders` functon accepts a configuration object that can be used to configure the nodes that the providers use to send transactions, as shown below.
423
+ ### Default Configuration
424
+
425
+ Calling `useInitializeProviders` with no arguments initializes the default supported wallet providers with the default node configuration:
426
+
427
+ | Key | Default Value |
428
+ | --------------------- | ------------------------------------------------------------------------------ |
429
+ | providers | `[PROVIDER_ID.PERA, PROVIDER_ID.DEFLY, PROVIDER_ID.DAFFI, PROVIDER_ID.EXODUS]` |
430
+ | nodeConfig.network | `'mainnet'` |
431
+ | nodeConfig.nodeServer | `'https://mainnet-api.algonode.cloud'` |
432
+ | nodeConfig.nodeToken | `''` |
433
+ | nodeConfig.nodePort | `443` |
434
+ | algosdkStatic | `undefined` |
257
435
 
258
436
  ```jsx
259
- const walletProviders = initializeProviders([], {
260
- network: 'devmodenet',
261
- nodeServer: 'http://algod',
262
- nodeToken: 'xxxxxxxxx',
263
- nodePort: '8080'
437
+ import React from 'react'
438
+ import { WalletProvider, useInitializeProviders } from '@txnlab/use-wallet'
439
+
440
+ export default function App() {
441
+ const providers = useInitializeProviders()
442
+
443
+ return (
444
+ <WalletProvider value={providers}>
445
+ <div className="App">{/* ... */}</div>
446
+ </WalletProvider>
447
+ )
448
+ }
449
+ ```
450
+
451
+ ### Node configuration
452
+
453
+ To configure the Algorand node that providers will use to send transactions, you can set the `nodeConfig` property. The `network` property should be specified as `mainnet`, `testnet`, `betanet` or the name of your local development network.
454
+
455
+ Refer to your wallet providers' documentation to see which networks they support.
456
+
457
+ ```jsx
458
+ const providers = await initializeProviders({
459
+ nodeConfig: {
460
+ network: 'testnet',
461
+ nodeServer: 'https://testnet-api.algonode.cloud',
462
+ nodeToken: '',
463
+ nodePort: '443'
464
+ }
264
465
  })
265
466
  ```
266
467
 
267
- Passing an empty array as the first argument enables all of the default providers. The `network` property should be specified as `betanet`, `testnet`, `mainnet` or the name of your local development network.
468
+ ### Customize provider support
268
469
 
269
- For more custom configuration options, the providers can be configured individually by creating an object and passing it to the `WalletProvider` where the key contains the provider ID, and the value calls the `init` function of the provider client. See below for an example:
470
+ You can choose which wallet providers to support by setting the `providers` property to an array of provider IDs or [provider objects](#provider-objects). The example below shows provider IDs being used.
270
471
 
271
472
  ```jsx
272
- ...
473
+ // Only initialize Pera and Defly providers
474
+ const providers = useInitializeProviders({
475
+ providers: [PROVIDER_ID.PERA, PROVIDER_ID.DEFLY]
476
+ })
477
+ ```
273
478
 
274
- import {
275
- PROVIDER_ID,
276
- pera,
277
- myalgo,
278
- } from "@txnlab/use-wallet";
279
-
280
- const walletProviders = {
281
- [PROVIDER_ID.PERA]: pera.init({
282
- clientOptions: {
283
- shouldShowSignTxnToast: true,
284
- },
285
- }),
286
- [PROVIDER_ID.MYALGO]: myalgo.init({
287
- network: "devmodenet",
288
- algodOptions: ["xxxxxxxxx", "http://algod", "8080"],
289
- clientOptions: { disableLedgerNano: true },
290
- }),
291
- };
292
-
293
- ...
294
-
295
- <WalletProvider value={walletProviders}>
296
- ...
297
- </WalletProvider>
479
+ ### Provider objects
480
+
481
+ Some wallet providers have accompanying client libraries that can be configured. You can pass an object to the providers array to set `clientOptions`, as shown below.
482
+
483
+ ```jsx
484
+ const providers = useInitializeProviders({
485
+ providers: [
486
+ PROVIDER_ID.DEFLY, // use default options for Defly Connect
487
+ { id: PROVIDER_ID.PERA, clientOptions: { shouldShowSignTxnToast: false } },
488
+ { id: PROVIDER_ID.MYALGO, clientOptions: { disableLedgerNano: false } },
489
+ PROVIDER_ID.EXODUS // Exodus has no client library
490
+ ]
491
+ })
298
492
  ```
299
493
 
300
- ## Static Imports
494
+ See each provider's documentation for the available client options.
495
+
496
+ You will need to use provider objects for [static imports](#static-imports), and for [WalletConnect 2.0](#walletconnect-20) support.
497
+
498
+ **TypeScript:** The provider objects are type-safe, so your IDE should be able to provide autocomplete suggestions for the client's available options based on the `id` that is set.
301
499
 
302
- By default, `use-wallet` dynamically imports all of the dependencies for the providiers, as well as `algosdk`, to reduce bundle size.
500
+ ### Static Imports
303
501
 
304
- Some React frameworks, like [Remix](https://remix.run/), do not support dynamic imports. To get around this, those dependencies can be imported in your application and passed to the `useWallet` provider. See below for an example.
502
+ By default, `use-wallet` dynamically imports all of the dependencies for the providers, as well as `algosdk`, to reduce bundle size.
503
+
504
+ Some React frameworks, like [Remix](https://remix.run/), do not support dynamic imports. To get around this, provider clients can be imported in your application and passed to the provider objects `clientStatic` property.
505
+
506
+ Set the imported `algosdk` to the `algosdkStatic` root property.
305
507
 
306
508
  ```jsx
307
- ...
308
-
309
- import algosdk from "algosdk";
310
- import MyAlgoConnect from "@randlabs/myalgo-connect";
311
- import { PeraWalletConnect } from "@perawallet/connect";
312
- import { DeflyWalletConnect } from "@blockshake/defly-connect";
313
- import WalletConnect from "@walletconnect/client";
314
- import QRCodeModal from "algorand-walletconnect-qrcode-modal";
315
-
316
- const walletProviders = {
317
- [PROVIDER_ID.PERA]: pera.init({
318
- algosdkStatic: algosdk,
319
- clientStatic: PeraWalletConnect,
320
- }),
321
- [PROVIDER_ID.MYALGO]: myalgo.init({
322
- algosdkStatic: algosdk,
323
- clientStatic: MyAlgoConnect,
324
- }),
325
- [PROVIDER_ID.DEFLY]: defly.init({
326
- algosdkStatic: algosdk,
327
- clientStatic: DeflyWalletConnect,
328
- }),
329
- [PROVIDER_ID.EXODUS]: exodus.init({
330
- algosdkStatic: algosdk,
331
- }),
332
- [PROVIDER_ID.ALGOSIGNER]: algosigner.init({
333
- algosdkStatic: algosdk,
334
- }),
335
- [PROVIDER_ID.WALLETCONNECT]: walletconnect.init({
336
- algosdkStatic: algosdk,
337
- clientStatic: WalletConnect,
338
- modalStatic: QRCodeModal,
339
- }),
340
- };
509
+ import React from 'react'
510
+ import algosdk from 'algosdk'
511
+ import { PROVIDER_ID, WalletProvider, useInitializeProviders } from '@txnlab/use-wallet'
512
+ import { DeflyWalletConnect } from '@blockshake/defly-connect'
513
+ import { PeraWalletConnect } from '@perawallet/connect'
514
+ import SignClient from '@walletconnect/sign-client'
515
+ import { WalletConnectModal } from '@walletconnect/modal'
341
516
 
342
517
  export default function App() {
343
- ...
518
+ const providers = useInitializeProviders({
519
+ providers: [
520
+ { id: PROVIDER_ID.PERA, clientStatic: PeraWalletConnect },
521
+ { id: PROVIDER_ID.DEFLY, clientStatic: DeflyWalletConnect },
522
+ {
523
+ id: PROVIDER_ID.WALLETCONNECT,
524
+ clientStatic: SignClient,
525
+ modalStatic: WalletConnectModal,
526
+ clientOptions: {
527
+ projectId: '<YOUR_PROJECT_ID>',
528
+ metadata: {
529
+ name: 'Example Dapp',
530
+ description: 'Example Dapp',
531
+ url: '#',
532
+ icons: ['https://walletconnect.com/walletconnect-logo.png']
533
+ }
534
+ }
535
+ },
536
+ PROVIDER_ID.EXODUS
537
+ ],
538
+ algosdkStatic: algosdk
539
+ })
344
540
 
345
541
  return (
346
- <WalletProvider value={walletProviders}>
347
- ...
542
+ <WalletProvider value={providers}>
543
+ <div className="App">{/* ... */}</div>
348
544
  </WalletProvider>
349
- );
545
+ )
546
+ }
547
+ ```
548
+
549
+ ## WalletConnect 2.0 Support
550
+
551
+ `use-wallet` v2 introduces support for WalletConnect 2.0. This is a major upgrade to the WalletConnect protocol, and introduces a number of breaking changes for app developers to contend with.
552
+
553
+ However, Algorand apps with `use-wallet` will be able to support the new protocol with minimal effort:
554
+
555
+ 1. **Obtain a project ID** - You will need to obtain a project ID from [WalletConnect Cloud](https://cloud.walletconnect.com/). This is a simple process, and there is no waiting period. Every app will need its own unique project ID.
556
+
557
+ 2. **Install peer dependencies** - Install `@walletconnect/sign-client` and `@walletconnect/modal`.
558
+
559
+ 3. **Update provider configuration** - You will need to use a provider object to initialize WalletConnect, and pass your `clientOptions` as shown below
560
+
561
+ ```jsx
562
+ const providers = useInitializeProviders({
563
+ providers: [
564
+ {
565
+ id: PROVIDER_ID.WALLETCONNECT,
566
+ clientOptions: {
567
+ projectId: '<YOUR_PROJECT_ID>',
568
+ metadata: {
569
+ name: 'Example Dapp',
570
+ description: 'Example Dapp',
571
+ url: '#',
572
+ icons: ['https://walletconnect.com/walletconnect-logo.png']
573
+ }
574
+ }
575
+ }
576
+ // other providers...
577
+ ]
578
+ })
579
+ ```
580
+
581
+ Since it requires the unique `projectId`, the WalletConnect provider is not initialized by default. This is a change from v1. If you want to support WalletConnect, it must be added to the `providers` array.
582
+
583
+ See [Migrating to WalletConnect 2.0](#migrating-to-walletconnect-20) below for more information.
584
+
585
+ ### "Module not found" errors in Next.js 13
586
+
587
+ With the WalletConnect provider initialized in your Next.js 13 app, you may see the error `Module not found: Can't resolve 'lokijs' in...` or similar in local development. To resolve this, add the following to your `next.config.js` file:
588
+
589
+ ```js
590
+ /** @type {import('next').NextConfig} */
591
+ const nextConfig = {
592
+ webpack: (config) => {
593
+ config.externals.push('pino-pretty', 'lokijs', 'encoding') // list modules in error messages
594
+ return config
595
+ }
596
+ // ...other config
350
597
  }
351
598
 
599
+ module.exports = nextConfig
352
600
  ```
353
601
 
354
- Note that some of the providers do not require static imports to be provided. This is usually the case of providers that are browser extensions.
602
+ See https://github.com/WalletConnect/walletconnect-monorepo/issues/1908#issuecomment-1487801131
603
+
604
+ ## Migration Guide
605
+
606
+ Version 2.x is a major version bump, and includes some breaking changes from 1.x.
607
+
608
+ ### initializeProviders
609
+
610
+ `initializeProviders` is now asynchronous, and must be called from inside a `useEffect` hook.
611
+
612
+ To simplify this, the `useInitializeProviders` hook is now provided, which calls `initializeProviders` internally. It accepts a single object as an argument.
613
+
614
+ The providers array should be set as the `providers` property.
615
+
616
+ ```diff
617
+ - const providers = initializeProviders([PROVIDER_ID.PERA, PROVIDER_ID.DEFLY])
618
+ + const providers = useInitializeProviders({
619
+ + providers: [PROVIDER_ID.PERA, PROVIDER_ID.DEFLY]
620
+ + })
621
+ ```
622
+
623
+ Node configuration should be set as the `nodeConfig` property.
624
+
625
+ ```diff
626
+ - const providers = initializeProviders([], {
627
+ - network: 'testnet',
628
+ - nodeServer: 'https://testnet-api.algonode.cloud',
629
+ - nodeToken: '',
630
+ - nodePort: '443'
631
+ - })
632
+ + const providers = useInitializeProviders({
633
+ + nodeConfig: {
634
+ + network: 'testnet',
635
+ + nodeServer: 'https://testnet-api.algonode.cloud',
636
+ + nodeToken: '',
637
+ + nodePort: '443'
638
+ + }
639
+ + })
640
+ ```
641
+
642
+ See [Provider Configuration](#provider-configuration) for more details.
643
+
644
+ ### shouldShowSignTxnToast
645
+
646
+ Pera Connect and Defly Connect both have a `shouldShowSignTxnToast` option that is set to `true` by default. `use-wallet` v1 set this to `false` by default, and required setting the option back to `true` to achieve the libraries' default behavior.
647
+
648
+ In v2 this option is set to `true` by default. If your app has this option explicitly set you can remove it from your configuration. If you wish to disable the toast(s), you must now explicitly set the option to `false`.
649
+
650
+ ```jsx
651
+ const providers = useInitializeProviders({
652
+ providers: [
653
+ { id: PROVIDER_ID.DEFLY, clientOptions: { shouldShowSignTxnToast: false } },
654
+ { id: PROVIDER_ID.PERA, clientOptions: { shouldShowSignTxnToast: false } }
655
+ // other providers...
656
+ ]
657
+ })
658
+ ```
659
+
660
+ ### WalletConnect provider
661
+
662
+ The WalletConnect provider now supports WalletConnect 2.0. To continue supporting this provider, or to add support to your application, you must install the `@walletconnect/sign-client` and `@walletconnect/modal` packages.
663
+
664
+ ```bash
665
+ npm install @walletconnect/sign-client @walletconnect/modal
666
+ ```
667
+
668
+ The peer dependencies for WalletConnect 1.x should be uninstalled.
669
+
670
+ ```bash
671
+ npm uninstall @walletconnect/client @json-rpc-tools/utils algorand-walletconnect-qrcode-modal
672
+ ```
673
+
674
+ WalletConnect is no longer initialized by default. To add support for WalletConnect, you must add it to the `providers` array, and pass your `clientOptions` as described in [WalletConnect 2.0 Support](#walletconnect-20-support) above.
355
675
 
356
676
  ## Local Development
357
677
 
@@ -365,7 +685,6 @@ yarn install
365
685
 
366
686
  ```bash
367
687
  yarn dev
368
-
369
688
  ```
370
689
 
371
690
  To develop against a local version of `use-wallet` in your application, do the following:
@@ -397,17 +716,19 @@ In the root of your application, run:
397
716
  ```bash
398
717
  cd node_modules/react
399
718
  yarn link
719
+ cd ../react-dom
720
+ yarn link
400
721
  ```
401
722
 
402
- In the root of `use-wallet` directory, run:
723
+ In the root of the `use-wallet` directory, run:
403
724
 
404
725
  ```bash
405
- yarn link react
726
+ yarn link react react-dom
406
727
  ```
407
728
 
408
729
  ## Used By
409
730
 
410
- Are you using `@txnlab/use-wallet`? We'd love to include you here. Let us know! [Twitter](https://twitter.com/NFDomains) | [Discord](https://discord.gg/7XcuMTfeZP) | [Email](mailto:admin@txnlab.dev)
731
+ Are you using `@txnlab/use-wallet`? We'd love to include your project here. Let us know! [Twitter](https://twitter.com/NFDomains) | [Discord](https://discord.gg/7XcuMTfeZP) | [Email](mailto:admin@txnlab.dev)
411
732
 
412
733
  - [@algoscan/use-wallet-ui](https://github.com/algoscan/use-wallet-ui)
413
734
  - [@algoworldnft/algoworld-swapper](https://github.com/algoworldnft/algoworld-swapper)