diff --git a/.changeset/strong-panthers-notice.md b/.changeset/strong-panthers-notice.md new file mode 100644 index 00000000000..b393a5d878e --- /dev/null +++ b/.changeset/strong-panthers-notice.md @@ -0,0 +1,56 @@ +--- +"@thirdweb-dev/wagmi-adapter": minor +--- + +Wagmi connector for in-app wallets + +You can now connect to an in-app wallet in your wagmi applications. + +Install the wagmi adapter: + +```bash +npm install @thirdweb-dev/wagmi-adapter +``` + +Create a wagmi config with the in-app wallet connector: + +```ts +import { http, createConfig } from "wagmi"; +import { inAppWalletConnector } from "@thirdweb-dev/wagmi-adapter"; +import { createThirdwebClient, defineChain as thirdwebChain } from "thirdweb"; + +const client = createThirdwebClient({ + clientId: "...", +}); + +export const config = createConfig({ + chains: [sepolia], + connectors: [ + inAppWalletConnector({ + client, + // optional: turn on smart accounts + smartAccounts: { + sponsorGas: true, + chain: thirdwebChain(sepolia), + }, + }), + ], + transports: { + [sepolia.id]: http(), + }, +}); +``` + +Then in your app, you can use the connector to connect with any supported strategy: + +```ts +const { connect, connectors } = useConnect(); + +const onClick = () => { + const inAppWallet = connectors.find((x) => x.id === "in-app-wallet"); + connect({ + connector: inAppWallet, + strategy: "google", + }); +}; +``` diff --git a/packages/thirdweb/src/exports/wallets.native.ts b/packages/thirdweb/src/exports/wallets.native.ts index 08ac10ad04c..09a7b8215db 100644 --- a/packages/thirdweb/src/exports/wallets.native.ts +++ b/packages/thirdweb/src/exports/wallets.native.ts @@ -89,8 +89,14 @@ export type { * @deprecated use InAppWalletSocialAuth instead */ InAppWalletSocialAuth as EmbeddedWalletSocialAuth, + InAppWalletCreationOptions, } from "../wallets/in-app/core/wallet/types.js"; +export type { + MultiStepAuthArgsType, + SingleStepAuthArgsType, +} from "../wallets/in-app/core/authentication/types.js"; + export { preAuthenticate, authenticate, diff --git a/packages/thirdweb/src/exports/wallets.ts b/packages/thirdweb/src/exports/wallets.ts index e9e24c3facc..4336ac5f1ba 100644 --- a/packages/thirdweb/src/exports/wallets.ts +++ b/packages/thirdweb/src/exports/wallets.ts @@ -96,8 +96,14 @@ export type { * @deprecated use InAppWalletSocialAuth instead */ InAppWalletSocialAuth as EmbeddedWalletSocialAuth, + InAppWalletCreationOptions, } from "../wallets/in-app/core/wallet/types.js"; +export type { + MultiStepAuthArgsType, + SingleStepAuthArgsType, +} from "../wallets/in-app/core/authentication/types.js"; + export { preAuthenticate, authenticate, diff --git a/packages/thirdweb/src/exports/wallets/in-app.native.ts b/packages/thirdweb/src/exports/wallets/in-app.native.ts index bf0515d84f5..e5de5a432b3 100644 --- a/packages/thirdweb/src/exports/wallets/in-app.native.ts +++ b/packages/thirdweb/src/exports/wallets/in-app.native.ts @@ -18,6 +18,12 @@ export type { InAppWalletAuth, InAppWalletSocialAuth, InAppWalletConnectionOptions, + InAppWalletAutoConnectOptions, } from "../../wallets/in-app/core/wallet/types.js"; +export type { + MultiStepAuthArgsType, + SingleStepAuthArgsType, +} from "../../wallets/in-app/core/authentication/types.js"; + export { hasStoredPasskey } from "../../wallets/in-app/native/auth/passkeys.js"; diff --git a/packages/thirdweb/src/exports/wallets/in-app.ts b/packages/thirdweb/src/exports/wallets/in-app.ts index e9e64cc6307..3a3812a6575 100644 --- a/packages/thirdweb/src/exports/wallets/in-app.ts +++ b/packages/thirdweb/src/exports/wallets/in-app.ts @@ -18,8 +18,14 @@ export type { InAppWalletAuth, InAppWalletSocialAuth, InAppWalletConnectionOptions, + InAppWalletAutoConnectOptions, } from "../../wallets/in-app/core/wallet/types.js"; +export type { + MultiStepAuthArgsType, + SingleStepAuthArgsType, +} from "../../wallets/in-app/core/authentication/types.js"; + export { hasStoredPasskey } from "../../wallets/in-app/web/lib/auth/passkeys.js"; export { diff --git a/packages/thirdweb/src/wallets/in-app/core/wallet/types.ts b/packages/thirdweb/src/wallets/in-app/core/wallet/types.ts index b1c0e7969a2..7d0a048ad85 100644 --- a/packages/thirdweb/src/wallets/in-app/core/wallet/types.ts +++ b/packages/thirdweb/src/wallets/in-app/core/wallet/types.ts @@ -1,6 +1,7 @@ import type { Chain } from "../../../../chains/types.js"; import type { ThirdwebClient } from "../../../../client/client.js"; import type { SupportedSmsCountry } from "../../../../react/web/wallets/in-app/supported-sms-countries.js"; +import type { Prettify } from "../../../../utils/type-utils.js"; import type { SmartWalletOptions } from "../../../smart/types.js"; import type { AuthOption, @@ -20,14 +21,12 @@ export type Ecosystem = { partnerId?: string; }; -export type InAppWalletConnectionOptions = ( - | MultiStepAuthArgsType - | SingleStepAuthArgsType -) & { - client: ThirdwebClient; - chain?: Chain; - redirect?: boolean; -}; +export type InAppWalletConnectionOptions = Prettify< + (MultiStepAuthArgsType | SingleStepAuthArgsType) & { + client: ThirdwebClient; + chain?: Chain; + } +>; export type InAppWalletAutoConnectOptions = { client: ThirdwebClient; diff --git a/packages/thirdweb/src/wallets/manager/connection-manager.test.ts b/packages/thirdweb/src/wallets/manager/connection-manager.test.ts index 5fa56f47521..ea57ad3c953 100644 --- a/packages/thirdweb/src/wallets/manager/connection-manager.test.ts +++ b/packages/thirdweb/src/wallets/manager/connection-manager.test.ts @@ -199,157 +199,157 @@ describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => { const definedChain = manager.activeWalletChainStore.getValue(); expect(definedChain).toEqual(newChain); }); -}); - -describe("handleSmartWalletConnection", () => { - let client: ThirdwebClient; - let eoaWallet: Wallet; - let smartWalletOptions: SmartWalletOptions; - beforeEach(() => { - client = TEST_CLIENT; - eoaWallet = { - id: "eoa-wallet-id", - getAccount: vi.fn().mockReturnValue(TEST_ACCOUNT_A), - subscribe: vi.fn().mockReturnValue(vi.fn()), - disconnect: vi.fn(), - switchChain: vi.fn(), - getChain: vi.fn().mockReturnValue(sepolia), - getConfig: vi.fn(), - } as unknown as Wallet; - smartWalletOptions = { - chain: sepolia, - } as SmartWalletOptions; - }); - - it("should connect a smart wallet and subscribe to disconnect event", async () => { - const onWalletDisconnect = vi.fn(); - const smartWallet = await handleSmartWalletConnection( - eoaWallet, - client, - smartWalletOptions, - onWalletDisconnect, - ); - - expect(smartWallet.getAccount()).toBeTruthy(); - - expect(eoaWallet.subscribe).toHaveBeenCalledWith( - "disconnect", - expect.any(Function), - ); - }); - - it("should call onWalletDisconnect when EOA wallet disconnects", async () => { - const onWalletDisconnect = vi.fn(); - const smartWallet = await handleSmartWalletConnection( - eoaWallet, - client, - smartWalletOptions, - onWalletDisconnect, - ); + describe("handleSmartWalletConnection", () => { + let client: ThirdwebClient; + let eoaWallet: Wallet; + let smartWalletOptions: SmartWalletOptions; + + beforeEach(() => { + client = TEST_CLIENT; + eoaWallet = { + id: "eoa-wallet-id", + getAccount: vi.fn().mockReturnValue(TEST_ACCOUNT_A), + subscribe: vi.fn().mockReturnValue(vi.fn()), + disconnect: vi.fn(), + switchChain: vi.fn(), + getChain: vi.fn().mockReturnValue(sepolia), + getConfig: vi.fn(), + } as unknown as Wallet; + smartWalletOptions = { + chain: sepolia, + } as SmartWalletOptions; + }); - // biome-ignore lint/suspicious/noExplicitAny: Mocked function - const disconnectCallback = (eoaWallet.subscribe as any).mock.calls[0][1]; - disconnectCallback(); + it("should connect a smart wallet and subscribe to disconnect event", async () => { + const onWalletDisconnect = vi.fn(); + const smartWallet = await handleSmartWalletConnection( + eoaWallet, + client, + smartWalletOptions, + onWalletDisconnect, + ); - expect(onWalletDisconnect).toHaveBeenCalledWith(smartWallet); - }); + expect(smartWallet.getAccount()).toBeTruthy(); - it("should throw an error if EOA wallet has no account", async () => { - eoaWallet.getAccount = vi.fn().mockReturnValue(null); + expect(eoaWallet.subscribe).toHaveBeenCalledWith( + "disconnect", + expect.any(Function), + ); + }); - await expect( - handleSmartWalletConnection( + it("should call onWalletDisconnect when EOA wallet disconnects", async () => { + const onWalletDisconnect = vi.fn(); + const smartWallet = await handleSmartWalletConnection( eoaWallet, client, smartWalletOptions, - vi.fn(), - ), - ).rejects.toThrow("Cannot set a wallet without an account as active"); - }); -}); + onWalletDisconnect, + ); -describe("Connection Manager Error Handling", () => { - let storage: AsyncStorage; - let client: ThirdwebClient; - let wallet: Wallet; + // biome-ignore lint/suspicious/noExplicitAny: Mocked function + const disconnectCallback = (eoaWallet.subscribe as any).mock.calls[0][1]; + disconnectCallback(); - beforeEach(() => { - storage = { - getItem: vi.fn(), - setItem: vi.fn(), - removeItem: vi.fn(), - }; - client = TEST_CLIENT; - wallet = { - id: "wallet-id", - getAccount: vi.fn().mockReturnValue(null), // Simulate wallet without an account - subscribe: vi.fn(), - disconnect: vi.fn(), - switchChain: vi.fn(), - getChain: vi.fn().mockReturnValue(sepolia), - getConfig: vi.fn(), - } as unknown as Wallet; - }); - - it("should throw an error if trying to set a wallet without an account as active", async () => { - const manager = createConnectionManager(storage); + expect(onWalletDisconnect).toHaveBeenCalledWith(smartWallet); + }); - await expect(manager.setActiveWallet(wallet)).rejects.toThrow( - "Cannot set a wallet without an account as active", - ); + it("should throw an error if EOA wallet has no account", async () => { + eoaWallet.getAccount = vi.fn().mockReturnValue(null); + + await expect( + handleSmartWalletConnection( + eoaWallet, + client, + smartWalletOptions, + vi.fn(), + ), + ).rejects.toThrow("Cannot set a wallet without an account as active"); + }); }); - it("should throw an error if handleConnection is called with a wallet without an account", async () => { - const manager = createConnectionManager(storage); + describe("Connection Manager Error Handling", () => { + let storage: AsyncStorage; + let client: ThirdwebClient; + let wallet: Wallet; + + beforeEach(() => { + storage = { + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + }; + client = TEST_CLIENT; + wallet = { + id: "wallet-id", + getAccount: vi.fn().mockReturnValue(null), // Simulate wallet without an account + subscribe: vi.fn(), + disconnect: vi.fn(), + switchChain: vi.fn(), + getChain: vi.fn().mockReturnValue(sepolia), + getConfig: vi.fn(), + } as unknown as Wallet; + }); - await expect(manager.handleConnection(wallet, { client })).rejects.toThrow( - "Cannot set a wallet without an account as active", - ); - }); -}); + it("should throw an error if trying to set a wallet without an account as active", async () => { + const manager = createConnectionManager(storage); -describe("Connection Manager Event Subscriptions", () => { - let storage: AsyncStorage; - let client: ThirdwebClient; - let wallet: Wallet; - let account: Account; + await expect(manager.setActiveWallet(wallet)).rejects.toThrow( + "Cannot set a wallet without an account as active", + ); + }); - beforeEach(() => { - storage = { - getItem: vi.fn(), - setItem: vi.fn(), - removeItem: vi.fn(), - }; - client = TEST_CLIENT; - account = TEST_ACCOUNT_A; - wallet = { - id: "wallet-id", - getAccount: vi.fn().mockReturnValue(account), - subscribe: vi.fn().mockReturnValue(vi.fn()), - disconnect: vi.fn(), - switchChain: vi.fn(), - getChain: vi.fn().mockReturnValue(sepolia), - getConfig: vi.fn(), - } as unknown as Wallet; - }); + it("should throw an error if handleConnection is called with a wallet without an account", async () => { + const manager = createConnectionManager(storage); - it("should subscribe to accountChanged, chainChanged, and disconnect events", async () => { - const manager = createConnectionManager(storage); + await expect( + manager.handleConnection(wallet, { client }), + ).rejects.toThrow("Cannot set a wallet without an account as active"); + }); + }); - await manager.handleConnection(wallet, { client }); + describe("Connection Manager Event Subscriptions", () => { + let storage: AsyncStorage; + let client: ThirdwebClient; + let wallet: Wallet; + let account: Account; + + beforeEach(() => { + storage = { + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + }; + client = TEST_CLIENT; + account = TEST_ACCOUNT_A; + wallet = { + id: "wallet-id", + getAccount: vi.fn().mockReturnValue(account), + subscribe: vi.fn().mockReturnValue(vi.fn()), + disconnect: vi.fn(), + switchChain: vi.fn(), + getChain: vi.fn().mockReturnValue(sepolia), + getConfig: vi.fn(), + } as unknown as Wallet; + }); - expect(wallet.subscribe).toHaveBeenCalledWith( - "accountChanged", - expect.any(Function), - ); - expect(wallet.subscribe).toHaveBeenCalledWith( - "chainChanged", - expect.any(Function), - ); - expect(wallet.subscribe).toHaveBeenCalledWith( - "disconnect", - expect.any(Function), - ); + it("should subscribe to accountChanged, chainChanged, and disconnect events", async () => { + const manager = createConnectionManager(storage); + + await manager.handleConnection(wallet, { client }); + + expect(wallet.subscribe).toHaveBeenCalledWith( + "accountChanged", + expect.any(Function), + ); + expect(wallet.subscribe).toHaveBeenCalledWith( + "chainChanged", + expect.any(Function), + ); + expect(wallet.subscribe).toHaveBeenCalledWith( + "disconnect", + expect.any(Function), + ); + }); }); }); diff --git a/packages/wagmi-adapter/README.md b/packages/wagmi-adapter/README.md new file mode 100644 index 00000000000..9b513578fbf --- /dev/null +++ b/packages/wagmi-adapter/README.md @@ -0,0 +1,3 @@ +# Wagmi Adapter + +This package enables the use of thirdweb's in-app wallets with wagmi. diff --git a/packages/wagmi-adapter/package.json b/packages/wagmi-adapter/package.json new file mode 100644 index 00000000000..6372f9cd406 --- /dev/null +++ b/packages/wagmi-adapter/package.json @@ -0,0 +1,55 @@ +{ + "name": "@thirdweb-dev/wagmi-adapter", + "version": "0.0.1", + "repository": { + "type": "git", + "url": "git+https://github.com/thirdweb-dev/js.git#main" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/thirdweb-dev/js/issues" + }, + "author": "thirdweb eng ", + "type": "module", + "main": "./dist/cjs/exports/thirdweb.js", + "module": "./dist/esm/exports/thirdweb.js", + "types": "./dist/types/exports/thirdweb.d.ts", + "typings": "./dist/types/exports/thirdweb.d.ts", + "exports": { + ".": { + "types": "./dist/types/exports/thirdweb.d.ts", + "import": "./dist/esm/exports/thirdweb.js", + "default": "./dist/cjs/exports/thirdweb.js" + }, + "./package.json": "./package.json" + }, + "files": ["dist/*", "src/*"], + "devDependencies": { + "@wagmi/core": "2.16.0", + "rimraf": "6.0.1", + "thirdweb": "workspace:*" + }, + "peerDependencies": { + "@wagmi/core": "^2.16.0", + "thirdweb": "^5", + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + }, + "scripts": { + "format": "biome format ./src --write", + "lint": "biome check ./src", + "fix": "biome check ./src --fix", + "build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types", + "build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json", + "build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json", + "build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", + "clean": "rimraf dist" + }, + "engines": { + "node": ">=18" + } +} diff --git a/packages/wagmi-adapter/src/connector.ts b/packages/wagmi-adapter/src/connector.ts new file mode 100644 index 00000000000..0651f2d4fa9 --- /dev/null +++ b/packages/wagmi-adapter/src/connector.ts @@ -0,0 +1,169 @@ +import { type CreateConnectorFn, createConnector } from "@wagmi/core"; +import type { Prettify } from "@wagmi/core/chains"; +import { type ThirdwebClient, defineChain, getAddress } from "thirdweb"; +import { + EIP1193, + type InAppWalletConnectionOptions, + type InAppWalletCreationOptions, + type MultiStepAuthArgsType, + type SingleStepAuthArgsType, + ecosystemWallet, + inAppWallet as thirdwebInAppWallet, +} from "thirdweb/wallets"; + +export type InAppWalletParameters = Prettify< + InAppWalletCreationOptions & { + client: ThirdwebClient; + ecosystemId?: `ecosystem.${string}`; + } +>; +export type InAppWalletConnector = ReturnType; +export type ConnectionOptions = Prettify< + (MultiStepAuthArgsType | SingleStepAuthArgsType) & { + chainId?: number | undefined; + isReconnecting?: boolean | undefined; + } +>; + +type Provider = EIP1193.EIP1193Provider | undefined; +type Properties = { + connect(parameters?: ConnectionOptions): Promise<{ + accounts: readonly `0x${string}`[]; + chainId: number; + }>; +}; +type StorageItem = { "tw.lastChainId": number }; + +/** + * Connect to an in-app wallet using the auth strategy of your choice. + * @param args - Options for the in-app wallet connection. + * @returns A wagmi connector. + * @example + * ```ts + * import { http, createConfig } from "wagmi"; + * import { inAppWalletConnector } from "@thirdweb-dev/wagmi-adapter"; + * import { createThirdwebClient, defineChain as thirdwebChain } from "thirdweb"; + * + * const client = createThirdwebClient({ + * clientId: "...", + * }); + * + * export const config = createConfig({ + * chains: [sepolia], + * connectors: [ + * inAppWalletConnector({ + * client, + * // optional: turn on smart accounts + * smartAccounts: { + * sponsorGas: true, + * chain: thirdwebChain(sepolia) + * } + * }), + * ], + * transports: { + * [sepolia.id]: http(), + * }, + * }); + * ``` + * + * Then in your app, you can use the connector to connect with any supported strategy: + * + * ```ts + * const { connect, connectors } = useConnect(); + * + * const onClick = () => { + * const inAppWallet = connectors.find((x) => x.id === "in-app-wallet"); + * connect({ + * connector: inAppWallet, strategy: "google" + * }); + * }; + * ``` + * @beta + */ +export function inAppWalletConnector( + args: InAppWalletParameters, +): CreateConnectorFn { + const wallet = args.ecosystemId + ? ecosystemWallet(args.ecosystemId, { partnerId: args.partnerId }) + : thirdwebInAppWallet(args); + const client = args.client; + return createConnector((config) => ({ + id: "in-app-wallet", + name: "In-App wallet", + type: "in-app", + connect: async (params) => { + const lastChainId = await config.storage?.getItem("tw.lastChainId"); + if (params?.isReconnecting) { + const account = await wallet.autoConnect({ + client, + chain: defineChain(lastChainId || 1), + }); + return { + accounts: [getAddress(account.address)], + chainId: lastChainId || 1, + }; + } + const inAppOptions = params && "strategy" in params ? params : undefined; + if (!inAppOptions) { + throw new Error( + "Missing strategy prop, pass it to connect() when connecting to this connector", + ); + } + const chain = defineChain(inAppOptions?.chainId || lastChainId || 1); + const decoratedOptions = { + ...inAppOptions, + client, + chain, + } as InAppWalletConnectionOptions; + const account = await wallet.connect(decoratedOptions); + await config.storage?.setItem("tw.lastChainId", chain.id); + return { accounts: [getAddress(account.address)], chainId: chain.id }; + }, + disconnect: async () => { + await wallet.disconnect(); + }, + getAccounts: async () => { + const account = wallet.getAccount(); + if (!account) { + throw new Error("Wallet not connected"); + } + return [getAddress(account.address)]; + }, + getChainId: async () => { + return wallet.getChain()?.id || 1; + }, + getProvider: async (params) => { + const lastChainId = await config.storage?.getItem("tw.lastChainId"); + const chain = defineChain(params?.chainId || lastChainId || 1); + if (!wallet.getAccount()) { + await wallet.autoConnect({ + client, + chain, + }); + } + return EIP1193.toProvider({ + wallet, + client, + chain: wallet.getChain() || chain, + }); + }, + isAuthorized: async () => true, // always try to reconnect + switchChain: async (params) => { + const chain = config.chains.find((x) => x.id === params.chainId); + if (!chain) { + throw new Error(`Chain ${params.chainId} not supported`); + } + await wallet.switchChain(defineChain(chain.id)); + return chain; + }, + onAccountsChanged: () => { + // no-op + }, + onChainChanged: () => { + // no-op + }, + onDisconnect: () => { + // no-op + }, + })); +} diff --git a/packages/wagmi-adapter/src/exports/thirdweb.ts b/packages/wagmi-adapter/src/exports/thirdweb.ts new file mode 100644 index 00000000000..060e4570006 --- /dev/null +++ b/packages/wagmi-adapter/src/exports/thirdweb.ts @@ -0,0 +1,4 @@ +export { + inAppWalletConnector, + type InAppWalletParameters, +} from "../connector.js"; diff --git a/packages/wagmi-adapter/tsconfig.base.json b/packages/wagmi-adapter/tsconfig.base.json new file mode 100644 index 00000000000..2b519cac7ea --- /dev/null +++ b/packages/wagmi-adapter/tsconfig.base.json @@ -0,0 +1,47 @@ +{ + // This tsconfig file contains the shared config for the build (tsconfig.build.json) and type checking (tsconfig.json) config. + "include": [], + "compilerOptions": { + // Incremental builds + // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. + "incremental": false, + + // Type checking + "strict": true, + "useDefineForClassFields": true, // Not enabled by default in `strict` mode unless we bump `target` to ES2022. + "noFallthroughCasesInSwitch": true, // Not enabled by default in `strict` mode. + "noImplicitReturns": true, // Not enabled by default in `strict` mode. + "useUnknownInCatchVariables": true, // TODO: This would normally be enabled in `strict` mode but would require some adjustments to the codebase. + "noImplicitOverride": true, // Not enabled by default in `strict` mode. + "noUnusedLocals": true, // Not enabled by default in `strict` mode. + "noUnusedParameters": true, // Not enabled by default in `strict` mode. + "exactOptionalPropertyTypes": false, // Not enabled by default in `strict` mode. + "noUncheckedIndexedAccess": true, // Not enabled by default in `strict` mode. + + // JavaScript support + "allowJs": false, + "checkJs": false, + + // Interop constraints + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "verbatimModuleSyntax": true, + "importHelpers": true, // This is only used for build validation. Since we do not have `tslib` installed, this will fail if we accidentally make use of anything that'd require injection of helpers. + + // Language and environment + "moduleResolution": "NodeNext", + "module": "NodeNext", + "target": "ES2021", // Setting this to `ES2021` enables native support for `Node v16+`: https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping. + "lib": [ + "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. + "DOM" // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + ], + + // Skip type checking for node modules + "skipLibCheck": true, + + // jsx for "/react" portion + "jsx": "react-jsx" + } +} diff --git a/packages/wagmi-adapter/tsconfig.build.json b/packages/wagmi-adapter/tsconfig.build.json new file mode 100644 index 00000000000..3ae3943df87 --- /dev/null +++ b/packages/wagmi-adapter/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src"], + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/*.test-d.ts", + "src/**/*.bench.ts", + "src/**/*.macro.ts" + ], + "compilerOptions": { + "moduleResolution": "node", + "sourceMap": true, + "rootDir": "./src" + } +} diff --git a/packages/wagmi-adapter/tsconfig.json b/packages/wagmi-adapter/tsconfig.json new file mode 100644 index 00000000000..f8b525d0c97 --- /dev/null +++ b/packages/wagmi-adapter/tsconfig.json @@ -0,0 +1,13 @@ +{ + // This configuration is used for local development and type checking. + "extends": "./tsconfig.base.json", + "include": ["src", "test"], + "exclude": [], + // "references": [{ "path": "./scripts/tsconfig.json" }], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~test/*": ["./test/src/*"] + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4127b50c599..ddf883e764b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1122,6 +1122,22 @@ importers: specifier: 2.1.8 version: 2.1.8(@types/node@22.10.2)(@vitest/ui@2.1.8)(happy-dom@15.11.7)(lightningcss@1.28.2)(msw@2.6.8(@types/node@22.10.2)(typescript@5.7.2))(terser@5.37.0) + packages/wagmi-adapter: + dependencies: + typescript: + specifier: '>=5.0.4' + version: 5.7.2 + devDependencies: + '@wagmi/core': + specifier: 2.16.0 + version: 2.16.0(@tanstack/query-core@5.62.7)(@types/react@19.0.1)(react@19.0.0)(typescript@5.7.2)(use-sync-external-store@1.2.2(react@19.0.0))(viem@2.21.54(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)) + rimraf: + specifier: 6.0.1 + version: 6.0.1 + thirdweb: + specifier: workspace:* + version: link:../thirdweb + packages: '@0no-co/graphql.web@1.0.12': @@ -4025,7 +4041,7 @@ packages: '@radix-ui/react-compose-refs@1.1.0': resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -4043,7 +4059,7 @@ packages: '@radix-ui/react-context@1.1.1': resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -4074,8 +4090,8 @@ packages: '@radix-ui/react-dismissable-layer@1.1.1': resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -4100,7 +4116,7 @@ packages: '@radix-ui/react-focus-guards@1.1.1': resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -4188,8 +4204,8 @@ packages: '@radix-ui/react-popper@1.2.0': resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -4201,8 +4217,8 @@ packages: '@radix-ui/react-portal@1.1.2': resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -4214,8 +4230,8 @@ packages: '@radix-ui/react-presence@1.1.1': resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -4375,7 +4391,7 @@ packages: '@radix-ui/react-use-controllable-state@1.1.0': resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -4420,7 +4436,7 @@ packages: '@radix-ui/react-use-size@1.1.0': resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': @@ -4429,8 +4445,8 @@ packages: '@radix-ui/react-visually-hidden@1.1.0': resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 + '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -6019,6 +6035,18 @@ packages: '@vitest/utils@2.1.8': resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + '@wagmi/core@2.16.0': + resolution: {integrity: sha512-sy4n7Jv6YCbT2jp4zQ/9H6l0A8StsN7P8mm2BRuODgW2w6Fj4j6h2xgYJD2tIjJHkLU/nvPJ7audZ55X7XQU/g==} + peerDependencies: + '@tanstack/query-core': '>=5.0.0' + typescript: '>=5.0.4' + viem: 2.x + peerDependenciesMeta: + '@tanstack/query-core': + optional: true + typescript: + optional: true + '@walletconnect/core@2.17.2': resolution: {integrity: sha512-O9VUsFg78CbvIaxfQuZMsHcJ4a2Z16DRz/O4S+uOAcGKhH/i/ln8hp864Tb+xRvifWSzaZ6CeAVxk657F+pscA==} engines: {node: '>=18'} @@ -14090,6 +14118,24 @@ packages: zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + zustand@5.0.0: + resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -21244,6 +21290,21 @@ snapshots: loupe: 3.1.2 tinyrainbow: 1.2.0 + '@wagmi/core@2.16.0(@tanstack/query-core@5.62.7)(@types/react@19.0.1)(react@19.0.0)(typescript@5.7.2)(use-sync-external-store@1.2.2(react@19.0.0))(viem@2.21.54(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.7.2) + viem: 2.21.54(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + zustand: 5.0.0(@types/react@19.0.1)(react@19.0.0)(use-sync-external-store@1.2.2(react@19.0.0)) + optionalDependencies: + '@tanstack/query-core': 5.62.7 + typescript: 5.7.2 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@walletconnect/core@2.17.2(@react-native-async-storage/async-storage@2.1.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@16.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@19.0.1)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ioredis@5.4.1)(utf-8-validate@5.0.10)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -23644,8 +23705,8 @@ snapshots: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-react: 7.37.2(eslint@8.57.0) eslint-plugin-react-hooks: 5.1.0(eslint@8.57.0) @@ -23664,7 +23725,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) @@ -23676,7 +23737,7 @@ snapshots: is-glob: 4.0.3 stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -23701,18 +23762,18 @@ snapshots: - bluebird - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -23723,7 +23784,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -31429,4 +31490,10 @@ snapshots: zod@3.24.1: {} + zustand@5.0.0(@types/react@19.0.1)(react@19.0.0)(use-sync-external-store@1.2.2(react@19.0.0)): + optionalDependencies: + '@types/react': 19.0.1 + react: 19.0.0 + use-sync-external-store: 1.2.2(react@19.0.0) + zwitch@2.0.4: {}