Skip to content

Commit

Permalink
feat: enable dynamic import of wallet libraries (#100)
Browse files Browse the repository at this point in the history
* feat: enable dynamic import of wallet libraries

* chore: fix error message in walletconnect init

* docs: explain how to use dynamic imports

* chore: test dynamic import in a story
  • Loading branch information
stefanofa authored Aug 6, 2023
1 parent 1fc5d14 commit 57f38f3
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 30 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ In the root of your app, initialize the `WalletProvider` with the `useInitialize

This example initializes Defly, Pera, Daffi and Exodus wallet providers. The default node configuration (mainnet via [AlgoNode](https://algonode.io/api/)) is used. See [Provider Configuration](#provider-configuration) for more options.

You can initialize your providers in two ways:

1. **Static Import** - This is the standard way of importing modules in JavaScript. In this method, the import statement is at the top of the file and the modules are imported when the file loads. This is done by passing the clientStatic property.

2. **Dynamic Import** - With the dynamic import() syntax, you can load modules on demand by calling a function. This can greatly reduce the initial load time of your app by only loading modules when they are needed. This is done by passing the getDynamicClient property which must be a function that returns a promise that resolves to the client.

Note: For each provider, either clientStatic or getDynamicClient must be passed, not both.

Here is an example of both:

### Static Import Example

```jsx
import React from 'react'
import { WalletProvider, useInitializeProviders, PROVIDER_ID } from '@txnlab/use-wallet'
Expand All @@ -119,6 +131,46 @@ export default function App() {
}
```

### Dynamic Import Example

```jsx
import React from 'react'
import { WalletProvider, useInitializeProviders, PROVIDER_ID } from '@txnlab/use-wallet'

const getDynamicDeflyWalletConnect = async () => {
const DeflyWalletConnect = (await import("@blockshake/defly-connect")).DeflyWalletConnect;
return DeflyWalletConnect;
};

const getDynamicPeraWalletConnect = async () => {
const PeraWalletConnect = (await import("@perawallet/connect")).PeraWalletConnect;
return PeraWalletConnect;
};

const getDynamicDaffiWalletConnect = async () => {
const DaffiWalletConnect = (await import("@daffiwallet/connect")).DaffiWalletConnect;
return DaffiWalletConnect;
};

export default function App() {
const providers = useInitializeProviders({
providers: [
{ id: PROVIDER_ID.DEFLY, getDynamicClient: getDynamicDeflyWalletConnect },
{ id: PROVIDER_ID.PERA, getDynamicClient: getDynamicPeraWalletConnect },
{ id: PROVIDER_ID.DAFFI, getDynamicClient: getDynamicDaffiWalletConnect },
{ id: PROVIDER_ID.EXODUS }
]
})

return (
<WalletProvider value={providers}>
<div className="App">{/* ... */}</div>
</WalletProvider>
)
}
```


## The `useWallet` Hook

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:
Expand Down
14 changes: 10 additions & 4 deletions src/clients/daffi/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,24 @@ class DaffiWalletClient extends BaseClient {
clientOptions,
algodOptions,
clientStatic,
getDynamicClient,
algosdkStatic,
network = DEFAULT_NETWORK
}: InitParams<PROVIDER_ID.DAFFI>) {
try {
debugLog(`${PROVIDER_ID.DAFFI.toUpperCase()} initializing...`)

if (!clientStatic) {
throw new Error('Daffi Wallet provider missing required property: clientStatic')
let DaffiWalletConnect
if (clientStatic) {
DaffiWalletConnect = clientStatic
} else if (getDynamicClient) {
DaffiWalletConnect = await getDynamicClient()
} else {
throw new Error(
'Daffi Wallet provider missing required property: clientStatic or getDynamicClient'
)
}

const DaffiWalletConnect = clientStatic

const algosdk = algosdkStatic || (await Algod.init(algodOptions)).algosdk
const algodClient = getAlgodClient(algosdk, algodOptions)

Expand Down
14 changes: 10 additions & 4 deletions src/clients/defly/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,24 @@ class DeflyWalletClient extends BaseClient {
clientOptions,
algodOptions,
clientStatic,
getDynamicClient,
algosdkStatic,
network = DEFAULT_NETWORK
}: InitParams<PROVIDER_ID.DEFLY>): Promise<BaseClient | null> {
try {
debugLog(`${PROVIDER_ID.DEFLY.toUpperCase()} initializing...`)

if (!clientStatic) {
throw new Error('Defly Wallet provider missing required property: clientStatic')
let DeflyWalletConnect
if (clientStatic) {
DeflyWalletConnect = clientStatic
} else if (getDynamicClient) {
DeflyWalletConnect = await getDynamicClient()
} else {
throw new Error(
'Defly Wallet provider missing required property: clientStatic or getDynamicClient'
)
}

const DeflyWalletConnect = clientStatic

const algosdk = algosdkStatic || (await Algod.init(algodOptions)).algosdk
const algodClient = getAlgodClient(algosdk, algodOptions)

Expand Down
14 changes: 10 additions & 4 deletions src/clients/myalgo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,24 @@ class MyAlgoWalletClient extends BaseClient {
clientOptions,
algodOptions,
clientStatic,
getDynamicClient,
algosdkStatic,
network = DEFAULT_NETWORK
}: InitParams<PROVIDER_ID.MYALGO>): Promise<BaseClient | null> {
try {
debugLog(`${PROVIDER_ID.MYALGO.toUpperCase()} initializing...`)

if (!clientStatic) {
throw new Error('MyAlgo Wallet provider missing required property: clientStatic')
let MyAlgoConnect
if (clientStatic) {
MyAlgoConnect = clientStatic
} else if (getDynamicClient) {
MyAlgoConnect = await getDynamicClient()
} else {
throw new Error(
'MyAlgo Wallet provider missing required property: clientStatic or getDynamicClient'
)
}

const MyAlgoConnect = clientStatic

const algosdk = algosdkStatic || (await Algod.init(algodOptions)).algosdk
const algodClient = getAlgodClient(algosdk, algodOptions)

Expand Down
14 changes: 10 additions & 4 deletions src/clients/pera/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,24 @@ class PeraWalletClient extends BaseClient {
clientOptions,
algodOptions,
clientStatic,
getDynamicClient,
algosdkStatic,
network = DEFAULT_NETWORK
}: InitParams<PROVIDER_ID.PERA>): Promise<BaseClient | null> {
try {
debugLog(`${PROVIDER_ID.PERA.toUpperCase()} initializing...`)

if (!clientStatic) {
throw new Error('Pera Wallet provider missing required property: clientStatic')
let PeraWalletConnect
if (clientStatic) {
PeraWalletConnect = clientStatic
} else if (getDynamicClient) {
PeraWalletConnect = await getDynamicClient()
} else {
throw new Error(
'Pera Wallet provider missing required property: clientStatic or getDynamicClient'
)
}

const PeraWalletConnect = clientStatic

const algosdk = algosdkStatic || (await Algod.init(algodOptions)).algosdk
const algodClient = getAlgodClient(algosdk, algodOptions)

Expand Down
14 changes: 10 additions & 4 deletions src/clients/walletconnect2/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,22 @@ class WalletConnectClient extends BaseClient {
clientOptions,
algodOptions,
clientStatic,
getDynamicClient,
algosdkStatic,
network = DEFAULT_NETWORK
}: InitParams<PROVIDER_ID.WALLETCONNECT>): Promise<BaseClient | null> {
try {
debugLog(`${PROVIDER_ID.WALLETCONNECT.toUpperCase()} initializing...`)

if (!clientStatic) {
throw new Error('WalletConnect provider missing required property: clientStatic')
let Client
if (clientStatic) {
Client = clientStatic
} else if (getDynamicClient) {
Client = await getDynamicClient()
} else {
throw new Error(
'WalletConnect provider missing required property: clientStatic or getDynamicClient'
)
}

if (!clientOptions) {
Expand All @@ -75,8 +83,6 @@ class WalletConnectClient extends BaseClient {

const chain = ALGORAND_CHAINS[network]

const Client = clientStatic

// Initialize client
const client = new Client({
...clientOptions,
Expand Down
8 changes: 6 additions & 2 deletions src/components/Example/Example.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import React from 'react'
import { DeflyWalletConnect } from '@blockshake/defly-connect'
import { PeraWalletConnect } from '@perawallet/connect'
import { DaffiWalletConnect } from '@daffiwallet/connect'
import { WalletProvider, PROVIDER_ID, useInitializeProviders } from '../../index'
import Account from './Account'
import Connect from './Connect'
import Transact from './Transact'

const getDynamicPeraWalletConnect = async () => {
const PeraWalletConnect = (await import('@perawallet/connect')).PeraWalletConnect
return PeraWalletConnect
}

export default function ConnectWallet() {
const walletProviders = useInitializeProviders({
providers: [
{ id: PROVIDER_ID.DEFLY, clientStatic: DeflyWalletConnect },
{ id: PROVIDER_ID.PERA, clientStatic: PeraWalletConnect },
{ id: PROVIDER_ID.PERA, getDynamicClient: getDynamicPeraWalletConnect },
{ id: PROVIDER_ID.DAFFI, clientStatic: DaffiWalletConnect },
{ id: PROVIDER_ID.EXODUS }
]
Expand Down
37 changes: 29 additions & 8 deletions src/types/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,47 @@ export type ProviderConfigMapping = {
[PROVIDER_ID.PERA]: {
clientOptions?: PeraWalletConnectOptions
clientStatic?: typeof PeraWalletConnect
getDynamicClient?: () => Promise<typeof PeraWalletConnect>
}
[PROVIDER_ID.DAFFI]: {
clientOptions?: DaffiWalletConnectOptions
clientStatic?: typeof DaffiWalletConnect
getDynamicClient?: () => Promise<typeof DaffiWalletConnect>
}
[PROVIDER_ID.DEFLY]: {
clientOptions?: DeflyWalletConnectOptions
clientStatic?: typeof DeflyWalletConnect
getDynamicClient?: () => Promise<typeof DeflyWalletConnect>
}
[PROVIDER_ID.WALLETCONNECT]: {
clientOptions?: WalletConnectModalSignOptions
clientStatic?: typeof WalletConnectModalSign
getDynamicClient?: () => Promise<typeof WalletConnectModalSign>
}
[PROVIDER_ID.MYALGO]: {
clientOptions?: MyAlgoConnectOptions
clientStatic?: typeof MyAlgoConnect
getDynamicClient?: () => Promise<typeof MyAlgoConnect>
}
[PROVIDER_ID.EXODUS]: {
clientOptions?: ExodusOptions
clientStatic?: undefined
getDynamicClient?: undefined
}
[PROVIDER_ID.KMD]: {
clientOptions?: KmdOptions
clientStatic?: undefined
getDynamicClient?: undefined
}
[PROVIDER_ID.ALGOSIGNER]: {
clientOptions?: undefined
clientStatic?: undefined
getDynamicClient?: undefined
}
[PROVIDER_ID.MNEMONIC]: {
clientOptions?: undefined
clientStatic?: undefined
getDynamicClient?: undefined
}
}

Expand Down Expand Up @@ -87,15 +96,27 @@ export type NodeConfig = {
nodeHeaders?: Record<string, string>
}

type StaticClient<T> = {
clientStatic: T
getDynamicClient?: undefined
}

type DynamicClient<T> = {
clientStatic?: undefined
getDynamicClient: () => Promise<T>
}

type OneOfStaticOrDynamicClient<T> = StaticClient<T> | DynamicClient<T>

type ProviderDef =
| (ProviderConfig<PROVIDER_ID.PERA> & { clientStatic: typeof PeraWalletConnect })
| (ProviderConfig<PROVIDER_ID.DEFLY> & { clientStatic: typeof DeflyWalletConnect })
| (ProviderConfig<PROVIDER_ID.DAFFI> & { clientStatic: typeof DaffiWalletConnect })
| (ProviderConfig<PROVIDER_ID.WALLETCONNECT> & {
clientStatic: typeof WalletConnectModalSign
clientOptions: WalletConnectModalSignOptions
})
| (ProviderConfig<PROVIDER_ID.MYALGO> & { clientStatic: typeof MyAlgoConnect })
| (ProviderConfig<PROVIDER_ID.PERA> & OneOfStaticOrDynamicClient<typeof PeraWalletConnect>)
| (ProviderConfig<PROVIDER_ID.DEFLY> & OneOfStaticOrDynamicClient<typeof DeflyWalletConnect>)
| (ProviderConfig<PROVIDER_ID.DAFFI> & OneOfStaticOrDynamicClient<typeof DaffiWalletConnect>)
| (ProviderConfig<PROVIDER_ID.WALLETCONNECT> &
OneOfStaticOrDynamicClient<typeof WalletConnectModalSign> & {
clientOptions: WalletConnectModalSignOptions
})
| (ProviderConfig<PROVIDER_ID.MYALGO> & OneOfStaticOrDynamicClient<typeof MyAlgoConnect>)
| ProviderConfig<PROVIDER_ID.EXODUS>
| ProviderConfig<PROVIDER_ID.KMD>
| PROVIDER_ID.EXODUS
Expand Down

0 comments on commit 57f38f3

Please sign in to comment.