diff --git a/README.md b/README.md index d430fac..bf868a3 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ This repository contains wallet adapters and components for Tron DApps. With out | [Trust](https://trustwallet.com) | Android | Not Support | | | IOS | Not Support | | | Browser Extension | >= 1.0.0 | +| [Guarda](https://guarda.com/) | Android | >= 1.0.0 | +| | IOS | >= 1.0.0 | +| | Browser Extension | >= 1.0.0 | > **Note**: In case wallet developers intend to release breaking changes, you can [open an issue here](https://github.com/tronweb3/tronwallet-adapter/issues/new) to inform us, thus enabling us to update the new protocols accordingly. @@ -198,6 +201,7 @@ tronwallet-adapter | | ├─imtoken # adapter for imToken Wallet | | ├─gatewallet # adapter for gate.io Wallet | | ├─foxwallet # adapter for FoxWallet +| | ├─guarda # adapter for Guarda Wallet | | ├─bybit # adapter for Bybit Wallet | | ├─trust # adapter for Trust Wallet | ├─react diff --git a/demos/cdn-demo/guarda/index.html b/demos/cdn-demo/guarda/index.html new file mode 100644 index 0000000..d063157 --- /dev/null +++ b/demos/cdn-demo/guarda/index.html @@ -0,0 +1,97 @@ + + + + + + GuardaAdapter Test Demo + + + +
+ + + + +
+ + + \ No newline at end of file diff --git a/demos/cdn-demo/package.json b/demos/cdn-demo/package.json index 90ee882..594b31c 100644 --- a/demos/cdn-demo/package.json +++ b/demos/cdn-demo/package.json @@ -10,6 +10,7 @@ "@tronweb3/abstract-adapter-evm": "^1.0.1", "@tronweb3/tronwallet-abstract-adapter": "^1.1.6", "@tronweb3/tronwallet-adapter-bitkeep": "^1.0.2", + "@tronweb3/tronwallet-adapter-guarda": "^1.0.0", "@tronweb3/tronwallet-adapter-ledger": "^1.1.8", "@tronweb3/tronwallet-adapter-metamask": "^1.0.1", "@tronweb3/tronwallet-adapter-okxwallet": "^1.0.2", diff --git a/demos/dev-demo/src/AdapterBasicTest.tsx b/demos/dev-demo/src/AdapterBasicTest.tsx index f29f73a..a2b634f 100644 --- a/demos/dev-demo/src/AdapterBasicTest.tsx +++ b/demos/dev-demo/src/AdapterBasicTest.tsx @@ -14,7 +14,8 @@ import { WalletConnectAdapter, FoxWalletAdapter, BybitWalletAdapter, - TrustAdapter + TrustAdapter, + GuardaAdapter } from '@tronweb3/tronwallet-adapters'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { tronWeb } from './tronweb'; @@ -35,6 +36,7 @@ export const AdapterBasicTest = memo(function AdapterBasicTest() { new LedgerAdapter(), new WalletConnectAdapter(walletconnectConfig), new TrustAdapter(), + new GuardaAdapter(), ], [] ); diff --git a/demos/dev-demo/src/components/WalletProvider.tsx b/demos/dev-demo/src/components/WalletProvider.tsx index 2fcab39..3bd3551 100644 --- a/demos/dev-demo/src/components/WalletProvider.tsx +++ b/demos/dev-demo/src/components/WalletProvider.tsx @@ -13,7 +13,8 @@ import { FoxWalletAdapter, BybitWalletAdapter, TronLinkAdapterName, - TrustAdapter + TrustAdapter, + GuardaAdapter } from '@tronweb3/tronwallet-adapters'; import { walletconnectConfig } from '../config'; import type { Adapter, AdapterName } from "@tronweb3/tronwallet-abstract-adapter"; @@ -62,6 +63,7 @@ export default function WalletProvider({ children }: PropsWithChildren) { new FoxWalletAdapter(), new BybitWalletAdapter(), new LedgerAdapter(), + new GuardaAdapter(), new WalletConnectAdapter(walletconnectConfig), ]; }, []); diff --git a/demos/react-ui/next-app/pages/_app.tsx b/demos/react-ui/next-app/pages/_app.tsx index 191ad9b..0b98210 100644 --- a/demos/react-ui/next-app/pages/_app.tsx +++ b/demos/react-ui/next-app/pages/_app.tsx @@ -21,7 +21,7 @@ export default function App({ Component, pageProps }: AppProps) { const [adapters, setAdapters] = useState([]); useEffect(() => { import('@tronweb3/tronwallet-adapters').then((res) => { - const { BitKeepAdapter, OkxWalletAdapter, TokenPocketAdapter, TronLinkAdapter, WalletConnectAdapter } = res; + const { BitKeepAdapter, OkxWalletAdapter, TokenPocketAdapter, TronLinkAdapter, WalletConnectAdapter, GuardaAdapter } = res; const tronLinkAdapter = new TronLinkAdapter(); const ledger = new LedgerAdapter({ accountNumber: 2, @@ -49,6 +49,7 @@ export default function App({ Component, pageProps }: AppProps) { const bitKeepAdapter = new BitKeepAdapter(); const tokenPocketAdapter = new TokenPocketAdapter(); const okxwalletAdapter = new OkxWalletAdapter(); + const guardaAdapter = new GuardaAdapter(); setAdapters([ tronLinkAdapter, bitKeepAdapter, @@ -56,6 +57,7 @@ export default function App({ Component, pageProps }: AppProps) { okxwalletAdapter, walletConnectAdapter, ledger, + guardaAdapter, ]); }); }, [setAdapters]); diff --git a/demos/react-ui/vite-app/src/App.tsx b/demos/react-ui/vite-app/src/App.tsx index 8a4761b..0c97a6d 100644 --- a/demos/react-ui/vite-app/src/App.tsx +++ b/demos/react-ui/vite-app/src/App.tsx @@ -11,7 +11,7 @@ import { } from '@tronweb3/tronwallet-adapter-react-ui'; import toast from 'react-hot-toast'; import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Alert } from '@mui/material'; -import { TronLinkAdapter, TokenPocketAdapter, BitKeepAdapter, OkxWalletAdapter, GateWalletAdapter, BybitWalletAdapter, LedgerAdapter, WalletConnectAdapter } from '@tronweb3/tronwallet-adapters'; +import { TronLinkAdapter, TokenPocketAdapter, BitKeepAdapter, OkxWalletAdapter, GateWalletAdapter, BybitWalletAdapter, LedgerAdapter, WalletConnectAdapter, GuardaAdapter } from '@tronweb3/tronwallet-adapters'; import { tronWeb } from './tronweb'; import { Button } from '@tronweb3/tronwallet-adapter-react-ui'; const rows = [ @@ -85,7 +85,8 @@ export function App() { const okxWalletAdapter = new OkxWalletAdapter(); const gateAdapter = new GateWalletAdapter(); const bybitAdapter = new BybitWalletAdapter(); - return [tronLink1, walletConnect1, ledger, tokenPocket, bitKeep, okxWalletAdapter, gateAdapter, bybitAdapter]; + const guardaAdapter = new GuardaAdapter(); + return [tronLink1, walletConnect1, ledger, tokenPocket, bitKeep, okxWalletAdapter, gateAdapter, bybitAdapter, guardaAdapter]; }, []); function onConnect() { console.log('onConnect'); diff --git a/demos/vue-ui/vite-app/src/App.vue b/demos/vue-ui/vite-app/src/App.vue index dea11b0..cbd86ba 100644 --- a/demos/vue-ui/vite-app/src/App.vue +++ b/demos/vue-ui/vite-app/src/App.vue @@ -11,6 +11,7 @@ import { TronLinkAdapter, WalletConnectAdapter, BybitWalletAdapter, + GuardaAdapter, } from '@tronweb3/tronwallet-adapters'; import { WalletModalProvider } from '@tronweb3/tronwallet-adapter-vue-ui'; const tronLink = new TronLinkAdapter(); @@ -53,7 +54,8 @@ const tokenPocket = new TokenPocketAdapter(); const bitKeep = new BitKeepAdapter(); const okxWalletAdapter = new OkxWalletAdapter(); const bybit = new BybitWalletAdapter(); -const adapters = [tronLink, walletConnect, ledger, tokenPocket, bitKeep, okxWalletAdapter, bybit]; +const guarda = new GuardaAdapter(); +const adapters = [tronLink, walletConnect, ledger, tokenPocket, bitKeep, okxWalletAdapter, bybit, guarda]; function onAdapterChanged(adapter: Adapter) { console.log('[wallet hooks] onAdapterChanged: ', adapter?.name); diff --git a/packages/adapters/adapters/README.md b/packages/adapters/adapters/README.md index bbf2f37..d2c5b56 100644 --- a/packages/adapters/adapters/README.md +++ b/packages/adapters/adapters/README.md @@ -343,4 +343,5 @@ Other adapters `Constructor` config api can be found in their source code `READM - [GateWalletAdapter](https://github.com/tronweb3/tronwallet-adapter/tree/main/packages/adapters/gatewallet) - [FoxWalletAdapter](https://github.com/tronweb3/tronwallet-adapter/tree/main/packages/adapters/foxwallet) - [BybitWalletAdapter](https://github.com/tronweb3/tronwallet-adapter/tree/main/packages/adapters/bybit) +- [GuardaAdapter](https://github.com/tronweb3/tronwallet-adapter/tree/main/packages/adapters/guarda) - [TrustAdapter](https://github.com/tronweb3/tronwallet-adapter/tree/main/packages/adapters/trust) diff --git a/packages/adapters/adapters/package.json b/packages/adapters/adapters/package.json index 437ee38..e47fe9c 100644 --- a/packages/adapters/adapters/package.json +++ b/packages/adapters/adapters/package.json @@ -52,7 +52,8 @@ "@tronweb3/tronwallet-adapter-gatewallet": "workspace:^", "@tronweb3/tronwallet-adapter-foxwallet": "workspace:^", "@tronweb3/tronwallet-adapter-bybit": "workspace:^", - "@tronweb3/tronwallet-adapter-trust": "workspace:^" + "@tronweb3/tronwallet-adapter-trust": "workspace:^", + "@tronweb3/tronwallet-adapter-guarda": "workspace:^" }, "devDependencies": { "@vitest/browser": "^2.0.4", diff --git a/packages/adapters/adapters/src/index.ts b/packages/adapters/adapters/src/index.ts index 325d44f..2705e09 100644 --- a/packages/adapters/adapters/src/index.ts +++ b/packages/adapters/adapters/src/index.ts @@ -9,3 +9,4 @@ export * from '@tronweb3/tronwallet-adapter-imtoken'; export * from '@tronweb3/tronwallet-adapter-foxwallet'; export * from '@tronweb3/tronwallet-adapter-bybit'; export * from '@tronweb3/tronwallet-adapter-trust'; +export * from '@tronweb3/tronwallet-adapter-guarda'; diff --git a/packages/adapters/adapters/tests/e2e/adapters.test.ts b/packages/adapters/adapters/tests/e2e/adapters.test.ts index 7c258bc..71a2891 100644 --- a/packages/adapters/adapters/tests/e2e/adapters.test.ts +++ b/packages/adapters/adapters/tests/e2e/adapters.test.ts @@ -14,4 +14,5 @@ test("window['@tronweb3/tronwallet-adapters'] should exist", () => { expect(Adapters.FoxWalletAdapter).not.toBeUndefined(); expect(Adapters.BybitWalletAdapter).not.toBeUndefined(); expect(Adapters.TrustAdapter).not.toBeUndefined(); + expect(Adapters.GuardaAdapter).not.toBeUndefined(); }); diff --git a/packages/adapters/guarda/LICENSE b/packages/adapters/guarda/LICENSE new file mode 100644 index 0000000..0594dba --- /dev/null +++ b/packages/adapters/guarda/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2022-Present, tronweb3 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/adapters/guarda/README.md b/packages/adapters/guarda/README.md new file mode 100644 index 0000000..2ce64f6 --- /dev/null +++ b/packages/adapters/guarda/README.md @@ -0,0 +1,63 @@ +# @tronweb3/tronwallet-adapter-guarda + +Wallet adapter for Guarda Extension and App wallet. + +## Installation + +```bash +npm install @tronweb3/tronwallet-adapter-guarda +``` + +## Usage + +```typescript +import { GuardaAdapter } from '@tronweb3/tronwallet-adapter-guarda'; + +const adapter = new GuardaAdapter({ + checkTimeout: 2000, + openAppWithDeeplink: true, + openUrlWhenWalletNotFound: true, +}); + +// Connect to wallet +await adapter.connect(); + +// Get address +console.log(adapter.address); + +// Sign transaction +const signedTx = await adapter.signTransaction(transaction); + +// Sign message +const signature = await adapter.signMessage('Hello World'); + +// Disconnect +await adapter.disconnect(); +``` + +## Configuration + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `checkTimeout` | `number` | `2000` | Timeout in millisecond for checking if is in Guarda App | +| `openAppWithDeeplink` | `boolean` | `true` | Set if open Guarda app using DeepLink | +| `openUrlWhenWalletNotFound` | `boolean` | `true` | Set if open Guarda website when wallet not found | + +## Events + +The adapter extends the base adapter and emits the following events: + +- `readyStateChanged`: When the wallet ready state changes +- `connect`: When the wallet connects +- `disconnect`: When the wallet disconnects +- `accountsChanged`: When the account changes +- `chainChanged`: When the chain changes +- `stateChanged`: When the adapter state changes + +## Caveats + +- `multiSign()` and `switchChain(chainId: string)` are not supported. + +## License + +MIT \ No newline at end of file diff --git a/packages/adapters/guarda/jest.config.js b/packages/adapters/guarda/jest.config.js new file mode 100644 index 0000000..80670be --- /dev/null +++ b/packages/adapters/guarda/jest.config.js @@ -0,0 +1,17 @@ +export default { + preset: 'ts-jest', + testEnvironment: 'jsdom', + extensionsToTreatAsEsm: ['.ts'], + transform: { + '^.+\\.ts$': ['ts-jest', { + useESM: true, + }], + }, + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, + testMatch: ['/tests/**/*.test.ts'], + collectCoverageFrom: ['/src/**/*.ts'], + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov', 'html'], +}; \ No newline at end of file diff --git a/packages/adapters/guarda/package.json b/packages/adapters/guarda/package.json new file mode 100644 index 0000000..f5f987e --- /dev/null +++ b/packages/adapters/guarda/package.json @@ -0,0 +1,53 @@ +{ + "name": "@tronweb3/tronwallet-adapter-guarda", + "version": "1.0.0", + "description": "Wallet adapter for Guarda Extension and App wallet.", + "keywords": [ + "TRON", + "TronWeb", + "Guarda" + ], + "author": "tronweb3", + "repository": { + "type": "git", + "url": "https://github.com/tronweb3/tronwallet-adapter" + }, + "license": "MIT", + "type": "module", + "sideEffects": false, + "engines": { + "node": ">=16", + "pnpm": ">=7" + }, + "main": "./lib/cjs/index.js", + "module": "./lib/esm/index.js", + "types": "./lib/types/index.d.ts", + "exports": { + "require": "./lib/cjs/index.js", + "import": "./lib/esm/index.js", + "types": "./lib/types/index.d.ts" + }, + "files": [ + "lib", + "src", + "LICENSE" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "clean": "shx mkdir -p lib && shx rm -rf lib", + "package": "shx echo '{ \"type\": \"commonjs\" }' > lib/cjs/package.json", + "test": "jest", + "build:umd": "node ../../../scripts/build-umd.js" + }, + "dependencies": { + "@tronweb3/tronwallet-abstract-adapter": "workspace:^", + "@tronweb3/tronwallet-adapter-tronlink": "workspace:^" + }, + "devDependencies": { + "@testing-library/dom": "^8.20.0", + "jest-environment-jsdom": "^29.3.1", + "shx": "^0.3.4" + } +} \ No newline at end of file diff --git a/packages/adapters/guarda/src/adapter.ts b/packages/adapters/guarda/src/adapter.ts new file mode 100644 index 0000000..44e5753 --- /dev/null +++ b/packages/adapters/guarda/src/adapter.ts @@ -0,0 +1,304 @@ +import { + Adapter, + AdapterState, + isInBrowser, + WalletReadyState, + WalletSignMessageError, + WalletNotFoundError, + WalletDisconnectedError, + WalletSignTransactionError, + WalletGetNetworkError, + WalletConnectionError, + isInMobileBrowser, +} from '@tronweb3/tronwallet-abstract-adapter'; +import type { + Transaction, + SignedTransaction, + AdapterName, + BaseAdapterConfig, + Network, + TronWeb, +} from '@tronweb3/tronwallet-abstract-adapter'; +import { getNetworkInfoByTronWeb } from '@tronweb3/tronwallet-adapter-tronlink'; +import type { + Tron, + TronAccountsChangedCallback, + TronChainChangedCallback, +} from '@tronweb3/tronwallet-adapter-tronlink'; +import { supportGuarda } from './utils.js'; + +export interface GuardaAdapterConfig extends BaseAdapterConfig { + checkTimeout?: number; + openAppWithDeeplink?: boolean; +} + +export const GuardaAdapterName = 'Guarda' as AdapterName<'Guarda'>; + +export interface GuardaWallet { + ready: boolean; + tronWeb: TronWeb; + tron: Tron; +} + +declare global { + interface Window { + guarda?: GuardaWallet; + } +} + +export class GuardaAdapter extends Adapter { + name = GuardaAdapterName; + url = 'https://guarda.com?install=guarda-extensional'; + icon = 'data:image/svg+xml;utf8,'; + + config: Required; + private _readyState: WalletReadyState = isInBrowser() ? WalletReadyState.Loading : WalletReadyState.NotFound; + private _state: AdapterState = AdapterState.Loading; + private _connecting: boolean; + private _wallet: GuardaWallet | null; + private _address: string | null; + + constructor(config: GuardaAdapterConfig = {}) { + super(); + + const { checkTimeout = 2 * 1000, openUrlWhenWalletNotFound = true, openAppWithDeeplink = true } = config; + if (typeof checkTimeout !== 'number') { + throw new Error('[GuardaAdapter] config.checkTimeout should be a number'); + } + this.config = { + checkTimeout, + openAppWithDeeplink, + openUrlWhenWalletNotFound, + }; + this._connecting = false; + this._wallet = null; + this._address = null; + + if (supportGuarda()) { + this._readyState = WalletReadyState.Found; + this._updateWallet(); + } else { + this._checkWallet().then(() => { + if (this.connected) { + this.emit('connect', this.address || ''); + } + }); + } + } + + get address() { + return this._address; + } + + get state() { + return this._state; + } + + get readyState() { + return this._readyState; + } + + get connecting() { + return this._connecting; + } + + async network(): Promise { + try { + await this._checkWallet(); + + if (this.state !== AdapterState.Connected) throw new WalletDisconnectedError(); + + const wallet = this._wallet; + if (!wallet || !wallet.tronWeb) throw new WalletDisconnectedError(); + + try { + const networkInfo = await getNetworkInfoByTronWeb(wallet.tronWeb); + return networkInfo; + } catch (err: any) { + throw new WalletGetNetworkError(err?.message, err); + } + } catch (error: any) { + this.emit('error', error); + throw error; + } + } + + async connect(): Promise { + try { + if (this.connected || this.connecting) { + return; + } + + await this._checkWallet(); + + if (this.readyState === WalletReadyState.NotFound) { + if (this.config.openUrlWhenWalletNotFound !== false && isInBrowser()) { + window.open(this.url, '_blank'); + } + throw new WalletNotFoundError(); + } + + if (!this._wallet) { + return; + } + + this._connecting = true; + const wallet = this._wallet as GuardaWallet; + + const res = await wallet.tron.request({ method: 'eth_requestAccounts' }); + + if (!res?.[0]) { + throw new WalletConnectionError('Request connect error.'); + } + + const address = res[0]; + + this.setAddress(address); + this.setState(AdapterState.Connected); + this.listenTronEvent(); + this.emit('connect', this.address || ''); + } catch (error: any) { + this.emit('error', error); + throw error; + } finally { + this._connecting = false; + } + } + + async disconnect(): Promise { + if (this.state !== AdapterState.Connected) { + return; + } + this.stopListenTronEvent(); + this.setAddress(null); + this.setState(AdapterState.Disconnect); + this.emit('disconnect'); + } + + async signTransaction(transaction: Transaction): Promise { + try { + const wallet = await this.checkAndGetWallet(); + try { + const signedTx = await wallet.tronWeb.trx.sign(transaction); + return signedTx; + } catch (error: any) { + if (error instanceof Error) { + throw new WalletSignTransactionError(error.message, error); + } else { + throw new WalletSignTransactionError(error, new Error(error)); + } + } + } catch (error: any) { + this.emit('error', error); + throw error; + } + } + + async signMessage(message: string): Promise { + try { + const wallet = await this.checkAndGetWallet(); + try { + const signature = await wallet.tronWeb.trx.signMessage(message); + return signature; + } catch (error: any) { + if (error instanceof Error) { + throw new WalletSignMessageError(error.message, error); + } else { + throw new WalletSignMessageError(error, new Error(error)); + } + } + } catch (error: any) { + this.emit('error', error); + throw error; + } + } + + private onChainChanged: TronChainChangedCallback = (data) => { + this.emit('chainChanged', data); + }; + + private onAccountsChanged: TronAccountsChangedCallback = () => { + const prevAddress = this._address || ''; + if (this._wallet?.tronWeb?.defaultAddress?.base58) { + const address = this._wallet.tronWeb.defaultAddress.base58; + this.setAddress(address); + this.emit('accountsChanged', address, prevAddress); + } else { + this.setAddress(null); + this.emit('disconnect'); + } + }; + + private listenTronEvent() { + this.stopListenTronEvent(); + if (this._wallet?.tron) { + this._wallet.tron.on('chainChanged', this.onChainChanged); + this._wallet.tron.on('accountsChanged', this.onAccountsChanged); + } + } + + private stopListenTronEvent() {} + + private async checkAndGetWallet() { + await this._checkWallet(); + if (this.state !== AdapterState.Connected) { + throw new WalletDisconnectedError(); + } + const wallet = this._wallet; + if (!wallet || !wallet.tronWeb) { + throw new WalletDisconnectedError(); + } + return wallet; + } + + private _checkPromise: Promise | null = null; + + private _checkWallet(): Promise { + if (this._checkPromise) { + return this._checkPromise; + } + + this._checkPromise = new Promise((resolve) => { + const check = () => { + if (supportGuarda()) { + this._readyState = WalletReadyState.Found; + this._updateWallet(); + resolve(true); + } else { + this._readyState = WalletReadyState.NotFound; + this.setState(AdapterState.NotFound); + resolve(false); + } + }; + check(); + }); + return this._checkPromise; + } + + private _updateWallet = () => { + if (!isInBrowser()) { + return; + } + + const guarda = window.guarda; + + if (guarda && guarda.tronWeb) { + this._wallet = guarda; + this.setState(AdapterState.Disconnect); + this.emit('readyStateChanged', this._readyState); + } else { + this._wallet = null; + this.setState(AdapterState.NotFound); + this.emit('readyStateChanged', this._readyState); + } + }; + + private setAddress(address: string | null) { + this._address = address; + } + + private setState(state: AdapterState) { + this._state = state; + this.emit('stateChanged', state); + } +} diff --git a/packages/adapters/guarda/src/index.ts b/packages/adapters/guarda/src/index.ts new file mode 100644 index 0000000..32e1005 --- /dev/null +++ b/packages/adapters/guarda/src/index.ts @@ -0,0 +1,2 @@ +export * from './adapter.js'; +export * from './utils.js'; \ No newline at end of file diff --git a/packages/adapters/guarda/src/utils.ts b/packages/adapters/guarda/src/utils.ts new file mode 100644 index 0000000..0f15e25 --- /dev/null +++ b/packages/adapters/guarda/src/utils.ts @@ -0,0 +1,3 @@ +export function supportGuarda() { + return !!window.tronWeb && typeof window.guarda !== 'undefined'; +} diff --git a/packages/adapters/guarda/tests/units/adapter.test.ts b/packages/adapters/guarda/tests/units/adapter.test.ts new file mode 100644 index 0000000..60ad7b2 --- /dev/null +++ b/packages/adapters/guarda/tests/units/adapter.test.ts @@ -0,0 +1,25 @@ +import { GuardaAdapter } from '../../src/adapter'; + +describe('GuardaAdapter', () => { + test('should be defined', () => { + expect(GuardaAdapter).not.toBeNull(); + }); + test('#constructor() should work fine', () => { + const adapter = new GuardaAdapter(); + expect(adapter.name).toEqual('Guarda'); + expect(adapter).toHaveProperty('icon'); + expect(adapter).toHaveProperty('url'); + expect(adapter).toHaveProperty('readyState'); + expect(adapter).toHaveProperty('address'); + expect(adapter).toHaveProperty('connecting'); + expect(adapter).toHaveProperty('connected'); + + expect(adapter).toHaveProperty('connect'); + expect(adapter).toHaveProperty('disconnect'); + expect(adapter).toHaveProperty('signMessage'); + expect(adapter).toHaveProperty('signTransaction'); + + expect(adapter).toHaveProperty('on'); + expect(adapter).toHaveProperty('off'); + }); +}); \ No newline at end of file diff --git a/packages/adapters/guarda/tsconfig.all.json b/packages/adapters/guarda/tsconfig.all.json new file mode 100644 index 0000000..a1ded9c --- /dev/null +++ b/packages/adapters/guarda/tsconfig.all.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../tsconfig.root.json", + "references": [ + { + "path": "../abstract-adapter/tsconfig.all.json" + }, + { + "path": "../tronlink/tsconfig.all.json" + }, + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + } + ] +} diff --git a/packages/adapters/guarda/tsconfig.cjs.json b/packages/adapters/guarda/tsconfig.cjs.json new file mode 100644 index 0000000..099b9aa --- /dev/null +++ b/packages/adapters/guarda/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.cjs.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs" + } +} diff --git a/packages/adapters/guarda/tsconfig.esm.json b/packages/adapters/guarda/tsconfig.esm.json new file mode 100644 index 0000000..4900d2f --- /dev/null +++ b/packages/adapters/guarda/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "../../../tsconfig.esm.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e1049d7..efdb3e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,6 +177,9 @@ importers: '@tronweb3/tronwallet-adapter-bitkeep': specifier: ^1.0.2 version: link:../../packages/adapters/bitkeep + '@tronweb3/tronwallet-adapter-guarda': + specifier: ^1.0.0 + version: link:../../packages/adapters/guarda '@tronweb3/tronwallet-adapter-ledger': specifier: ^1.1.8 version: 1.1.8 @@ -574,6 +577,9 @@ importers: '@tronweb3/tronwallet-adapter-gatewallet': specifier: workspace:^ version: link:../gatewallet + '@tronweb3/tronwallet-adapter-guarda': + specifier: workspace:^ + version: link:../guarda '@tronweb3/tronwallet-adapter-imtoken': specifier: workspace:^ version: link:../imtoken @@ -691,6 +697,25 @@ importers: specifier: ^0.3.4 version: 0.3.4 + packages/adapters/guarda: + dependencies: + '@tronweb3/tronwallet-abstract-adapter': + specifier: workspace:^ + version: link:../abstract-adapter + '@tronweb3/tronwallet-adapter-tronlink': + specifier: workspace:^ + version: link:../tronlink + devDependencies: + '@testing-library/dom': + specifier: ^8.20.0 + version: 8.20.1 + jest-environment-jsdom: + specifier: ^29.3.1 + version: 29.7.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + shx: + specifier: ^0.3.4 + version: 0.3.4 + packages/adapters/imtoken: dependencies: '@tronweb3/tronwallet-abstract-adapter': @@ -11529,41 +11554,6 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.42 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/environment@28.1.3': dependencies: '@jest/fake-timers': 28.1.3 @@ -15102,21 +15092,6 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - create-jest@29.7.0(@types/node@20.14.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.12)(typescript@5.5.4)): dependencies: '@jest/types': 29.6.3 @@ -15619,8 +15594,8 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-react: 7.35.0(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -15642,13 +15617,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 is-core-module: 2.15.0 @@ -15659,18 +15634,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -15680,7 +15655,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -15691,7 +15666,7 @@ snapshots: semver: 7.6.3 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.5.4) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16823,25 +16798,6 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)): - dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-cli@29.7.0(@types/node@20.14.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.12)(typescript@5.5.4)): dependencies: '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.12)(typescript@5.5.4)) @@ -17013,37 +16969,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)): - dependencies: - '@babel/core': 7.27.1 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0(babel-plugin-macros@3.1.0) - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 18.19.42 - ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.3) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - jest-config@29.7.0(@types/node@20.14.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.12)(typescript@5.5.4)): dependencies: '@babel/core': 7.27.1 @@ -17579,10 +17504,10 @@ snapshots: jest@29.6.4(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.4)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.3)) + jest-cli: 29.7.0(@types/node@18.19.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.4)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros diff --git a/tsconfig.all.json b/tsconfig.all.json index 7cccf19..0da7cb2 100644 --- a/tsconfig.all.json +++ b/tsconfig.all.json @@ -19,6 +19,9 @@ { "path": "./packages/adapters/tokenpocket/tsconfig.all.json" }, + { + "path": "./packages/adapters/guarda/tsconfig.all.json" + }, { "path": "./packages/adapters/bitkeep/tsconfig.all.json" },