Răsfoiți Sursa

Merge pull request #107 from lorisleiva/feature/add-vue-core

Add Vue core package
Jordan Sexton 4 ani în urmă
părinte
comite
8901169d3e

+ 1 - 0
README.md

@@ -168,6 +168,7 @@ These packages are what most projects can use to support wallets on Solana.
 | [base](https://github.com/solana-labs/wallet-adapter/tree/master/packages/core/base)          | Adapter interfaces, error types, and common utilities | [`@solana/wallet-adapter-base`](https://www.npmjs.com/package/@solana/wallet-adapter-base)       |
 | [react](https://github.com/solana-labs/wallet-adapter/tree/master/packages/core/react)        | Contexts and hooks for React dApps                    | [`@solana/wallet-adapter-react`](https://www.npmjs.com/package/@solana/wallet-adapter-react)     |
 | [angular](https://github.com/solana-labs/wallet-adapter/tree/master/packages/core/angular) \* | Stores and configuration for Angular dApps            | [`@solana/wallet-adapter-angular`](https://www.npmjs.com/package/@solana/wallet-adapter-angular) |
+| [vue](https://github.com/solana-labs/wallet-adapter/tree/master/packages/core/vue) \*         | Stores and composables for Vue 3 dApps                | [`@solana/wallet-adapter-vue`](https://www.npmjs.com/package/@solana/wallet-adapter-vue)         |
 
 \* Package has not been published to NPM yet.
 

+ 16 - 3
packages/core/react/src/useLocalStorage.ts

@@ -5,9 +5,12 @@ export function useLocalStorage<T>(key: string, defaultState: T): [T, (newValue:
         if (typeof localStorage === 'undefined') return defaultState;
 
         const value = localStorage.getItem(key);
-        if (value) return JSON.parse(value) as T;
-
-        return defaultState;
+        try {
+            return value ? (JSON.parse(value) as T) : defaultState;
+        } catch (error) {
+            console.warn(error);
+            return defaultState;
+        }
     });
 
     const setLocalStorage = useCallback(
@@ -20,6 +23,16 @@ export function useLocalStorage<T>(key: string, defaultState: T): [T, (newValue:
             } else {
                 localStorage.setItem(key, JSON.stringify(newValue));
             }
+
+            if (newValue === null) {
+                localStorage.removeItem(key);
+            } else {
+                try {
+                    localStorage.setItem(key, JSON.stringify(newValue));
+                } catch (error) {
+                    console.error(error);
+                }
+            }
         },
         [value, setValue, key]
     );

+ 1 - 0
packages/core/vue/.gitignore

@@ -0,0 +1 @@
+lib

+ 1 - 0
packages/core/vue/.prettierignore

@@ -0,0 +1 @@
+lib

+ 202 - 0
packages/core/vue/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 5 - 0
packages/core/vue/README.md

@@ -0,0 +1,5 @@
+# `@solana/wallet-adapter-vue`
+
+<!-- @TODO -->
+
+Coming soon.

+ 34 - 0
packages/core/vue/package.json

@@ -0,0 +1,34 @@
+{
+    "name": "@solana/wallet-adapter-vue",
+    "version": "0.1.0",
+    "author": "Solana Maintainers <maintainers@solana.foundation>",
+    "repository": "https://github.com/solana-labs/wallet-adapter",
+    "license": "Apache-2.0",
+    "main": "lib/index.js",
+    "esnext": "lib/index.js",
+    "types": "lib/index.d.ts",
+    "files": [
+        "lib",
+        "src",
+        "LICENSE"
+    ],
+    "publishConfig": {
+        "access": "public"
+    },
+    "scripts": {
+        "clean": "shx rm -rf lib/*",
+        "build": "yarn clean && tsc"
+    },
+    "peerDependencies": {
+        "@solana/wallet-adapter-base": "^0.6.0",
+        "@solana/wallet-adapter-wallets": "^0.10.1",
+        "@solana/web3.js": "^1.20.0",
+        "vue": "^3.0.0"
+    },
+    "devDependencies": {
+        "@solana/wallet-adapter-base": "^0.6.0",
+        "@solana/wallet-adapter-wallets": "^0.10.1",
+        "@solana/web3.js": "^1.20.0",
+        "vue": "^3.0.0"
+    }
+}

+ 5 - 0
packages/core/vue/src/errors.ts

@@ -0,0 +1,5 @@
+import { WalletError } from '@solana/wallet-adapter-base';
+
+export class WalletNotSelectedError extends WalletError {
+    name = 'WalletNotSelectedError';
+}

+ 3 - 0
packages/core/vue/src/index.ts

@@ -0,0 +1,3 @@
+export * from './errors';
+export * from './useLocalStorage';
+export * from './useWallet';

+ 28 - 0
packages/core/vue/src/useLocalStorage.ts

@@ -0,0 +1,28 @@
+import { customRef, Ref } from '@vue/reactivity';
+
+export function useLocalStorage<T>(key: string, defaultValue: T | null = null): Ref<T | null> {
+    return customRef<T | null>((track, trigger) => ({
+        get: () => {
+            track();
+            const value = localStorage.getItem(key);
+            try {
+                return value ? (JSON.parse(value) as T) : defaultValue;
+            } catch (error) {
+                console.warn(error);
+                return defaultValue;
+            }
+        },
+        set: (value) => {
+            if (value === null) {
+                localStorage.removeItem(key);
+            } else {
+                try {
+                    localStorage.setItem(key, JSON.stringify(value));
+                } catch (error) {
+                    console.error(error);
+                }
+            }
+            trigger();
+        },
+    }));
+}

+ 290 - 0
packages/core/vue/src/useWallet.ts

@@ -0,0 +1,290 @@
+import {
+    MessageSignerWalletAdapter,
+    SendTransactionOptions,
+    SignerWalletAdapter,
+    WalletError,
+    WalletNotConnectedError,
+    WalletNotReadyError,
+} from '@solana/wallet-adapter-base';
+import { Wallet, WalletName } from '@solana/wallet-adapter-wallets';
+import { Connection, PublicKey, Transaction, TransactionSignature } from '@solana/web3.js';
+import { computed, Ref, ref, watch, watchEffect } from '@vue/runtime-core';
+import { WalletNotSelectedError } from './errors';
+import { useLocalStorage } from './useLocalStorage';
+
+type Adapter = ReturnType<Wallet['adapter']>;
+type WalletDictionary = { [name in WalletName]: Wallet };
+
+export interface WalletStore {
+    // Props.
+    wallets: Wallet[];
+    autoConnect: boolean;
+
+    // Data.
+    wallet: Ref<Wallet | null>;
+    adapter: Ref<Adapter | null>;
+    publicKey: Ref<PublicKey | null>;
+    ready: Ref<boolean>;
+    connected: Ref<boolean>;
+    connecting: Ref<boolean>;
+    disconnecting: Ref<boolean>;
+
+    // Methods.
+    select(walletName: WalletName): void;
+    connect(): Promise<void>;
+    disconnect(): Promise<void>;
+    sendTransaction(
+        transaction: Transaction,
+        connection: Connection,
+        options?: SendTransactionOptions
+    ): Promise<TransactionSignature>;
+
+    signTransaction: Ref<SignerWalletAdapter['signTransaction'] | undefined>;
+    signAllTransactions: Ref<SignerWalletAdapter['signAllTransactions'] | undefined>;
+    signMessage: Ref<MessageSignerWalletAdapter['signMessage'] | undefined>;
+}
+
+export interface WalletStoreProps {
+    wallets: Wallet[];
+    autoConnect?: boolean;
+    onError?: (error: WalletError) => void;
+    localStorageKey?: string;
+}
+
+let walletStore: WalletStore = {} as WalletStore;
+
+export const useWallet = (): WalletStore => walletStore;
+
+export const initWallet = ({
+    wallets,
+    autoConnect = false,
+    onError = (error: WalletError) => console.error(error),
+    localStorageKey = 'walletName',
+}: WalletStoreProps): (() => void) => {
+    const name: Ref<WalletName | null> = useLocalStorage<WalletName>(localStorageKey);
+    const wallet = ref<Wallet | null>(null);
+    const adapter = ref<Adapter | null>(null);
+    const publicKey = ref<PublicKey | null>(null);
+    const ready = ref<boolean>(false);
+    const connected = ref<boolean>(false);
+    const connecting = ref<boolean>(false);
+    const disconnecting = ref<boolean>(false);
+
+    // Helper methods to set and reset the main state variables.
+    const setState = (state: {
+        wallet: Wallet | null;
+        adapter: Adapter | null;
+        publicKey: PublicKey | null;
+        ready: boolean;
+        connected: boolean;
+    }) => {
+        wallet.value = state.wallet;
+        adapter.value = state.adapter;
+        ready.value = state.ready;
+        publicKey.value = state.publicKey;
+        connected.value = state.connected;
+    };
+    const setStateFromAdapter = (wallet: Wallet, adapter: Adapter) => {
+        setState({
+            wallet,
+            adapter,
+            ready: adapter.ready,
+            publicKey: adapter.publicKey,
+            connected: adapter.connected,
+        });
+    };
+    const resetState = () => {
+        setState({
+            wallet: null,
+            adapter: null,
+            ready: false,
+            publicKey: null,
+            connected: false,
+        });
+    };
+
+    // Create a wallet dictionary keyed by their name.
+    const walletsByName = computed<WalletDictionary>(() => {
+        return wallets.reduce((walletsByName, wallet) => {
+            walletsByName[wallet.name] = wallet;
+            return walletsByName;
+        }, {} as WalletDictionary);
+    });
+
+    // Update the wallet and adapter based on the wallet provider.
+    watch(
+        name,
+        (): void => {
+            const wallet = walletsByName.value?.[name.value as WalletName] ?? null;
+            const adapter = wallet?.adapter() ?? null;
+            if (!adapter) return resetState();
+            setStateFromAdapter(wallet, adapter);
+        },
+        { immediate: true }
+    );
+
+    // Select a wallet by name.
+    const select = async (newName: WalletName): Promise<void> => {
+        if (name.value === newName) return;
+        if (adapter.value) await adapter.value.disconnect();
+        name.value = newName;
+    };
+
+    // Handle the adapter events.
+    const onReady = () => (ready.value = true);
+    const onDisconnect = () => (name.value = null);
+    const onConnect = () => {
+        if (!wallet.value || !adapter.value) return;
+        setStateFromAdapter(wallet.value, adapter.value);
+    };
+    const invalidateListeners = watchEffect((onInvalidate) => {
+        const _adapter = adapter.value;
+        if (!_adapter) return;
+
+        _adapter.on('ready', onReady);
+        _adapter.on('connect', onConnect);
+        _adapter.on('disconnect', onDisconnect);
+        _adapter.on('error', onError);
+
+        onInvalidate(() => {
+            _adapter.off('ready', onReady);
+            _adapter.off('connect', onConnect);
+            _adapter.off('disconnect', onDisconnect);
+            _adapter.off('error', onError);
+        });
+    });
+
+    // Helper method to return an error whilst using the onError callback.
+    const newError = (error: WalletError): WalletError => {
+        onError(error);
+        return error;
+    };
+
+    // Connect the adapter to the wallet.
+    const connect = async (): Promise<void> => {
+        if (connected.value || connecting.value || disconnecting.value) return;
+        if (!wallet.value || !adapter.value) throw newError(new WalletNotSelectedError());
+
+        if (!ready.value) {
+            name.value = null;
+            window.open(wallet.value.url, '_blank');
+            throw newError(new WalletNotReadyError());
+        }
+
+        try {
+            connecting.value = true;
+            await adapter.value.connect();
+        } catch (error: any) {
+            name.value = null;
+            throw error;
+        } finally {
+            connecting.value = false;
+        }
+    };
+
+    // Disconnect the adapter from the wallet.
+    const disconnect = async (): Promise<void> => {
+        if (disconnecting.value) return;
+        if (!adapter.value) {
+            name.value = null;
+            return;
+        }
+
+        try {
+            disconnecting.value = true;
+            await adapter.value.disconnect();
+        } finally {
+            name.value = null;
+            disconnecting.value = false;
+        }
+    };
+
+    // Send a transaction using the provided connection.
+    const sendTransaction = async (
+        transaction: Transaction,
+        connection: Connection,
+        options?: SendTransactionOptions
+    ) => {
+        if (!adapter.value) throw newError(new WalletNotSelectedError());
+        if (!connected.value) throw newError(new WalletNotConnectedError());
+        return await adapter.value.sendTransaction(transaction, connection, options);
+    };
+
+    // Sign a transaction if the wallet supports it.
+    const signTransaction = computed(() => {
+        const _adapter = adapter.value;
+        if (!(_adapter && 'signTransaction' in _adapter)) return;
+        return async (transaction: Transaction) => {
+            if (!connected.value) throw newError(new WalletNotConnectedError());
+            return await _adapter.signTransaction(transaction);
+        };
+    });
+
+    // Sign multiple transactions if the wallet supports it
+    const signAllTransactions = computed(() => {
+        const _adapter = adapter.value;
+        if (!(_adapter && 'signAllTransactions' in _adapter)) return;
+        return async (transactions: Transaction[]) => {
+            if (!connected.value) throw newError(new WalletNotConnectedError());
+            return await _adapter.signAllTransactions(transactions);
+        };
+    });
+
+    // Sign an arbitrary message if the wallet supports it.
+    const signMessage = computed(() => {
+        const _adapter = adapter.value;
+        if (!(_adapter && 'signMessage' in _adapter)) return;
+        return async (message: Uint8Array) => {
+            if (!connected.value) throw newError(new WalletNotConnectedError());
+            return await _adapter.signMessage(message);
+        };
+    });
+
+    // If autoConnect is enabled, try to connect when the adapter changes and is ready.
+    watchEffect(async (): Promise<void> => {
+        if (!autoConnect || !adapter.value || !ready.value || connected.value || connecting.value) return;
+        try {
+            connecting.value = true;
+            await adapter.value.connect();
+        } catch (error: any) {
+            // Clear the selected wallet
+            name.value = null;
+            // Don't throw error, but onError will still be called
+        } finally {
+            connecting.value = false;
+        }
+    });
+
+    // Set up the store.
+    walletStore = {
+        // Props.
+        wallets,
+        autoConnect,
+
+        // Data.
+        wallet,
+        adapter,
+        publicKey,
+        ready,
+        connected,
+        connecting,
+        disconnecting,
+
+        // Methods.
+        select,
+        connect,
+        disconnect,
+        sendTransaction,
+        signTransaction,
+        signAllTransactions,
+        signMessage,
+    };
+
+    if (typeof window !== 'undefined') {
+        // Trigger that method before unloading the page in case users did not register it.
+        window.addEventListener('beforeunload', invalidateListeners);
+    }
+
+    // Provide a method to cleanup any dependencies within the store.
+    return invalidateListeners;
+};

+ 9 - 0
packages/core/vue/tsconfig.json

@@ -0,0 +1,9 @@
+{
+    "extends": "../../../tsconfig.json",
+    "compilerOptions": {
+        "noEmit": false,
+        "outDir": "lib",
+        "isolatedModules": false
+    },
+    "include": ["src"]
+}

+ 112 - 2
yarn.lock

@@ -3953,6 +3953,96 @@
     "@typescript-eslint/types" "4.33.0"
     eslint-visitor-keys "^2.0.0"
 
+"@vue/compiler-core@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.19.tgz#b537dd377ce51fdb64e9b30ebfbff7cd70a64cb9"
+  integrity sha512-8dOPX0YOtaXol0Zf2cfLQ4NU/yHYl2H7DCKsLEZ7gdvPK6ZSEwGLJ7IdghhY2YEshEpC5RB9QKdC5I07z8Dtjg==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@vue/shared" "3.2.19"
+    estree-walker "^2.0.2"
+    source-map "^0.6.1"
+
+"@vue/compiler-dom@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.19.tgz#0607bc90de6af55fde73b09b3c4d0bf8cb597ed8"
+  integrity sha512-WzQoE8rfkFjPtIioc7SSgTsnz9g2oG61DU8KHnzPrRS7fW/lji6H2uCYJfp4Z6kZE8GjnHc1Ljwl3/gxDes0cw==
+  dependencies:
+    "@vue/compiler-core" "3.2.19"
+    "@vue/shared" "3.2.19"
+
+"@vue/compiler-sfc@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.19.tgz#d412195a98ebd49b84602f171719294a1d9549be"
+  integrity sha512-pLlbgkO1UHTO02MSpa/sFOXUwIDxSMiKZ1ozE5n71CY4DM+YmI+G3gT/ZHZ46WBId7f3VTF/D8pGwMygcQbrQA==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@vue/compiler-core" "3.2.19"
+    "@vue/compiler-dom" "3.2.19"
+    "@vue/compiler-ssr" "3.2.19"
+    "@vue/ref-transform" "3.2.19"
+    "@vue/shared" "3.2.19"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+    postcss "^8.1.10"
+    source-map "^0.6.1"
+
+"@vue/compiler-ssr@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.19.tgz#3e91ecf70f8f961c5f63eacd2139bcdab9a7a07c"
+  integrity sha512-oLon0Cn3O7WEYzzmzZavGoqXH+199LT+smdjBT3Uf3UX4HwDNuBFCmvL0TsqV9SQnIgKvBRbQ7lhbpnd4lqM3w==
+  dependencies:
+    "@vue/compiler-dom" "3.2.19"
+    "@vue/shared" "3.2.19"
+
+"@vue/reactivity@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.19.tgz#fc6e0f0106f295226835cfed5ff5f84d927bea65"
+  integrity sha512-FtachoYs2SnyrWup5UikP54xDX6ZJ1s5VgHcJp4rkGoutU3Ry61jhs+nCX7J64zjX992Mh9gGUC0LqTs8q9vCA==
+  dependencies:
+    "@vue/shared" "3.2.19"
+
+"@vue/ref-transform@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/ref-transform/-/ref-transform-3.2.19.tgz#cf0f986486bb26838fbd09749e927bab19745600"
+  integrity sha512-03wwUnoIAeKti5IGGx6Vk/HEBJ+zUcm5wrUM3+PQsGf7IYnXTbeIfHHpx4HeSeWhnLAjqZjADQwW8uA4rBmVbg==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@vue/compiler-core" "3.2.19"
+    "@vue/shared" "3.2.19"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+
+"@vue/runtime-core@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.19.tgz#807715b7f4728abb84fa4a8efdbe37d8ddb4c6d3"
+  integrity sha512-qArZSWKxWsgKfxk9BelZ32nY0MZ31CAW2kUUyVJyxh4cTfHaXGbjiQB5JgsvKc49ROMNffv9t3/qjasQqAH+RQ==
+  dependencies:
+    "@vue/reactivity" "3.2.19"
+    "@vue/shared" "3.2.19"
+
+"@vue/runtime-dom@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.19.tgz#7e8bf645754703e360fa132e4be9113edf2377bb"
+  integrity sha512-hIRboxXwafeHhbZEkZYNV0MiJXPNf4fP0X6hM2TJb0vssz8BKhD9cF92BkRgZztTQevecbhk0gu4uAPJ3dxL9A==
+  dependencies:
+    "@vue/runtime-core" "3.2.19"
+    "@vue/shared" "3.2.19"
+    csstype "^2.6.8"
+
+"@vue/server-renderer@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.19.tgz#870bcec9f7cdaee0c2187a169b6e636ab4362fb1"
+  integrity sha512-A9FNT7fgQJXItwdzWREntAgWKVtKYuXHBKGev/H4+ByTu8vB7gQXGcim01QxaJshdNg4dYuH2tEBZXCNCNx+/w==
+  dependencies:
+    "@vue/compiler-ssr" "3.2.19"
+    "@vue/shared" "3.2.19"
+
+"@vue/shared@3.2.19":
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.19.tgz#111ec3da18337d86274446984c49925b1b2b2dd7"
+  integrity sha512-Knqhx7WieLdVgwCAZgTVrDCXZ50uItuecLh9JdLC8O+a5ayaSyIQYveUK3hCRNC7ws5zalHmZwfdLMGaS8r4Ew==
+
 "@walletconnect/client@^2.0.0-beta.17":
   version "2.0.0-beta.18.2"
   resolved "https://registry.yarnpkg.com/@walletconnect/client/-/client-2.0.0-beta.18.2.tgz#135e9722ff4a1b685b3d78dbe2a6f77658488906"
@@ -6998,7 +7088,7 @@ cssstyle@^2.3.0:
   dependencies:
     cssom "~0.3.6"
 
-csstype@^2.5.2:
+csstype@^2.5.2, csstype@^2.6.8:
   version "2.6.18"
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.18.tgz#980a8b53085f34af313410af064f2bd241784218"
   integrity sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==
@@ -8128,7 +8218,7 @@ estree-walker@^1.0.1:
   resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
   integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
 
-estree-walker@^2.0.1:
+estree-walker@^2.0.1, estree-walker@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
   integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
@@ -14289,6 +14379,15 @@ postcss@^8.1.0, postcss@^8.2.15, postcss@^8.2.4, postcss@^8.3.5:
     picocolors "^0.2.1"
     source-map-js "^0.6.2"
 
+postcss@^8.1.10:
+  version "8.3.8"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.8.tgz#9ebe2a127396b4b4570ae9f7770e7fb83db2bac1"
+  integrity sha512-GT5bTjjZnwDifajzczOC+r3FI3Cu+PgPvrsjhQdRqa2kTJ4968/X9CUce9xttIB0xOs5c6xf0TCWZo/y9lF6bA==
+  dependencies:
+    nanocolors "^0.2.2"
+    nanoid "^3.1.25"
+    source-map-js "^0.6.2"
+
 preact@^10.4.1:
   version "10.5.14"
   resolved "https://registry.yarnpkg.com/preact/-/preact-10.5.14.tgz#0b14a2eefba3c10a57116b90d1a65f5f00cd2701"
@@ -17909,6 +18008,17 @@ vscode-textmate@5.2.0:
   resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e"
   integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==
 
+vue@^3.0.0:
+  version "3.2.19"
+  resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.19.tgz#da2c80a6a0271c7097fee9e31692adfd9d569c8f"
+  integrity sha512-6KAMdIfAtlK+qohTIUE4urwAv4A3YRuo8uAbByApUmiB0CziGAAPs6qVugN6oHPia8YIafHB/37K0O6KZ7sGmA==
+  dependencies:
+    "@vue/compiler-dom" "3.2.19"
+    "@vue/compiler-sfc" "3.2.19"
+    "@vue/runtime-dom" "3.2.19"
+    "@vue/server-renderer" "3.2.19"
+    "@vue/shared" "3.2.19"
+
 w3c-hr-time@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"