@txnlab/use-wallet 2.0.0-alpha.2 → 2.0.0-alpha.3

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.
package/README.md CHANGED
@@ -511,8 +511,7 @@ import algosdk from 'algosdk'
511
511
  import { PROVIDER_ID, WalletProvider, useInitializeProviders } from '@txnlab/use-wallet'
512
512
  import { DeflyWalletConnect } from '@blockshake/defly-connect'
513
513
  import { PeraWalletConnect } from '@perawallet/connect'
514
- import SignClient from '@walletconnect/sign-client'
515
- import { WalletConnectModal } from '@walletconnect/modal'
514
+ import { Web3ModalSign } from '@web3modal/sign-html'
516
515
 
517
516
  export default function App() {
518
517
  const providers = useInitializeProviders({
@@ -521,8 +520,7 @@ export default function App() {
521
520
  { id: PROVIDER_ID.DEFLY, clientStatic: DeflyWalletConnect },
522
521
  {
523
522
  id: PROVIDER_ID.WALLETCONNECT,
524
- clientStatic: SignClient,
525
- modalStatic: WalletConnectModal,
523
+ clientStatic: Web3ModalSign,
526
524
  clientOptions: {
527
525
  projectId: '<YOUR_PROJECT_ID>',
528
526
  metadata: {
@@ -554,7 +552,7 @@ However, Algorand apps with `use-wallet` will be able to support the new protoco
554
552
 
555
553
  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
554
 
557
- 2. **Install peer dependencies** - Install `@walletconnect/sign-client` and `@walletconnect/modal`.
555
+ 2. **Install peer dependency** - Install `@web3modal/sign-html`.
558
556
 
559
557
  3. **Update provider configuration** - You will need to use a provider object to initialize WalletConnect, and pass your `clientOptions` as shown below
560
558
 
@@ -659,10 +657,10 @@ const providers = useInitializeProviders({
659
657
 
660
658
  ### WalletConnect provider
661
659
 
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.
660
+ The WalletConnect provider now supports WalletConnect 2.0. To continue supporting this provider, or to add support to your application, you must install the `@web3modal/sign-html` package.
663
661
 
664
662
  ```bash
665
- npm install @walletconnect/sign-client @walletconnect/modal
663
+ npm install @web3modal/sign-html
666
664
  ```
667
665
 
668
666
  The peer dependencies for WalletConnect 1.x should be uninstalled.
package/dist/cjs/index.js CHANGED
@@ -1899,6 +1899,19 @@ class AlgoSignerClient extends BaseClient {
1899
1899
  }
1900
1900
  }
1901
1901
 
1902
+ const ICON$2 = 'data:image/svg+xml;base64,' +
1903
+ 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgNDgwIDQ4MCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDgwIDQ4MDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiMzMzk2RkY7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTI2LjYsMTY4YzYyLjYtNjEuMywxNjQuMi02MS4zLDIyNi44LDBsNy41LDcuNGMzLjEsMy4xLDMuMSw4LDAsMTEuMWwtMjUuOCwyNS4yYy0xLjYsMS41LTQuMSwxLjUtNS43LDAKCWwtMTAuNC0xMC4yYy00My43LTQyLjgtMTE0LjUtNDIuOC0xNTguMiwwbC0xMS4xLDEwLjljLTEuNiwxLjUtNC4xLDEuNS01LjcsMGwtMjUuOC0yNS4yYy0zLjEtMy4xLTMuMS04LDAtMTEuMUwxMjYuNiwxNjh6CgkgTTQwNi43LDIyMC4ybDIyLjksMjIuNWMzLjEsMy4xLDMuMSw4LDAsMTEuMUwzMjYuMiwzNTUuMWMtMy4xLDMuMS04LjIsMy4xLTExLjMsMGwtNzMuNC03MS45Yy0wLjgtMC44LTIuMS0wLjgtMi44LDBsLTczLjQsNzEuOQoJYy0zLjEsMy4xLTguMiwzLjEtMTEuMywwTDUwLjMsMjUzLjhjLTMuMS0zLjEtMy4xLTgsMC0xMS4xbDIyLjktMjIuNWMzLjEtMy4xLDguMi0zLjEsMTEuMywwbDczLjQsNzEuOWMwLjgsMC44LDIuMSwwLjgsMi44LDAKCWw3My40LTcxLjljMy4xLTMuMSw4LjItMy4xLDExLjMsMGw3My40LDcxLjljMC44LDAuOCwyLjEsMC44LDIuOCwwbDczLjQtNzEuOUMzOTguNSwyMTcuMSw0MDMuNiwyMTcuMSw0MDYuNywyMjAuMkw0MDYuNywyMjAuMnoiLz4KPC9zdmc+Cg==';
1904
+ const DEFAULT_NETWORK = 'mainnet';
1905
+ const ALGORAND_CHAINS = {
1906
+ mainnet: 'algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73k',
1907
+ testnet: 'algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDe',
1908
+ betanet: 'algorand:mFgazF-2uRS1tMiL9dsj01hJGySEmPN2'
1909
+ };
1910
+
1911
+ const isPublicNetwork = (network) => {
1912
+ return network === 'betanet' || network === 'testnet' || network === 'mainnet';
1913
+ };
1914
+
1902
1915
  const getPayloadId = () => {
1903
1916
  const date = Date.now() * Math.pow(10, 3);
1904
1917
  const extra = Math.floor(Math.random() * Math.pow(10, 3));
@@ -1914,30 +1927,15 @@ const formatJsonRpcRequest = (method, params) => {
1914
1927
  };
1915
1928
  };
1916
1929
 
1917
- const isPublicNetwork = (network) => {
1918
- return network === 'betanet' || network === 'testnet' || network === 'mainnet';
1919
- };
1920
-
1921
- const ICON$2 = 'data:image/svg+xml;base64,' +
1922
- 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgNDgwIDQ4MCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDgwIDQ4MDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiMzMzk2RkY7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTI2LjYsMTY4YzYyLjYtNjEuMywxNjQuMi02MS4zLDIyNi44LDBsNy41LDcuNGMzLjEsMy4xLDMuMSw4LDAsMTEuMWwtMjUuOCwyNS4yYy0xLjYsMS41LTQuMSwxLjUtNS43LDAKCWwtMTAuNC0xMC4yYy00My43LTQyLjgtMTE0LjUtNDIuOC0xNTguMiwwbC0xMS4xLDEwLjljLTEuNiwxLjUtNC4xLDEuNS01LjcsMGwtMjUuOC0yNS4yYy0zLjEtMy4xLTMuMS04LDAtMTEuMUwxMjYuNiwxNjh6CgkgTTQwNi43LDIyMC4ybDIyLjksMjIuNWMzLjEsMy4xLDMuMSw4LDAsMTEuMUwzMjYuMiwzNTUuMWMtMy4xLDMuMS04LjIsMy4xLTExLjMsMGwtNzMuNC03MS45Yy0wLjgtMC44LTIuMS0wLjgtMi44LDBsLTczLjQsNzEuOQoJYy0zLjEsMy4xLTguMiwzLjEtMTEuMywwTDUwLjMsMjUzLjhjLTMuMS0zLjEtMy4xLTgsMC0xMS4xbDIyLjktMjIuNWMzLjEtMy4xLDguMi0zLjEsMTEuMywwbDczLjQsNzEuOWMwLjgsMC44LDIuMSwwLjgsMi44LDAKCWw3My40LTcxLjljMy4xLTMuMSw4LjItMy4xLDExLjMsMGw3My40LDcxLjljMC44LDAuOCwyLjEsMC44LDIuOCwwbDczLjQtNzEuOUMzOTguNSwyMTcuMSw0MDMuNiwyMTcuMSw0MDYuNywyMjAuMkw0MDYuNywyMjAuMnoiLz4KPC9zdmc+Cg==';
1923
- const DEFAULT_NETWORK = 'mainnet';
1924
- const ALGORAND_CHAINS = {
1925
- mainnet: 'algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73k',
1926
- testnet: 'algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDe',
1927
- betanet: 'algorand:mFgazF-2uRS1tMiL9dsj01hJGySEmPN2'
1928
- };
1929
-
1930
1930
  class WalletConnectClient extends BaseClient {
1931
1931
  #client;
1932
1932
  clientOptions;
1933
- #modal;
1934
1933
  network;
1935
1934
  chain;
1936
- constructor({ metadata, client, clientOptions, modal, algosdk, algodClient, network, chain }) {
1935
+ constructor({ metadata, client, clientOptions, algosdk, algodClient, network, chain }) {
1937
1936
  super(metadata, algosdk, algodClient);
1938
1937
  this.#client = client;
1939
1938
  this.clientOptions = clientOptions;
1940
- this.#modal = modal;
1941
1939
  this.network = network;
1942
1940
  this.chain = chain;
1943
1941
  this.metadata = WalletConnectClient.metadata;
@@ -1948,45 +1946,43 @@ class WalletConnectClient extends BaseClient {
1948
1946
  icon: ICON$2,
1949
1947
  isWalletConnect: true
1950
1948
  };
1951
- static async init({ clientOptions, algodOptions, clientStatic, modalStatic, modalOptions, algosdkStatic, network = DEFAULT_NETWORK }) {
1949
+ static async init({ clientOptions, algodOptions, clientStatic, algosdkStatic, network = DEFAULT_NETWORK }) {
1952
1950
  try {
1953
1951
  if (!isPublicNetwork(network)) {
1954
1952
  throw new Error(`WalletConnect only supports Algorand mainnet, testnet, and betanet. "${network}" is not supported.`);
1955
1953
  }
1954
+ if (!clientOptions) {
1955
+ throw new Error('WalletConnect clientOptions must be provided');
1956
+ }
1956
1957
  const chain = ALGORAND_CHAINS[network];
1957
- // Initialize sign client
1958
- const Client = clientStatic || (await import('@walletconnect/sign-client')).default;
1959
- const client = await Client.init(clientOptions);
1960
- // Initialize web3modal
1961
- const modalModule = modalStatic
1962
- ? { WalletConnectModal: modalStatic }
1963
- : await import('@walletconnect/modal');
1964
- const Web3Modal = modalModule.WalletConnectModal;
1965
- const modal = new Web3Modal({
1966
- explorerExcludedWalletIds: 'ALL',
1967
- ...modalOptions,
1968
- projectId: clientOptions?.projectId || '',
1969
- walletConnectVersion: 2
1958
+ const clientModule = clientStatic
1959
+ ? { Web3ModalSign: clientStatic }
1960
+ : await import('@web3modal/sign-html');
1961
+ const Client = clientModule.Web3ModalSign;
1962
+ // Initialize client
1963
+ const client = new Client({
1964
+ ...clientOptions,
1965
+ modalOptions: {
1966
+ explorerExcludedWalletIds: 'ALL',
1967
+ ...clientOptions.modalOptions
1968
+ }
1970
1969
  });
1971
1970
  // Initialize algod client
1972
1971
  const algosdk = algosdkStatic || (await Algod.init(algodOptions)).algosdk;
1973
1972
  const algodClient = getAlgodClient(algosdk, algodOptions);
1974
1973
  // Initialize wallet client
1975
- const walletClient = new WalletConnectClient({
1974
+ return new WalletConnectClient({
1976
1975
  metadata: WalletConnectClient.metadata,
1977
1976
  client,
1978
1977
  clientOptions,
1979
- modal,
1980
1978
  algosdk,
1981
1979
  algodClient,
1982
1980
  network,
1983
1981
  chain
1984
1982
  });
1985
- walletClient.#subscribeToEvents();
1986
- return walletClient;
1987
1983
  }
1988
1984
  catch (error) {
1989
- console.error('Error initializing', error);
1985
+ console.error('Error initializing WalletConnect client', error);
1990
1986
  return null;
1991
1987
  }
1992
1988
  }
@@ -1998,63 +1994,35 @@ class WalletConnectClient extends BaseClient {
1998
1994
  events: []
1999
1995
  }
2000
1996
  };
2001
- const { uri, approval } = await this.#client.connect({ requiredNamespaces });
2002
- if (uri) {
2003
- await this.#modal.openModal({ uri, standaloneChains: [this.chain] });
2004
- }
2005
- return new Promise((resolve, reject) => {
2006
- const unsubscribeModal = this.#modal.subscribeModal((state) => {
2007
- if (!state.open) {
2008
- unsubscribeModal();
2009
- reject(new Error('Modal closed'));
2010
- }
2011
- });
2012
- approval()
2013
- .then((session) => {
2014
- const { accounts } = session.namespaces.algorand;
2015
- resolve({
2016
- ...WalletConnectClient.metadata,
2017
- accounts: accounts.map((accountStr, index) => ({
2018
- name: `WalletConnect ${index + 1}`,
2019
- address: accountStr.split(':').pop(),
2020
- providerId: WalletConnectClient.metadata.id
2021
- }))
2022
- });
2023
- })
2024
- .catch((error) => {
2025
- reject(error);
2026
- })
2027
- .finally(() => {
2028
- unsubscribeModal();
2029
- this.#modal.closeModal();
1997
+ try {
1998
+ const session = await this.#client.connect({
1999
+ requiredNamespaces
2030
2000
  });
2031
- });
2001
+ const { accounts } = session.namespaces.algorand;
2002
+ return {
2003
+ ...WalletConnectClient.metadata,
2004
+ accounts: this.#mapAccounts(accounts)
2005
+ };
2006
+ }
2007
+ catch (error) {
2008
+ console.error('Error connecting to WalletConnect', error);
2009
+ throw error;
2010
+ }
2032
2011
  }
2033
- // eslint-disable-next-line @typescript-eslint/require-await
2034
2012
  async reconnect() {
2035
- const session = this.#getSession();
2013
+ const session = await this.#client.getSession();
2036
2014
  if (typeof session === 'undefined') {
2037
2015
  return null;
2038
2016
  }
2039
2017
  const { accounts } = session.namespaces.algorand;
2040
2018
  return {
2041
2019
  ...WalletConnectClient.metadata,
2042
- accounts: accounts.map((accountStr, index) => ({
2043
- name: `WalletConnect ${index + 1}`,
2044
- address: accountStr.split(':').pop(),
2045
- providerId: WalletConnectClient.metadata.id
2046
- }))
2020
+ accounts: this.#mapAccounts(accounts)
2047
2021
  };
2048
2022
  }
2049
2023
  async disconnect() {
2050
2024
  try {
2051
- if (typeof this.#client === 'undefined') {
2052
- throw new Error('WalletConnect is not initialized');
2053
- }
2054
- const session = this.#getSession();
2055
- if (typeof session === 'undefined') {
2056
- throw new Error('Session is not connected');
2057
- }
2025
+ const session = await this.#getSession();
2058
2026
  await this.#client.disconnect({
2059
2027
  topic: session.topic,
2060
2028
  // replicates getSdkError('USER_DISCONNECTED') from @walletconnect/utils
@@ -2068,27 +2036,49 @@ class WalletConnectClient extends BaseClient {
2068
2036
  console.error('Error disconnecting', error);
2069
2037
  }
2070
2038
  }
2071
- async signTransactions(connectedAccounts, txnGroups, indexesToSign, returnGroup = true) {
2072
- // If txnGroups is a nested array, flatten it
2039
+ async signTransactions(connectedAccounts, txnGroups, indexesToSign = [], returnGroup = true) {
2040
+ // Flatten transactions array if nested
2073
2041
  const transactions = Array.isArray(txnGroups[0])
2074
2042
  ? txnGroups.flatMap((txn) => txn)
2075
2043
  : txnGroups;
2076
- // Decode the transactions to access their properties.
2044
+ const { txnsToSign, signedIndexes } = this.#composeTransactions(transactions, connectedAccounts, indexesToSign);
2045
+ const request = formatJsonRpcRequest('algo_signTxn', [txnsToSign]);
2046
+ const session = await this.#getSession();
2047
+ const response = await this.#client.request({
2048
+ chainId: this.chain,
2049
+ topic: session.topic,
2050
+ request
2051
+ });
2052
+ // Check if the result is the same length as the transactions
2053
+ const lengthsMatch = response.length === transactions.length;
2054
+ // Join the signed transactions with the original group of transactions
2055
+ const signedTxns = transactions.reduce((acc, txn, i) => {
2056
+ if (signedIndexes.includes(i)) {
2057
+ const signedTxn = lengthsMatch ? response[i] : response.shift();
2058
+ signedTxn && acc.push(new Uint8Array(Buffer.from(signedTxn, 'base64')));
2059
+ }
2060
+ else if (returnGroup) {
2061
+ acc.push(txn);
2062
+ }
2063
+ return acc;
2064
+ }, []);
2065
+ return signedTxns;
2066
+ }
2067
+ #composeTransactions(transactions, connectedAccounts, indexesToSign) {
2068
+ // Decode the transactions
2077
2069
  const decodedTxns = transactions.map((txn) => {
2078
2070
  return this.algosdk.decodeObj(txn);
2079
2071
  });
2072
+ // Track signed transactions
2080
2073
  const signedIndexes = [];
2081
- // Marshal the transactions,
2082
- // and add the signers property if they shouldn't be signed.
2074
+ // Marshal the transactions into WalletConnect format
2083
2075
  const txnsToSign = decodedTxns.reduce((acc, txn, i) => {
2084
2076
  const isSigned = 'txn' in txn;
2085
- if (indexesToSign && indexesToSign.length && indexesToSign.includes(i)) {
2086
- signedIndexes.push(i);
2087
- acc.push({
2088
- txn: Buffer.from(transactions[i]).toString('base64')
2089
- });
2090
- }
2091
- else if (!isSigned && connectedAccounts.includes(this.algosdk.encodeAddress(txn['snd']))) {
2077
+ const senderAccount = !isSigned
2078
+ ? this.algosdk.encodeAddress(txn['snd'])
2079
+ : this.algosdk.encodeAddress(txn.txn['snd']);
2080
+ const shouldSign = indexesToSign.includes(i) || (!isSigned && connectedAccounts.includes(senderAccount));
2081
+ if (shouldSign) {
2092
2082
  signedIndexes.push(i);
2093
2083
  acc.push({
2094
2084
  txn: Buffer.from(transactions[i]).toString('base64')
@@ -2104,51 +2094,21 @@ class WalletConnectClient extends BaseClient {
2104
2094
  }
2105
2095
  return acc;
2106
2096
  }, []);
2107
- const session = this.#getSession();
2097
+ return { txnsToSign, signedIndexes };
2098
+ }
2099
+ async #getSession() {
2100
+ const session = await this.#client.getSession();
2108
2101
  if (typeof session === 'undefined') {
2109
2102
  throw new Error('Session is not connected');
2110
2103
  }
2111
- const request = formatJsonRpcRequest('algo_signTxn', [txnsToSign]);
2112
- // Play an audio file to keep Wallet Connect's web socket open on iOS
2113
- // when the user goes into background mode.
2114
- // await this.keepWCAliveStart()
2115
- const response = await this.#client.request({
2116
- chainId: this.chain,
2117
- topic: session.topic,
2118
- request
2119
- });
2120
- // this.keepWCAliveStop()
2121
- // Check if the result is the same length as the transactions
2122
- const lengthsMatch = response.length === transactions.length;
2123
- // Join the newly signed transactions with the original group of transactions.
2124
- const signedTxns = transactions.reduce((acc, txn, i) => {
2125
- if (signedIndexes.includes(i)) {
2126
- const signedByUser = lengthsMatch ? response[i] : response.shift();
2127
- signedByUser && acc.push(new Uint8Array(Buffer.from(signedByUser, 'base64')));
2128
- }
2129
- else if (returnGroup) {
2130
- acc.push(txn);
2131
- }
2132
- return acc;
2133
- }, []);
2134
- return signedTxns;
2104
+ return session;
2135
2105
  }
2136
- #subscribeToEvents() {
2137
- if (typeof this.#client === 'undefined') {
2138
- throw new Error('WalletConnect is not initialized');
2139
- }
2140
- this.#client.on('session_event', (args) => {
2141
- console.log('EVENT', 'session_event', args);
2142
- });
2143
- this.#client.on('session_update', ({ topic, params }) => {
2144
- console.log('EVENT', 'session_update', { topic, params });
2145
- });
2146
- this.#client.on('session_delete', () => {
2147
- console.log('EVENT', 'session_delete');
2148
- });
2149
- }
2150
- #getSession() {
2151
- return this.#client.session.getAll().at(-1);
2106
+ #mapAccounts(accounts) {
2107
+ return accounts.map((accountStr, index) => ({
2108
+ name: `WalletConnect ${index + 1}`,
2109
+ address: accountStr.split(':').pop(),
2110
+ providerId: WalletConnectClient.metadata.id
2111
+ }));
2152
2112
  }
2153
2113
  }
2154
2114