diff --git a/.gitignore b/.gitignore
index 1834fe72ab..dde82b8cb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,10 @@ tsconfig.tsbuildinfo
.env.production.local
.envrc
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
+
# proxy packages
packages/cli/config
packages/cli/plugins
@@ -37,3 +41,6 @@ packages/vue/chains
packages/vue/connectors
packages/vue/nuxt
packages/vue/query
+packages/svelte/.svelte-kit
+packages/svelte/.output
+
diff --git a/biome.json b/biome.json
index ce99662cb0..3d3bacce99 100644
--- a/biome.json
+++ b/biome.json
@@ -11,7 +11,12 @@
"lineWidth": 80
},
"linter": {
- "ignore": ["packages/create-wagmi/templates/*"],
+ "ignore": [
+ "packages/create-wagmi/templates/*",
+ "packages/svelte/**/*.svelte",
+ "playgrounds/sveltekit/.svelte-kit/**",
+ "playgrounds/sveltekit/**/*.svelte"
+ ],
"enabled": true,
"rules": {
"recommended": true,
diff --git a/package.json b/package.json
index 23205a136c..9ec30c872a 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"dev:nuxt": "pnpm --filter nuxt-app dev",
"dev:react": "pnpm --filter vite-react dev",
"dev:vue": "pnpm --filter vite-vue dev",
+ "dev:svelte": "pnpm --filter sveltekit dev",
"docs:dev": "pnpm --filter site dev",
"format": "biome format --write",
"postinstall": "pnpm preconstruct",
@@ -37,6 +38,7 @@
"test:update": "vitest --update",
"test:ui": "vitest --ui",
"test:vue": "vitest --project @wagmi/vue",
+ "test:svelte": "vitest --project @wagmi/svelte",
"version:update": "bun scripts/updateVersion.ts",
"version:update:viem": "bun scripts/updateViemVersion.ts"
},
diff --git a/packages/svelte/.prettierignore b/packages/svelte/.prettierignore
new file mode 100644
index 0000000000..ab78a95ddd
--- /dev/null
+++ b/packages/svelte/.prettierignore
@@ -0,0 +1,4 @@
+# Package Managers
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
diff --git a/packages/svelte/.prettierrc b/packages/svelte/.prettierrc
new file mode 100644
index 0000000000..3f7802c372
--- /dev/null
+++ b/packages/svelte/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "useTabs": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "plugins": ["prettier-plugin-svelte"],
+ "overrides": [
+ {
+ "files": "*.svelte",
+ "options": {
+ "parser": "svelte"
+ }
+ }
+ ]
+}
diff --git a/packages/svelte/README.md b/packages/svelte/README.md
new file mode 100644
index 0000000000..89f30467b8
--- /dev/null
+++ b/packages/svelte/README.md
@@ -0,0 +1,13 @@
+# @wagmi/vue
+
+Svelte Runes for Ethereum
+
+## Installation
+
+```bash
+pnpm add @wagmi/svelte viem https://pkg.pr.new/@tanstack/svelte-query@ccce0b8
+```
+
+## Documentation
+
+For documentation and guides, visit [wagmi.sh](https://wagmi.sh).
diff --git a/packages/svelte/eslint.config.js b/packages/svelte/eslint.config.js
new file mode 100644
index 0000000000..ae06ec3043
--- /dev/null
+++ b/packages/svelte/eslint.config.js
@@ -0,0 +1,33 @@
+import js from '@eslint/js'
+import prettier from 'eslint-config-prettier'
+import svelte from 'eslint-plugin-svelte'
+import globals from 'globals'
+import ts from 'typescript-eslint'
+
+export default ts.config(
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs['flat/recommended'],
+ prettier,
+ ...svelte.configs['flat/prettier'],
+ {
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node,
+ },
+ },
+ },
+ {
+ files: ['**/*.svelte'],
+
+ languageOptions: {
+ parserOptions: {
+ parser: ts.parser,
+ },
+ },
+ },
+ {
+ ignores: ['build/', '.svelte-kit/', 'dist/'],
+ },
+)
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
new file mode 100644
index 0000000000..b77e6497db
--- /dev/null
+++ b/packages/svelte/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@wagmi/svelte",
+ "version": "0.0.1",
+ "scripts": {
+ "build": "vite build && npm run package",
+ "preview": "vite preview",
+ "package": "svelte-kit sync && svelte-package && publint",
+ "prepublishOnly": "npm run package",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
+ },
+ "files": ["dist", "!dist/**/*.test.*", "!dist/**/*.spec.*"],
+ "sideEffects": ["**/*.css"],
+ "svelte": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "type": "module",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "svelte": "./dist/index.js"
+ },
+ "./chains": {
+ "types": "./dist/exports/chains.d.ts",
+ "default": "./dist/exports/chains.js"
+ }
+ },
+ "peerDependencies": {
+ "@tanstack/svelte-query": "https://pkg.pr.new/@tanstack/svelte-query@ccce0b8",
+ "viem": "2.x",
+ "svelte": "^5.0.0"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.0.0",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/package": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
+ "@tanstack/svelte-query": "https://pkg.pr.new/@tanstack/svelte-query@ccce0b8",
+ "@wagmi/test": "workspace:*",
+ "globals": "^15.0.0",
+ "publint": "^0.2.0",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "typescript": "^5.0.0",
+ "vite": "^5.0.11",
+ "vitest": "^2.0.4"
+ },
+ "dependencies": {
+ "@wagmi/connectors": "workspace:*",
+ "@wagmi/core": "workspace:*"
+ }
+}
diff --git a/packages/svelte/src/WagmiProvider.svelte b/packages/svelte/src/WagmiProvider.svelte
new file mode 100644
index 0000000000..9833ff4705
--- /dev/null
+++ b/packages/svelte/src/WagmiProvider.svelte
@@ -0,0 +1,43 @@
+
+
+{@render children()}
diff --git a/packages/svelte/src/app.d.ts b/packages/svelte/src/app.d.ts
new file mode 100644
index 0000000000..7ebc6f0435
--- /dev/null
+++ b/packages/svelte/src/app.d.ts
@@ -0,0 +1,15 @@
+// See https://svelte.dev/docs/kit/types#app
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+
+ const __VERSION__: string
+}
+
+export {}
diff --git a/packages/svelte/src/app.html b/packages/svelte/src/app.html
new file mode 100644
index 0000000000..f22aeaad5e
--- /dev/null
+++ b/packages/svelte/src/app.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/packages/svelte/src/context.ts b/packages/svelte/src/context.ts
new file mode 100644
index 0000000000..37edb84c22
--- /dev/null
+++ b/packages/svelte/src/context.ts
@@ -0,0 +1,15 @@
+import type { ResolvedRegister } from '@wagmi/core'
+import { getContext, setContext } from 'svelte'
+
+type ContextConfig = ResolvedRegister['config']
+const WAGMI_CONFIG_KEY = Symbol('WAGMI_CONFIG')
+
+export const getWagmiConfig = (): ContextConfig => {
+ const client = getContext(WAGMI_CONFIG_KEY)
+
+ return client
+}
+
+export const setWagmiConfig = (config: ContextConfig) => {
+ setContext(WAGMI_CONFIG_KEY, config)
+}
diff --git a/packages/svelte/src/errors.test.ts b/packages/svelte/src/errors.test.ts
new file mode 100644
index 0000000000..7a9fea3135
--- /dev/null
+++ b/packages/svelte/src/errors.test.ts
@@ -0,0 +1,164 @@
+import { expect, test } from 'vitest'
+
+import { BaseError, WagmiProviderNotFoundError } from './errors.js'
+
+test('BaseError', () => {
+ expect(new BaseError('An error occurred.')).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Version: @wagmi/svelte@x.y.z]
+ `)
+
+ expect(
+ new BaseError('An error occurred.', { details: 'details' }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+
+ expect(new BaseError('', { details: 'details' })).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('BaseError (w/ docsPath)', () => {
+ expect(
+ new BaseError('An error occurred.', {
+ details: 'details',
+ docsPath: '/lol',
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Docs: https://wagmi.sh/react/lol.html
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+ expect(
+ new BaseError('An error occurred.', {
+ cause: new BaseError('error', { docsPath: '/docs' }),
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Docs: https://wagmi.sh/react/docs.html
+ Version: @wagmi/svelte@x.y.z]
+ `)
+ expect(
+ new BaseError('An error occurred.', {
+ cause: new BaseError('error'),
+ docsPath: '/lol',
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Docs: https://wagmi.sh/react/lol.html
+ Version: @wagmi/svelte@x.y.z]
+ `)
+ expect(
+ new BaseError('An error occurred.', {
+ details: 'details',
+ docsPath: '/lol',
+ docsSlug: 'test',
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Docs: https://wagmi.sh/react/lol.html#test
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('BaseError (w/ metaMessages)', () => {
+ expect(
+ new BaseError('An error occurred.', {
+ details: 'details',
+ metaMessages: ['Reason: idk', 'Cause: lol'],
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An error occurred.
+
+ Reason: idk
+ Cause: lol
+
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('inherited BaseError', () => {
+ const err = new BaseError('An error occurred.', {
+ details: 'details',
+ docsPath: '/lol',
+ })
+ expect(
+ new BaseError('An internal error occurred.', {
+ cause: err,
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An internal error occurred.
+
+ Docs: https://wagmi.sh/react/lol.html
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('inherited Error', () => {
+ const err = new Error('details')
+ expect(
+ new BaseError('An internal error occurred.', {
+ cause: err,
+ docsPath: '/lol',
+ }),
+ ).toMatchInlineSnapshot(`
+ [WagmiError: An internal error occurred.
+
+ Docs: https://wagmi.sh/react/lol.html
+ Details: details
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('walk: no predicate fn (walks to leaf)', () => {
+ class FooError extends BaseError {}
+ class BarError extends BaseError {}
+
+ const err = new BaseError('test1', {
+ cause: new FooError('test2', { cause: new BarError('test3') }),
+ })
+ expect(err.walk()).toMatchInlineSnapshot(`
+ [WagmiError: test3
+
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('walk: predicate fn', () => {
+ class FooError extends BaseError {}
+ class BarError extends BaseError {}
+
+ const err = new BaseError('test1', {
+ cause: new FooError('test2', { cause: new BarError('test3') }),
+ })
+ expect(err.walk((err) => err instanceof FooError)).toMatchInlineSnapshot(`
+ [WagmiError: test2
+
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
+
+test('WagmiProviderNotFoundError', () => {
+ expect(new WagmiProviderNotFoundError()).toMatchInlineSnapshot(`
+ [WagmiProviderNotFoundError: \`useConfig\` must be used within \`WagmiProvider\`.
+
+ Docs: https://wagmi.sh/react/api/WagmiProvider.html
+ Version: @wagmi/svelte@x.y.z]
+ `)
+})
diff --git a/packages/svelte/src/errors.ts b/packages/svelte/src/errors.ts
new file mode 100644
index 0000000000..91ec8e8722
--- /dev/null
+++ b/packages/svelte/src/errors.ts
@@ -0,0 +1,27 @@
+import { BaseError as CoreError } from '@wagmi/core'
+
+import { getVersion } from './version.js'
+
+export type BaseErrorType = BaseError & { name: 'WagmiError' }
+
+export class BaseError extends CoreError {
+ override name = 'WagmiError'
+ override get docsBaseUrl() {
+ return 'https://wagmi.sh/react'
+ }
+ override get version() {
+ return getVersion()
+ }
+}
+
+export type WagmiProviderNotFoundErrorType = WagmiProviderNotFoundError & {
+ name: 'WagmiProviderNotFoundError'
+}
+export class WagmiProviderNotFoundError extends BaseError {
+ override name = 'WagmiProviderNotFoundError'
+ constructor() {
+ super('`useConfig` must be used within `WagmiProvider`.', {
+ docsPath: '/api/WagmiProvider',
+ })
+ }
+}
diff --git a/packages/svelte/src/exports/chains.ts b/packages/svelte/src/exports/chains.ts
new file mode 100644
index 0000000000..dfe5ccc8c0
--- /dev/null
+++ b/packages/svelte/src/exports/chains.ts
@@ -0,0 +1,3 @@
+// biome-ignore lint/performance/noBarrelFile: entrypoint module
+// biome-ignore lint/performance/noReExportAll: entrypoint module
+export * from 'viem/chains'
diff --git a/packages/svelte/src/exports/index.ts b/packages/svelte/src/exports/index.ts
new file mode 100644
index 0000000000..be80b3e1bc
--- /dev/null
+++ b/packages/svelte/src/exports/index.ts
@@ -0,0 +1,219 @@
+////////////////////////////////////////////////////////////////////////////////
+// Errors
+////////////////////////////////////////////////////////////////////////////////
+
+// biome-ignore lint/performance/noBarrelFile: entrypoint module
+export {
+ type BaseErrorType,
+ BaseError,
+ type WagmiProviderNotFoundErrorType,
+ WagmiProviderNotFoundError,
+} from '../errors.js'
+
+////////////////////////////////////////////////////////////////////////////////
+// Hooks
+////////////////////////////////////////////////////////////////////////////////
+
+export { default as WagmiProvider } from '../WagmiProvider.svelte'
+
+export {
+ type UseAccountParameters,
+ type UseAccountReturnType,
+ useAccount,
+} from '../hooks/useAccount.svelte.js'
+
+export {
+ type UseAccountEffectParameters,
+ useAccountEffect,
+} from '../hooks/useAccountEffect.svelte.js'
+
+export {
+ type UseBalanceParameters,
+ type UseBalanceReturnType,
+ useBalance,
+} from '../hooks/useBalance.svelte.js'
+
+export {
+ type UseBlockNumberParameters,
+ type UseBlockNumberReturnType,
+ useBlockNumber,
+} from '../hooks/useBlockNumber.svelte.js'
+
+export {
+ type UseChainIdParameters,
+ type UseChainIdReturnType,
+ useChainId,
+} from '../hooks/useChainId.svelte.js'
+
+export {
+ type UseChainsParameters,
+ type UseChainsReturnType,
+ useChains,
+} from '../hooks/useChains.svelte.js'
+
+export {
+ type UseConfigParameters,
+ type UseConfigReturnType,
+ useConfig,
+} from '../hooks/useConfig.svelte.js'
+
+export {
+ type UseConnectParameters,
+ type UseConnectReturnType,
+ useConnect,
+} from '../hooks/useConnect.svelte.js'
+
+export {
+ type UseConnectionsParameters,
+ type UseConnectionsReturnType,
+ useConnections,
+} from '../hooks/useConnections.svelte.js'
+
+export {
+ type UseConnectorsParameters,
+ type UseConnectorsReturnType,
+ useConnectors,
+} from '../hooks/useConnectors.svelte.js'
+
+export {
+ type UseDisconnectParameters,
+ type UseDisconnectReturnType,
+ useDisconnect,
+} from '../hooks/useDisconnect.svelte.js'
+
+export {
+ type UseEnsAvatarParameters,
+ type UseEnsAvatarReturnType,
+ useEnsAvatar,
+} from '../hooks/useEnsAvatar.svelte.js'
+
+export {
+ type UseEnsNameParameters,
+ type UseEnsNameReturnType,
+ useEnsName,
+} from '../hooks/useEnsName.svelte.js'
+
+export {
+ type UseGasPriceParameters,
+ type UseGasPriceReturnType,
+ useGasPrice,
+} from '../hooks/useGasPrice.svelte.js'
+
+export {
+ type UseReadContractParameters,
+ type UseReadContractReturnType,
+ useReadContract,
+ /** @deprecated Use `useWriteContract` instead */
+ useReadContract as useContractRead,
+} from '../hooks/useReadContract.svelte.js'
+
+export {
+ type UseReadContractsParameters,
+ type UseReadContractsReturnType,
+ useReadContracts,
+ /** @deprecated Use `useWriteContract` instead */
+ useReadContracts as useContractReads,
+} from '../hooks/useReadContracts.svelte.js'
+
+export {
+ type UseSendTransactionParameters,
+ type UseSendTransactionReturnType,
+ useSendTransaction,
+} from '../hooks/useSendTransaction.svelte.js'
+
+export {
+ type UseSignMessageParameters,
+ type UseSignMessageReturnType,
+ useSignMessage,
+} from '../hooks/useSignMessage.svelte.js'
+
+export {
+ type UseSwitchAccountParameters,
+ type UseSwitchAccountReturnType,
+ useSwitchAccount,
+} from '../hooks/useSwitchAccount.svelte.js'
+
+export {
+ type UseSwitchChainParameters,
+ type UseSwitchChainReturnType,
+ useSwitchChain,
+} from '../hooks/useSwitchChain.svelte.js'
+
+export {
+ type UseWaitForTransactionReceiptParameters,
+ type UseWaitForTransactionReceiptReturnType,
+ useWaitForTransactionReceipt,
+} from '../hooks/useWaitForTransactionReceipt.svelte.js'
+
+export {
+ type UseWatchBlockNumberParameters,
+ type UseWatchBlockNumberReturnType,
+ useWatchBlockNumber,
+} from '../hooks/useWatchBlockNumber.svelte.js'
+
+export {
+ type UseWriteContractParameters,
+ type UseWriteContractReturnType,
+ useWriteContract,
+ /** @deprecated Use `useWriteContract` instead */
+ useWriteContract as useContractWrite,
+} from '../hooks/useWriteContract.svelte.js'
+
+////////////////////////////////////////////////////////////////////////////////
+// @wagmi/core
+////////////////////////////////////////////////////////////////////////////////
+
+export {
+ // Config
+ type Connection,
+ type Connector,
+ type Config,
+ type CreateConfigParameters,
+ type PartializedState,
+ type State,
+ createConfig,
+ // Connector
+ type ConnectorEventMap,
+ type CreateConnectorFn,
+ createConnector,
+ // Errors
+ type ChainNotConfiguredErrorType,
+ ChainNotConfiguredError,
+ type ConnectorAlreadyConnectedErrorType,
+ ConnectorAlreadyConnectedError,
+ type ConnectorNotFoundErrorType,
+ ConnectorNotFoundError,
+ type ConnectorAccountNotFoundErrorType,
+ ConnectorAccountNotFoundError,
+ type ConnectorChainMismatchErrorType,
+ ConnectorChainMismatchError,
+ type ConnectorUnavailableReconnectingErrorType,
+ ConnectorUnavailableReconnectingError,
+ type ProviderNotFoundErrorType,
+ ProviderNotFoundError,
+ type SwitchChainNotSupportedErrorType,
+ SwitchChainNotSupportedError,
+ // Storage
+ type CreateStorageParameters,
+ type Storage,
+ createStorage,
+ noopStorage,
+ // Transports
+ custom,
+ fallback,
+ http,
+ webSocket,
+ unstable_connector,
+ type Transport,
+ // Types
+ type Register,
+ type ResolvedRegister,
+ // Utilities
+ cookieStorage,
+ cookieToInitialState,
+ deepEqual,
+ deserialize,
+ normalizeChainId,
+ parseCookie,
+ serialize,
+} from '@wagmi/core'
diff --git a/packages/svelte/src/hooks/useAccount.svelte.test.ts b/packages/svelte/src/hooks/useAccount.svelte.test.ts
new file mode 100644
index 0000000000..eb8a6599fa
--- /dev/null
+++ b/packages/svelte/src/hooks/useAccount.svelte.test.ts
@@ -0,0 +1,33 @@
+import { connect, disconnect } from '@wagmi/core'
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useAccount } from './useAccount.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(useAccount())
+
+ expect(result.address).not.toBeDefined()
+ expect(result.status).toEqual('disconnected')
+
+ await connect(config, { connector: config.connectors[0]! })
+
+ await expect.poll(() => result.address).toBeDefined()
+ await expect.poll(() => result.status).toEqual('connected')
+
+ await disconnect(config)
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const result = $derived.by(() => useAccount(() => ({ config })))
+ expect(result).toBeDefined()
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useAccount.svelte.ts b/packages/svelte/src/hooks/useAccount.svelte.ts
new file mode 100644
index 0000000000..9198473b76
--- /dev/null
+++ b/packages/svelte/src/hooks/useAccount.svelte.ts
@@ -0,0 +1,40 @@
+import {
+ type Config,
+ type GetAccountReturnType,
+ type ResolvedRegister,
+ getAccount,
+ watchAccount,
+} from '@wagmi/core'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseAccountParameters =
+ RuneParameters>
+
+export type UseAccountReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useAccount */
+export function useAccount(
+ parameters: UseAccountParameters = () => ({}),
+): UseAccountReturnType {
+ const config = $derived.by(useConfig(parameters))
+
+ let account = $state(getAccount(config))
+
+ $effect(() => {
+ account = getAccount(config)
+
+ return watchAccount(config, {
+ onChange(newAccount) {
+ account = newAccount
+ },
+ })
+ })
+
+ return () => account
+}
diff --git a/packages/svelte/src/hooks/useAccountEffect.svelte.test.ts b/packages/svelte/src/hooks/useAccountEffect.svelte.test.ts
new file mode 100644
index 0000000000..b11b554585
--- /dev/null
+++ b/packages/svelte/src/hooks/useAccountEffect.svelte.test.ts
@@ -0,0 +1,92 @@
+import { mock } from '@wagmi/connectors'
+import {
+ http,
+ connect,
+ createConfig,
+ disconnect,
+ getAccount,
+ reconnect,
+} from '@wagmi/core'
+import { accounts, chain, config, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test, vi } from 'vitest'
+import { useAccountEffect } from './useAccountEffect.svelte'
+import { useConnect } from './useConnect.svelte'
+import { useDisconnect } from './useDisconnect.svelte'
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const result = useAccountEffect(() => ({ config }))
+ expect(result).toBeUndefined()
+ },
+ { shouldMockConfig: false },
+ ),
+)
+
+test(
+ 'behavior: connect and disconnect called once',
+ testHook(async () => {
+ const onConnect = vi.fn()
+ const onDisconnect = vi.fn()
+
+ const connectHook = $derived.by(useConnect())
+ const disconnectHook = $derived.by(useDisconnect())
+
+ useAccountEffect(() => ({ onConnect, onDisconnect }))
+
+ connectHook.connect({ connector: connectHook.connectors[0]! })
+ await expect.poll(() => connectHook.data?.accounts).toBeTruthy()
+
+ connectHook.connect({ connector: connectHook.connectors[0]! })
+ await expect.poll(() => connectHook.isSuccess).toBeTruthy()
+
+ await wait(1000) // TODO: why is this needed?
+
+ disconnectHook.disconnect()
+ await expect.poll(() => disconnectHook.isSuccess).toBeTruthy()
+
+ disconnectHook.disconnect()
+ await expect.poll(() => disconnectHook.isSuccess).toBeTruthy()
+
+ expect(onConnect).toBeCalledTimes(1)
+ expect(onDisconnect).toBeCalledTimes(1)
+ }),
+)
+
+const mockConnector = mock({
+ accounts,
+ features: { reconnect: true },
+})
+const newConfig = createConfig({
+ chains: [chain.mainnet],
+ connectors: [mockConnector],
+ transports: { [chain.mainnet.id]: http() },
+})
+
+test(
+ 'behavior: connect called on reconnect',
+ testHook(
+ async () => {
+ const onConnect = vi.fn((data) => {
+ expect(data.isReconnected).toBeTruthy()
+ })
+
+ useAccountEffect(() => ({ onConnect }))
+
+ await reconnect(newConfig)
+
+ await connect(newConfig, { connector: mockConnector })
+
+ await expect.poll(() => onConnect).toHaveBeenCalledOnce()
+ },
+ { mockConfigOverride: newConfig, reconnectOnMount: true },
+ async () => {
+ await connect(newConfig, { connector: mockConnector })
+ },
+ async () => {
+ await disconnect(newConfig)
+ },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useAccountEffect.svelte.ts b/packages/svelte/src/hooks/useAccountEffect.svelte.ts
new file mode 100644
index 0000000000..623829ced2
--- /dev/null
+++ b/packages/svelte/src/hooks/useAccountEffect.svelte.ts
@@ -0,0 +1,63 @@
+import { type GetAccountReturnType, watchAccount } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import type { RuneParameters } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseAccountEffectParameters = RuneParameters<
+ Compute<
+ {
+ onConnect?(
+ data: Compute<
+ Pick<
+ Extract,
+ 'address' | 'addresses' | 'chain' | 'chainId' | 'connector'
+ > & {
+ isReconnected: boolean
+ }
+ >,
+ ): void
+ onDisconnect?(): void
+ } & ConfigParameter
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useAccountEffect */
+export function useAccountEffect(
+ parameters: UseAccountEffectParameters = () => ({}),
+) {
+ const { onConnect, onDisconnect } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+
+ $effect(() => {
+ return watchAccount(config, {
+ onChange(data, prevData) {
+ if (
+ (prevData.status === 'reconnecting' ||
+ (prevData.status === 'connecting' &&
+ prevData.address === undefined)) &&
+ data.status === 'connected'
+ ) {
+ const { address, addresses, chain, chainId, connector } = data
+ const isReconnected =
+ prevData.status === 'reconnecting' ||
+ // if `previousAccount.status` is `undefined`, the connector connected immediately.
+ prevData.status === undefined
+ onConnect?.({
+ address,
+ addresses,
+ chain,
+ chainId,
+ connector,
+ isReconnected,
+ })
+ } else if (
+ prevData.status === 'connected' &&
+ data.status === 'disconnected'
+ )
+ onDisconnect?.()
+ },
+ })
+ })
+}
diff --git a/packages/svelte/src/hooks/useBalance.svelte.test.ts b/packages/svelte/src/hooks/useBalance.svelte.test.ts
new file mode 100644
index 0000000000..b9f4edd56a
--- /dev/null
+++ b/packages/svelte/src/hooks/useBalance.svelte.test.ts
@@ -0,0 +1,333 @@
+import { accounts, chain, testClient, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { flushSync } from 'svelte'
+import { type Address, parseEther } from 'viem'
+import { beforeEach, expect, test } from 'vitest'
+import { useBalance } from './useBalance.svelte.js'
+
+const address = accounts[0]
+
+beforeEach(async () => {
+ await testClient.mainnet.setBalance({ address, value: parseEther('10000') })
+ // await testClient.mainnet.mine({ blocks: 1 })
+ // await testClient.mainnet2.setBalance({ address, value: parseEther('69') })
+ // await testClient.mainnet2.mine({ blocks: 1 })
+})
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(useBalance(() => ({ address })))
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ const { data, ...rest } = result
+ expect(data).toMatchObject(
+ expect.objectContaining({
+ decimals: expect.any(Number),
+ formatted: expect.any(String),
+ symbol: expect.any(String),
+ value: expect.any(BigInt),
+ }),
+ )
+ expect(rest).toMatchInlineSnapshot(`
+ {
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "balance",
+ {
+ "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'parameters: chainId',
+ testHook(async () => {
+ const result = $derived.by(
+ useBalance(() => ({ address, chainId: chain.mainnet2.id })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": {
+ "decimals": 18,
+ "formatted": "10000",
+ "symbol": "WAG",
+ "value": 10000000000000000000000n,
+ },
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "balance",
+ {
+ "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "chainId": 456,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'parameters: token',
+ testHook(async () => {
+ const result = $derived.by(
+ useBalance(() => ({
+ address: '0x4557B18E779944BFE9d78A672452331C186a9f48',
+ token: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": {
+ "decimals": 18,
+ "formatted": "0.559062564299199392",
+ "symbol": "DAI",
+ "value": 559062564299199392n,
+ },
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "balance",
+ {
+ "address": "0x4557B18E779944BFE9d78A672452331C186a9f48",
+ "chainId": 1,
+ "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'parameters: unit',
+ testHook(async () => {
+ const result = $derived.by(
+ useBalance(() => ({
+ address,
+ chainId: chain.mainnet2.id,
+ unit: 'wei',
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": {
+ "decimals": 18,
+ "formatted": "10000000000000000000000",
+ "symbol": "WAG",
+ "value": 10000000000000000000000n,
+ },
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "balance",
+ {
+ "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "chainId": 456,
+ "unit": "wei",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'behavior: address: undefined -> defined',
+ testHook(async () => {
+ let address: Address | undefined = $state(undefined)
+ const result = $derived.by(useBalance(() => ({ address })))
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": undefined,
+ "dataUpdatedAt": 0,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": false,
+ "isFetchedAfterMount": false,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": true,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": false,
+ "isSuccess": false,
+ "queryKey": [
+ "balance",
+ {
+ "address": undefined,
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "pending",
+ }
+ `)
+
+ address = accounts[0]
+ flushSync()
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": {
+ "decimals": 18,
+ "formatted": "10000",
+ "symbol": "ETH",
+ "value": 10000000000000000000000n,
+ },
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "balance",
+ {
+ "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'behavior: disabled when properties missing',
+ testHook(async () => {
+ const result = $derived.by(useBalance())
+
+ await wait(100)
+ await expect.poll(() => result.isPending).toBeTruthy()
+ }),
+)
diff --git a/packages/svelte/src/hooks/useBalance.svelte.ts b/packages/svelte/src/hooks/useBalance.svelte.ts
new file mode 100644
index 0000000000..62131f7751
--- /dev/null
+++ b/packages/svelte/src/hooks/useBalance.svelte.ts
@@ -0,0 +1,62 @@
+import type { Config, GetBalanceErrorType, ResolvedRegister } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import type { GetBalanceQueryFnData } from '@wagmi/core/query'
+import {
+ type GetBalanceData,
+ type GetBalanceOptions,
+ type GetBalanceQueryKey,
+ getBalanceQueryOptions,
+} from '@wagmi/core/query'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ QueryParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseBalanceParameters<
+ config extends Config = Config,
+ selectData = GetBalanceData,
+> = RuneParameters<
+ Compute<
+ GetBalanceOptions &
+ ConfigParameter &
+ QueryParameter<
+ GetBalanceQueryFnData,
+ GetBalanceErrorType,
+ selectData,
+ GetBalanceQueryKey
+ >
+ >
+>
+
+export type UseBalanceReturnType = RuneReturnType<
+ CreateQueryReturnType
+>
+
+/** https://wagmi.sh/react/api/hooks/useBalance */
+export function useBalance<
+ config extends Config = ResolvedRegister['config'],
+ selectData = GetBalanceData,
+>(
+ parameters: UseBalanceParameters = () => ({}),
+): UseBalanceReturnType {
+ const { address, query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(parameters))
+
+ const options = $derived(
+ getBalanceQueryOptions(config, {
+ ...parameters(),
+ chainId: parameters().chainId ?? chainId,
+ }),
+ )
+ const enabled = $derived(Boolean(address && (query.enabled ?? true)))
+
+ return createQuery(() => ({ ...query, ...options, enabled }))
+}
diff --git a/packages/svelte/src/hooks/useBlockNumber.svelte.test.ts b/packages/svelte/src/hooks/useBlockNumber.svelte.test.ts
new file mode 100644
index 0000000000..9632fc5953
--- /dev/null
+++ b/packages/svelte/src/hooks/useBlockNumber.svelte.test.ts
@@ -0,0 +1,79 @@
+import { getBlockNumber } from '@wagmi/core'
+import { config, testClient, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { flushSync } from 'svelte'
+import { expect, test } from 'vitest'
+import { useBlockNumber } from './useBlockNumber.svelte.js'
+
+test(
+ 'mounts',
+ testHook(
+ async () => {
+ const result = $derived.by(useBlockNumber())
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 19258213n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "blockNumber",
+ {
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ },
+ {},
+ async () => {
+ await testClient.mainnet.resetFork()
+ },
+ ),
+)
+
+test(
+ 'parameters: watch',
+ testHook(
+ async () => {
+ const result = $derived.by(useBlockNumber(() => ({ watch: true })))
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+ const blockNumber = result.data!
+ expect(result.data).toMatchInlineSnapshot('19258213n')
+
+ await testClient.mainnet.mine({ blocks: 1 })
+ await expect.poll(() => result.data).toEqual(blockNumber + 1n)
+
+ await testClient.mainnet.mine({ blocks: 1 })
+ await expect.poll(() => result.data).toEqual(blockNumber + 2n)
+ },
+ {},
+ async () => {
+ await testClient.mainnet.resetFork()
+ },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useBlockNumber.svelte.ts b/packages/svelte/src/hooks/useBlockNumber.svelte.ts
new file mode 100644
index 0000000000..e4f9be5da0
--- /dev/null
+++ b/packages/svelte/src/hooks/useBlockNumber.svelte.ts
@@ -0,0 +1,108 @@
+import { useQueryClient } from '@tanstack/svelte-query'
+import type {
+ Config,
+ GetBlockNumberErrorType,
+ ResolvedRegister,
+} from '@wagmi/core'
+import type {
+ Compute,
+ UnionCompute,
+ UnionStrictOmit,
+} from '@wagmi/core/internal'
+import {
+ type GetBlockNumberData,
+ type GetBlockNumberOptions,
+ type GetBlockNumberQueryFnData,
+ type GetBlockNumberQueryKey,
+ getBlockNumberQueryOptions,
+} from '@wagmi/core/query'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ QueryParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+import {
+ type UseWatchBlockNumberParameters,
+ useWatchBlockNumber,
+} from './useWatchBlockNumber.svelte.js'
+
+export type UseBlockNumberParameters<
+ config extends Config = Config,
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = GetBlockNumberData,
+> = RuneParameters<
+ Compute<
+ GetBlockNumberOptions &
+ ConfigParameter &
+ QueryParameter<
+ GetBlockNumberQueryFnData,
+ GetBlockNumberErrorType,
+ selectData,
+ GetBlockNumberQueryKey
+ > & {
+ watch?:
+ | boolean
+ | UnionCompute<
+ UnionStrictOmit<
+ ReturnType>,
+ 'chainId' | 'config' | 'onBlockNumber' | 'onError'
+ >
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseBlockNumberReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useBlockNumber */
+export function useBlockNumber<
+ config extends Config = ResolvedRegister['config'],
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = GetBlockNumberData,
+>(
+ parameters: UseBlockNumberParameters<
+ config,
+ chainId,
+ selectData
+ > = () => ({}),
+): UseBlockNumberReturnType {
+ const { query = {}, watch } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const queryClient = useQueryClient()
+ const configChainId = $derived.by(useChainId(parameters))
+ const chainId = $derived(parameters().chainId ?? configChainId)
+
+ const options = $derived(
+ getBlockNumberQueryOptions(config, {
+ ...parameters(),
+ chainId,
+ }),
+ )
+
+ useWatchBlockNumber(() => ({
+ ...({
+ config: parameters().config,
+ chainId: parameters().chainId,
+ ...(typeof watch === 'object' ? watch : {}),
+ } as ReturnType),
+ enabled: Boolean(
+ (query.enabled ?? true) &&
+ (typeof watch === 'object' ? watch.enabled : watch),
+ ),
+ onBlockNumber(blockNumber) {
+ queryClient.setQueryData(options.queryKey, blockNumber)
+ },
+ }))
+
+ return createQuery(() => ({ ...query, ...options }))
+}
diff --git a/packages/svelte/src/hooks/useChainId.svelte.test.ts b/packages/svelte/src/hooks/useChainId.svelte.test.ts
new file mode 100644
index 0000000000..ce0b39a0c4
--- /dev/null
+++ b/packages/svelte/src/hooks/useChainId.svelte.test.ts
@@ -0,0 +1,30 @@
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { flushSync } from 'svelte'
+import { expect, test, vi } from 'vitest'
+import { useChainId } from './useChainId.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const chainId = $derived.by(useChainId())
+ expect(chainId).toMatchInlineSnapshot('1')
+
+ config.setState((x) => ({ ...x, chainId: 456 }))
+ const svelte = await import('svelte')
+ svelte.getContext = vi.fn().mockReturnValue(config) // TODO: why do i need to mock it again?
+ flushSync()
+ expect(chainId).toMatchInlineSnapshot('456')
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const chainId = $derived.by(useChainId(() => ({ config })))
+ expect(chainId).toBeDefined()
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useChainId.svelte.ts b/packages/svelte/src/hooks/useChainId.svelte.ts
new file mode 100644
index 0000000000..4f492a5210
--- /dev/null
+++ b/packages/svelte/src/hooks/useChainId.svelte.ts
@@ -0,0 +1,41 @@
+import {
+ type Config,
+ type GetChainIdReturnType,
+ type ResolvedRegister,
+ getChainId,
+ watchChainId,
+} from '@wagmi/core'
+
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseChainIdParameters =
+ RuneParameters>
+
+export type UseChainIdReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useChainId */
+export function useChainId(
+ parameters: UseChainIdParameters = () => ({}),
+): UseChainIdReturnType {
+ const config = $derived.by(useConfig(parameters))
+ let chainId = $state(getChainId(config))
+
+ $effect(() => {
+ chainId = getChainId(config)
+ const unsubscribe = watchChainId(config, {
+ onChange: (newChainId) => {
+ chainId = newChainId
+ },
+ })
+
+ return unsubscribe
+ })
+
+ return () => chainId
+}
diff --git a/packages/svelte/src/hooks/useChains.svelte.test.ts b/packages/svelte/src/hooks/useChains.svelte.test.ts
new file mode 100644
index 0000000000..c0bf1b3654
--- /dev/null
+++ b/packages/svelte/src/hooks/useChains.svelte.test.ts
@@ -0,0 +1,36 @@
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useChains } from './useChains.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(useChains())
+
+ expect(result.map((x) => x.id)).toMatchInlineSnapshot(`
+ [
+ 1,
+ 456,
+ 10,
+ ]
+ `)
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const result = $derived.by(useChains(() => ({ config })))
+ expect(result.map((x) => x.id)).toMatchInlineSnapshot(`
+ [
+ 1,
+ 456,
+ 10,
+ ]
+ `)
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useChains.svelte.ts b/packages/svelte/src/hooks/useChains.svelte.ts
new file mode 100644
index 0000000000..7da83dc375
--- /dev/null
+++ b/packages/svelte/src/hooks/useChains.svelte.ts
@@ -0,0 +1,41 @@
+import {
+ type Config,
+ type GetChainsReturnType,
+ type ResolvedRegister,
+ getChains,
+} from '@wagmi/core'
+import { watchChains } from '@wagmi/core/internal'
+
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseChainsParameters =
+ RuneParameters>
+
+export type UseChainsReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useChains */
+export function useChains(
+ parameters: UseChainsParameters = () => ({}),
+): UseChainsReturnType {
+ const config = $derived.by(useConfig(parameters))
+ let chains = $state(getChains(config))
+
+ $effect(() => {
+ chains = getChains(config)
+ const unsubscribe = watchChains(config, {
+ onChange: (newChains) => {
+ chains = newChains
+ },
+ })
+
+ return unsubscribe
+ })
+
+ return () => chains
+}
diff --git a/packages/svelte/src/hooks/useConfig.svelte.test.ts b/packages/svelte/src/hooks/useConfig.svelte.test.ts
new file mode 100644
index 0000000000..767dcb5c1e
--- /dev/null
+++ b/packages/svelte/src/hooks/useConfig.svelte.test.ts
@@ -0,0 +1,21 @@
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useConfig } from './useConfig.svelte.js'
+
+test(
+ 'mounts',
+ testHook(() => {
+ const config = useConfig()
+ expect(config).toBeDefined()
+ }),
+)
+
+test(
+ 'behavior: throws when not inside Provider',
+ testHook(
+ () => {
+ expect(() => useConfig()).toThrow()
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useConfig.svelte.ts b/packages/svelte/src/hooks/useConfig.svelte.ts
new file mode 100644
index 0000000000..998ae9baaf
--- /dev/null
+++ b/packages/svelte/src/hooks/useConfig.svelte.ts
@@ -0,0 +1,26 @@
+import type { Config, ResolvedRegister } from '@wagmi/core'
+
+import { getWagmiConfig } from '$lib/context.js'
+import { WagmiProviderNotFoundError } from '$lib/errors.js'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+
+export type UseConfigParameters =
+ RuneParameters>
+
+export type UseConfigReturnType =
+ RuneReturnType
+
+/** https://wagmi.sh/react/api/hooks/useConfig */
+export function useConfig(
+ parameters: UseConfigParameters = () => ({}),
+): UseConfigReturnType {
+ const contextConfig = getWagmiConfig()
+ const config = $derived(parameters().config ?? contextConfig)
+ if (!config) throw new WagmiProviderNotFoundError()
+
+ return (() => config) as UseConfigReturnType
+}
diff --git a/packages/svelte/src/hooks/useConnect.svelte.test.ts b/packages/svelte/src/hooks/useConnect.svelte.test.ts
new file mode 100644
index 0000000000..f66392db68
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnect.svelte.test.ts
@@ -0,0 +1,33 @@
+import { disconnect } from '@wagmi/core'
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { afterEach, expect, test } from 'vitest'
+import { useAccount } from './useAccount.svelte.js'
+import { useConnect } from './useConnect.svelte.js'
+
+const connector = config.connectors[0]!
+
+afterEach(async () => {
+ if (config.state.current === connector.uid)
+ await disconnect(config, { connector })
+})
+
+test(
+ 'default',
+ testHook(async () => {
+ const account = $derived.by(useAccount())
+ const connect = $derived.by(useConnect())
+
+ expect(account.address).not.toBeDefined()
+ expect(account.status).toEqual('disconnected')
+
+ connect.connect({
+ connector: connect.connectors[0]!,
+ })
+
+ await expect.poll(() => account.isConnected).toBeTruthy()
+
+ expect(account.address).toBeDefined()
+ expect(account.status).toEqual('connected')
+ }),
+)
diff --git a/packages/svelte/src/hooks/useConnect.svelte.ts b/packages/svelte/src/hooks/useConnect.svelte.ts
new file mode 100644
index 0000000000..bfbcae3f78
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnect.svelte.ts
@@ -0,0 +1,108 @@
+import {
+ type CreateMutationResult,
+ createMutation,
+} from '@tanstack/svelte-query'
+import type { Config, ConnectErrorType, ResolvedRegister } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type ConnectData,
+ type ConnectMutate,
+ type ConnectMutateAsync,
+ type ConnectVariables,
+ connectMutationOptions,
+} from '@wagmi/core/query'
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+import {
+ type UseConnectorsReturnType,
+ useConnectors,
+} from './useConnectors.svelte.js'
+
+export type UseConnectParameters<
+ config extends Config = Config,
+ context = unknown,
+> = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ ConnectData,
+ ConnectErrorType,
+ ConnectVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseConnectReturnType<
+ config extends Config = Config,
+ context = unknown,
+> = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ ConnectData,
+ ConnectErrorType,
+ ConnectVariables,
+ context
+ > & {
+ connect: ConnectMutate
+ connectAsync: ConnectMutateAsync
+ connectors: Compute>
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useConnect */
+export function useConnect<
+ config extends Config = ResolvedRegister['config'],
+ context = unknown,
+>(
+ parameters: UseConnectParameters = () => ({}),
+): UseConnectReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(connectMutationOptions(config))
+ const { mutate, mutateAsync, ...result } = $derived(
+ createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ })),
+ )
+
+ // Reset mutation back to an idle state when the connector disconnects.
+ $effect(() => {
+ ;[
+ // deps
+ config,
+ result.reset,
+ ]
+ return config.subscribe(
+ ({ status }) => status,
+ (status, previousStatus) => {
+ if (previousStatus === 'connected' && status === 'disconnected')
+ result.reset()
+ },
+ )
+ })
+
+ const connectors = $derived.by(useConnectors(() => ({ config })))
+
+ return () => ({
+ ...result,
+ connect: mutate,
+ connectAsync: mutateAsync,
+ connectors,
+ })
+}
diff --git a/packages/svelte/src/hooks/useConnections.svelte.test.ts b/packages/svelte/src/hooks/useConnections.svelte.test.ts
new file mode 100644
index 0000000000..e1a75df810
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnections.svelte.test.ts
@@ -0,0 +1,30 @@
+import { connect } from '@wagmi/core'
+import { config, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { flushSync } from 'svelte'
+import { expect, test } from 'vitest'
+import { useConnections } from './useConnections.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(useConnections())
+
+ expect(result).toEqual([])
+
+ await connect(config, { connector: config.connectors[0]! })
+
+ await expect.poll(() => result.length).toEqual(1)
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const result = $derived.by(useConnections(() => ({ config })))
+ expect(result).toBeDefined()
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useConnections.svelte.ts b/packages/svelte/src/hooks/useConnections.svelte.ts
new file mode 100644
index 0000000000..d4d4cde43d
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnections.svelte.ts
@@ -0,0 +1,37 @@
+import {
+ type GetConnectionsReturnType,
+ getConnections,
+ watchConnections,
+} from '@wagmi/core'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseConnectionsParameters = RuneParameters
+
+export type UseConnectionsReturnType = RuneReturnType
+
+/** https://wagmi.sh/react/api/hooks/useConnections */
+export function useConnections(
+ parameters: UseConnectionsParameters = () => ({}),
+): UseConnectionsReturnType {
+ const config = $derived.by(useConfig(parameters))
+
+ let connections = $state(getConnections(config))
+
+ $effect(() => {
+ connections = getConnections(config)
+ const unsubscribe = watchConnections(config, {
+ onChange: (newConnections) => {
+ connections = newConnections
+ },
+ })
+
+ return unsubscribe
+ })
+
+ return () => connections
+}
diff --git a/packages/svelte/src/hooks/useConnectors.svelte.test.ts b/packages/svelte/src/hooks/useConnectors.svelte.test.ts
new file mode 100644
index 0000000000..3f601c47ca
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnectors.svelte.test.ts
@@ -0,0 +1,34 @@
+import { mock } from '@wagmi/connectors'
+import { accounts, config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useConnectors } from './useConnectors.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(useConnectors())
+
+ const count = config.connectors.length
+ expect(result.length).toBe(count)
+ expect(result).toEqual(config.connectors)
+
+ config._internal.connectors.setState(() => [
+ ...config.connectors,
+ config._internal.connectors.setup(mock({ accounts })),
+ ])
+
+ await expect.poll(() => result.length).toBe(count + 1)
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ () => {
+ const result = $derived.by(useConnectors(() => ({ config })))
+ expect(result).toBeDefined()
+ },
+ { shouldMockConfig: false },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useConnectors.svelte.ts b/packages/svelte/src/hooks/useConnectors.svelte.ts
new file mode 100644
index 0000000000..8ee5b4f2f6
--- /dev/null
+++ b/packages/svelte/src/hooks/useConnectors.svelte.ts
@@ -0,0 +1,37 @@
+import {
+ type GetConnectorsReturnType,
+ getConnectors,
+ watchConnectors,
+} from '@wagmi/core'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseConnectorsParameters = RuneParameters
+
+export type UseConnectorsReturnType = RuneReturnType
+
+/** https://wagmi.sh/react/api/hooks/useConnectors */
+export function useConnectors(
+ parameters: UseConnectorsParameters = () => ({}),
+): UseConnectorsReturnType {
+ const config = $derived.by(useConfig(parameters))
+
+ let connectors = $state(getConnectors(config))
+
+ $effect(() => {
+ connectors = getConnectors(config)
+ const unsubscribe = watchConnectors(config, {
+ onChange: (newConnectors) => {
+ connectors = newConnectors
+ },
+ })
+
+ return unsubscribe
+ })
+
+ return () => connectors
+}
diff --git a/packages/svelte/src/hooks/useDisconnect.svelte.test.ts b/packages/svelte/src/hooks/useDisconnect.svelte.test.ts
new file mode 100644
index 0000000000..d4d76edb4c
--- /dev/null
+++ b/packages/svelte/src/hooks/useDisconnect.svelte.test.ts
@@ -0,0 +1,30 @@
+import { connect } from '@wagmi/core'
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { beforeEach, expect, test } from 'vitest'
+import { useAccount } from './useAccount.svelte.js'
+import { useDisconnect } from './useDisconnect.svelte.js'
+
+const connector = config.connectors[0]!
+
+beforeEach(async () => {
+ await connect(config, { connector })
+})
+
+test(
+ 'default',
+ testHook(async () => {
+ const account = $derived.by(useAccount())
+ const disconnect = $derived.by(useDisconnect())
+
+ expect(account.address).toBeDefined()
+ expect(account.status).toEqual('connected')
+
+ disconnect.disconnect()
+
+ await expect.poll(() => account.isDisconnected).toBeTruthy()
+
+ expect(account.address).not.toBeDefined()
+ expect(account.status).toEqual('disconnected')
+ }),
+)
diff --git a/packages/svelte/src/hooks/useDisconnect.svelte.ts b/packages/svelte/src/hooks/useDisconnect.svelte.ts
new file mode 100644
index 0000000000..dca8c4e755
--- /dev/null
+++ b/packages/svelte/src/hooks/useDisconnect.svelte.ts
@@ -0,0 +1,80 @@
+import {
+ type CreateMutationResult,
+ createMutation,
+} from '@tanstack/svelte-query'
+import type { Connector, DisconnectErrorType } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type DisconnectData,
+ type DisconnectMutate,
+ type DisconnectMutateAsync,
+ type DisconnectVariables,
+ disconnectMutationOptions,
+} from '@wagmi/core/query'
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+import { useConnections } from './useConnections.svelte.js'
+
+export type UseDisconnectParameters = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ DisconnectData,
+ DisconnectErrorType,
+ DisconnectVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseDisconnectReturnType = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ DisconnectData,
+ DisconnectErrorType,
+ DisconnectVariables,
+ context
+ > & {
+ connectors: readonly Connector[]
+ disconnect: DisconnectMutate
+ disconnectAsync: DisconnectMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useDisconnect */
+export function useDisconnect(
+ parameters: UseDisconnectParameters = () => ({}),
+): UseDisconnectReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(disconnectMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ const connections = $derived.by(useConnections(() => ({ config })))
+ const connectors = $derived(connections.map((c) => c.connector))
+
+ return () => ({
+ ...result,
+ connectors,
+ disconnect: mutate,
+ disconnectAsync: mutateAsync,
+ })
+}
diff --git a/packages/svelte/src/hooks/useEnsAvatar.svelte.test.ts b/packages/svelte/src/hooks/useEnsAvatar.svelte.test.ts
new file mode 100644
index 0000000000..13505179b4
--- /dev/null
+++ b/packages/svelte/src/hooks/useEnsAvatar.svelte.test.ts
@@ -0,0 +1,52 @@
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useEnsAvatar } from './useEnsAvatar.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(
+ useEnsAvatar(() => ({
+ name: 'wevm.eth',
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": "https://euc.li/wevm.eth",
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "ensAvatar",
+ {
+ "chainId": 1,
+ "name": "wevm.eth",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
diff --git a/packages/svelte/src/hooks/useEnsAvatar.svelte.ts b/packages/svelte/src/hooks/useEnsAvatar.svelte.ts
new file mode 100644
index 0000000000..6f8282e4a7
--- /dev/null
+++ b/packages/svelte/src/hooks/useEnsAvatar.svelte.ts
@@ -0,0 +1,62 @@
+import type {
+ Config,
+ GetEnsAvatarErrorType,
+ ResolvedRegister,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type GetEnsAvatarData,
+ type GetEnsAvatarOptions,
+ type GetEnsAvatarQueryFnData,
+ type GetEnsAvatarQueryKey,
+ getEnsAvatarQueryOptions,
+} from '@wagmi/core/query'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter, QueryParameter } from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseEnsAvatarParameters<
+ config extends Config = Config,
+ selectData = GetEnsAvatarData,
+> = RuneParameters<
+ Compute<
+ GetEnsAvatarOptions &
+ ConfigParameter &
+ QueryParameter<
+ GetEnsAvatarQueryFnData,
+ GetEnsAvatarErrorType,
+ selectData,
+ GetEnsAvatarQueryKey
+ >
+ >
+>
+
+export type UseEnsAvatarReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useEnsAvatar */
+export function useEnsAvatar<
+ config extends Config = ResolvedRegister['config'],
+ selectData = GetEnsAvatarData,
+>(
+ parameters: UseEnsAvatarParameters = () => ({}),
+): UseEnsAvatarReturnType {
+ const { name, query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(() => ({ config })))
+
+ const options = $derived(
+ getEnsAvatarQueryOptions(config, {
+ ...parameters(),
+ chainId: parameters().chainId ?? chainId,
+ }),
+ )
+
+ const enabled = $derived(Boolean(name && (query.enabled ?? true)))
+
+ return createQuery(() => ({ ...query, ...options, enabled }))
+}
diff --git a/packages/svelte/src/hooks/useEnsName.svelte.test.ts b/packages/svelte/src/hooks/useEnsName.svelte.test.ts
new file mode 100644
index 0000000000..3f9fc6e3bf
--- /dev/null
+++ b/packages/svelte/src/hooks/useEnsName.svelte.test.ts
@@ -0,0 +1,52 @@
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useEnsName } from './useEnsName.svelte'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(
+ useEnsName(() => ({
+ address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": "wevm.eth",
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "ensName",
+ {
+ "address": "0xd2135CfB216b74109775236E36d4b433F1DF507B",
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
diff --git a/packages/svelte/src/hooks/useEnsName.svelte.ts b/packages/svelte/src/hooks/useEnsName.svelte.ts
new file mode 100644
index 0000000000..724343887a
--- /dev/null
+++ b/packages/svelte/src/hooks/useEnsName.svelte.ts
@@ -0,0 +1,62 @@
+import type { Config, GetEnsNameErrorType, ResolvedRegister } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type GetEnsNameData,
+ type GetEnsNameOptions,
+ type GetEnsNameQueryFnData,
+ type GetEnsNameQueryKey,
+ getEnsNameQueryOptions,
+} from '@wagmi/core/query'
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ QueryParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseEnsNameParameters<
+ config extends Config = Config,
+ selectData = GetEnsNameData,
+> = RuneParameters<
+ Compute<
+ GetEnsNameOptions &
+ ConfigParameter &
+ QueryParameter<
+ GetEnsNameQueryFnData,
+ GetEnsNameErrorType,
+ selectData,
+ GetEnsNameQueryKey
+ >
+ >
+>
+
+export type UseEnsNameReturnType = RuneReturnType<
+ CreateQueryReturnType
+>
+
+/** https://wagmi.sh/react/api/hooks/useEnsName */
+export function useEnsName<
+ config extends Config = ResolvedRegister['config'],
+ selectData = GetEnsNameData,
+>(
+ parameters: UseEnsNameParameters = () => ({}),
+): UseEnsNameReturnType {
+ const { address, query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(() => ({ config })))
+
+ const options = $derived(
+ getEnsNameQueryOptions(config, {
+ ...parameters(),
+ chainId: parameters().chainId ?? chainId,
+ }),
+ )
+
+ const enabled = $derived(Boolean(address && (query.enabled ?? true)))
+
+ return createQuery(() => ({ ...query, ...options, enabled }))
+}
diff --git a/packages/svelte/src/hooks/useGasPrice.svelte.test.ts b/packages/svelte/src/hooks/useGasPrice.svelte.test.ts
new file mode 100644
index 0000000000..b09ac5bd5a
--- /dev/null
+++ b/packages/svelte/src/hooks/useGasPrice.svelte.test.ts
@@ -0,0 +1,116 @@
+import { chain, testClient } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useGasPrice } from './useGasPrice.svelte'
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const result = $derived.by(useGasPrice())
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 2750000000n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "gasPrice",
+ {
+ "chainId": 1,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ },
+ {},
+ async () => {
+ await testClient.mainnet.restart()
+
+ await testClient.mainnet.setNextBlockBaseFeePerGas({
+ baseFeePerGas: 2_000_000_000n,
+ })
+ await testClient.mainnet.mine({ blocks: 1 })
+ },
+ ),
+)
+
+test(
+ 'parameters: chainId',
+ testHook(
+ async () => {
+ const result = $derived.by(
+ useGasPrice(() => ({ chainId: chain.mainnet2.id })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 1875000000n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "gasPrice",
+ {
+ "chainId": 456,
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ },
+ {},
+ async () => {
+ await testClient.mainnet2.restart()
+
+ await testClient.mainnet2.setNextBlockBaseFeePerGas({
+ baseFeePerGas: 1_000_000_000n,
+ })
+ await testClient.mainnet2.mine({ blocks: 1 })
+ },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useGasPrice.svelte.ts b/packages/svelte/src/hooks/useGasPrice.svelte.ts
new file mode 100644
index 0000000000..7e806e8d54
--- /dev/null
+++ b/packages/svelte/src/hooks/useGasPrice.svelte.ts
@@ -0,0 +1,65 @@
+import type {
+ Config,
+ GetGasPriceErrorType,
+ ResolvedRegister,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type GetGasPriceData,
+ type GetGasPriceOptions,
+ type GetGasPriceQueryFnData,
+ type GetGasPriceQueryKey,
+ getGasPriceQueryOptions,
+} from '@wagmi/core/query'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter, QueryParameter } from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseGasPriceParameters<
+ config extends Config = Config,
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = GetGasPriceData,
+> = RuneParameters<
+ Compute<
+ GetGasPriceOptions &
+ ConfigParameter &
+ QueryParameter<
+ GetGasPriceQueryFnData,
+ GetGasPriceErrorType,
+ selectData,
+ GetGasPriceQueryKey
+ >
+ >
+>
+
+export type UseGasPriceReturnType =
+ RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useGasPrice */
+export function useGasPrice<
+ config extends Config = ResolvedRegister['config'],
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = GetGasPriceData,
+>(
+ parameters: UseGasPriceParameters = () => ({}),
+): UseGasPriceReturnType {
+ const { query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const configChainId = $derived.by(useChainId(() => ({ config })))
+ const chainId = $derived(parameters().chainId ?? configChainId)
+
+ const options = $derived(
+ getGasPriceQueryOptions(config, {
+ ...parameters(),
+ chainId,
+ }),
+ )
+
+ return createQuery(() => ({ ...query, ...options }))
+}
diff --git a/packages/svelte/src/hooks/useReadContract.svelte.test.ts b/packages/svelte/src/hooks/useReadContract.svelte.test.ts
new file mode 100644
index 0000000000..c9b040ce10
--- /dev/null
+++ b/packages/svelte/src/hooks/useReadContract.svelte.test.ts
@@ -0,0 +1,204 @@
+import { abi, address, bytecode, chain, config, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useReadContract } from './useReadContract.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(
+ useReadContract(() => ({
+ address: address.wagmiMintExample,
+ abi: abi.wagmiMintExample,
+ functionName: 'balanceOf',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] as const,
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 4n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "readContract",
+ {
+ "address": "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 1,
+ "functionName": "balanceOf",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'parameters: chainId',
+ testHook(async () => {
+ const result = $derived.by(
+ useReadContract(() => ({
+ address: address.wagmiMintExample,
+ abi: abi.wagmiMintExample,
+ functionName: 'balanceOf',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] as const,
+ chainId: chain.mainnet2.id,
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 4n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "readContract",
+ {
+ "address": "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 456,
+ "functionName": "balanceOf",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'parameters: config',
+ testHook(
+ async () => {
+ const result = $derived.by(
+ useReadContract(() => ({
+ address: address.wagmiMintExample,
+ abi: abi.wagmiMintExample,
+ functionName: 'balanceOf',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] as const,
+ config,
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": 4n,
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "readContract",
+ {
+ "address": "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 1,
+ "functionName": "balanceOf",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ },
+ { shouldMockConfig: false },
+ ),
+)
+
+test(
+ 'parameters: deployless read (bytecode)',
+ testHook(async () => {
+ const result = $derived.by(
+ useReadContract(() => ({
+ abi: abi.wagmiMintExample,
+ functionName: 'name',
+ code: bytecode.wagmiMintExample,
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result.data).toMatchInlineSnapshot(`"wagmi"`)
+ }),
+)
+
+test(
+ 'behavior: disabled when properties missing',
+ testHook(async () => {
+ const result = $derived.by(useReadContract())
+
+ await wait(100)
+ await expect.poll(() => result.isPending).toBeTruthy()
+ }),
+)
diff --git a/packages/svelte/src/hooks/useReadContract.svelte.ts b/packages/svelte/src/hooks/useReadContract.svelte.ts
new file mode 100644
index 0000000000..8a30cb07cc
--- /dev/null
+++ b/packages/svelte/src/hooks/useReadContract.svelte.ts
@@ -0,0 +1,109 @@
+'use client'
+
+import type {
+ Config,
+ ReadContractErrorType,
+ ResolvedRegister,
+} from '@wagmi/core'
+import type { UnionCompute } from '@wagmi/core/internal'
+import {
+ type ReadContractData,
+ type ReadContractOptions,
+ type ReadContractQueryFnData,
+ type ReadContractQueryKey,
+ readContractQueryOptions,
+ structuralSharing,
+} from '@wagmi/core/query'
+import type { Abi, ContractFunctionArgs, ContractFunctionName, Hex } from 'viem'
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type {
+ ConfigParameter,
+ QueryParameter,
+ RuneParameters,
+ RuneReturnType,
+} from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseReadContractParameters<
+ abi extends Abi | readonly unknown[] = Abi,
+ functionName extends ContractFunctionName<
+ abi,
+ 'pure' | 'view'
+ > = ContractFunctionName,
+ args extends ContractFunctionArgs<
+ abi,
+ 'pure' | 'view',
+ functionName
+ > = ContractFunctionArgs,
+ config extends Config = Config,
+ selectData = ReadContractData,
+> = RuneParameters<
+ UnionCompute<
+ ReadContractOptions &
+ ConfigParameter &
+ QueryParameter<
+ ReadContractQueryFnData,
+ ReadContractErrorType,
+ selectData,
+ ReadContractQueryKey
+ >
+ >
+>
+
+export type UseReadContractReturnType<
+ abi extends Abi | readonly unknown[] = Abi,
+ functionName extends ContractFunctionName<
+ abi,
+ 'pure' | 'view'
+ > = ContractFunctionName,
+ args extends ContractFunctionArgs<
+ abi,
+ 'pure' | 'view',
+ functionName
+ > = ContractFunctionArgs,
+ selectData = ReadContractData,
+> = RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useReadContract */
+export function useReadContract<
+ const abi extends Abi | readonly unknown[],
+ functionName extends ContractFunctionName,
+ args extends ContractFunctionArgs,
+ config extends Config = ResolvedRegister['config'],
+ selectData = ReadContractData,
+>(
+ parameters: UseReadContractParameters<
+ abi,
+ functionName,
+ args,
+ config,
+ selectData
+ > = () => ({}) as any,
+): UseReadContractReturnType {
+ const { abi, address, functionName, query = {} } = $derived.by(parameters)
+ // @ts-ignore
+ const code = $derived(parameters().code as Hex | undefined)
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(() => ({ config })))
+
+ const options = $derived(
+ readContractQueryOptions(config, {
+ ...(parameters() as any),
+ chainId: parameters().chainId ?? chainId,
+ }),
+ )
+ const enabled = $derived(
+ Boolean(
+ (address || code) && abi && functionName && (query.enabled ?? true),
+ ),
+ )
+
+ return createQuery(() => ({
+ ...query,
+ ...options,
+ enabled,
+ structuralSharing: query.structuralSharing ?? structuralSharing,
+ }))
+}
diff --git a/packages/svelte/src/hooks/useReadContracts.svelte.test.ts b/packages/svelte/src/hooks/useReadContracts.svelte.test.ts
new file mode 100644
index 0000000000..0cb49b10a0
--- /dev/null
+++ b/packages/svelte/src/hooks/useReadContracts.svelte.test.ts
@@ -0,0 +1,267 @@
+import { abi, address, chain } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useReadContracts } from './useReadContracts.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(
+ useReadContracts(() => ({
+ contracts: [
+ {
+ address: address.wagmiMintExample,
+ abi: abi.wagmiMintExample,
+ functionName: 'balanceOf',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'],
+ },
+ {
+ address: address.wagmiMintExample,
+ abi: abi.wagmiMintExample,
+ functionName: 'symbol',
+ },
+ ],
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": [
+ {
+ "result": 4n,
+ "status": "success",
+ },
+ {
+ "result": "WAGMI",
+ "status": "success",
+ },
+ ],
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "readContracts",
+ {
+ "chainId": 1,
+ "contracts": [
+ {
+ "address": "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 1,
+ "functionName": "balanceOf",
+ },
+ {
+ "address": "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
+ "chainId": 1,
+ "functionName": "symbol",
+ },
+ ],
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'multichain',
+ testHook(async () => {
+ const { mainnet, mainnet2, optimism } = chain
+ const result = $derived.by(
+ useReadContracts(() => ({
+ contracts: [
+ {
+ abi: abi.wagmigotchi,
+ address: address.wagmigotchi,
+ chainId: mainnet.id,
+ functionName: 'love',
+ args: ['0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c'],
+ },
+ {
+ abi: abi.wagmigotchi,
+ address: address.wagmigotchi,
+ chainId: mainnet.id,
+ functionName: 'love',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'],
+ },
+ {
+ abi: abi.wagmigotchi,
+ address: address.wagmigotchi,
+ chainId: mainnet.id,
+ functionName: 'love',
+ args: ['0xd2135CfB216b74109775236E36d4b433F1DF507B'],
+ },
+ {
+ abi: abi.wagmigotchi,
+ address: address.wagmigotchi,
+ chainId: mainnet2.id,
+ functionName: 'getAlive',
+ },
+ {
+ abi: abi.mloot,
+ address: address.mloot,
+ chainId: mainnet2.id,
+ functionName: 'tokenOfOwnerByIndex',
+ args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', 0n],
+ },
+ {
+ abi: abi.erc20,
+ address: address.optimism.usdc,
+ chainId: optimism.id,
+ functionName: 'symbol',
+ },
+ {
+ abi: abi.erc20,
+ address: address.optimism.usdc,
+ chainId: optimism.id,
+ functionName: 'balanceOf',
+ args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'],
+ },
+ ],
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": [
+ {
+ "result": 2n,
+ "status": "success",
+ },
+ {
+ "result": 1n,
+ "status": "success",
+ },
+ {
+ "result": 0n,
+ "status": "success",
+ },
+ {
+ "result": false,
+ "status": "success",
+ },
+ {
+ "result": 370395n,
+ "status": "success",
+ },
+ {
+ "result": "USDC",
+ "status": "success",
+ },
+ {
+ "result": 10959340n,
+ "status": "success",
+ },
+ ],
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "readContracts",
+ {
+ "chainId": 1,
+ "contracts": [
+ {
+ "address": "0xecb504d39723b0be0e3a9aa33d646642d1051ee1",
+ "args": [
+ "0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c",
+ ],
+ "chainId": 1,
+ "functionName": "love",
+ },
+ {
+ "address": "0xecb504d39723b0be0e3a9aa33d646642d1051ee1",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 1,
+ "functionName": "love",
+ },
+ {
+ "address": "0xecb504d39723b0be0e3a9aa33d646642d1051ee1",
+ "args": [
+ "0xd2135CfB216b74109775236E36d4b433F1DF507B",
+ ],
+ "chainId": 1,
+ "functionName": "love",
+ },
+ {
+ "address": "0xecb504d39723b0be0e3a9aa33d646642d1051ee1",
+ "chainId": 456,
+ "functionName": "getAlive",
+ },
+ {
+ "address": "0x1dfe7ca09e99d10835bf73044a23b73fc20623df",
+ "args": [
+ "0xA0Cf798816D4b9b9866b5330EEa46a18382f251e",
+ 0n,
+ ],
+ "chainId": 456,
+ "functionName": "tokenOfOwnerByIndex",
+ },
+ {
+ "address": "0x7f5c764cbc14f9669b88837ca1490cca17c31607",
+ "chainId": 10,
+ "functionName": "symbol",
+ },
+ {
+ "address": "0x7f5c764cbc14f9669b88837ca1490cca17c31607",
+ "args": [
+ "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC",
+ ],
+ "chainId": 10,
+ "functionName": "balanceOf",
+ },
+ ],
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
diff --git a/packages/svelte/src/hooks/useReadContracts.svelte.ts b/packages/svelte/src/hooks/useReadContracts.svelte.ts
new file mode 100644
index 0000000000..81ce6b9651
--- /dev/null
+++ b/packages/svelte/src/hooks/useReadContracts.svelte.ts
@@ -0,0 +1,93 @@
+import type {
+ Config,
+ ReadContractsErrorType,
+ ResolvedRegister,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type ReadContractsData,
+ type ReadContractsOptions,
+ type ReadContractsQueryFnData,
+ type ReadContractsQueryKey,
+ readContractsQueryOptions,
+ structuralSharing,
+} from '@wagmi/core/query'
+import type { ContractFunctionParameters } from 'viem'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter, QueryParameter } from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseReadContractsParameters<
+ contracts extends readonly unknown[] = readonly ContractFunctionParameters[],
+ allowFailure extends boolean = true,
+ config extends Config = Config,
+ selectData = ReadContractsData,
+> = RuneParameters<
+ Compute<
+ ReadContractsOptions &
+ ConfigParameter &
+ QueryParameter<
+ ReadContractsQueryFnData,
+ ReadContractsErrorType,
+ selectData,
+ ReadContractsQueryKey
+ >
+ >
+>
+
+export type UseReadContractsReturnType<
+ contracts extends readonly unknown[] = readonly ContractFunctionParameters[],
+ allowFailure extends boolean = true,
+ selectData = ReadContractsData,
+> = RuneReturnType>
+
+/** https://wagmi.sh/react/api/hooks/useReadContracts */
+export function useReadContracts<
+ const contracts extends readonly unknown[],
+ allowFailure extends boolean = true,
+ config extends Config = ResolvedRegister['config'],
+ selectData = ReadContractsData,
+>(
+ parameters: UseReadContractsParameters<
+ contracts,
+ allowFailure,
+ config,
+ selectData
+ > = () => ({}),
+): UseReadContractsReturnType {
+ const { contracts = [], query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(() => ({ config })))
+
+ const options = $derived(
+ readContractsQueryOptions(config, {
+ ...parameters(),
+ chainId,
+ }),
+ )
+
+ const enabled = $derived(() => {
+ let isContractsValid = false
+ for (const contract of contracts) {
+ const { abi, address, functionName } =
+ contract as ContractFunctionParameters
+ if (!abi || !address || !functionName) {
+ isContractsValid = false
+ break
+ }
+ isContractsValid = true
+ }
+ return Boolean(isContractsValid && (query.enabled ?? true))
+ })
+
+ return createQuery(() => ({
+ ...options,
+ ...query,
+ enabled,
+ structuralSharing: query.structuralSharing ?? structuralSharing,
+ }))
+}
diff --git a/packages/svelte/src/hooks/useSendTransaction.svelte.test.ts b/packages/svelte/src/hooks/useSendTransaction.svelte.test.ts
new file mode 100644
index 0000000000..7680628516
--- /dev/null
+++ b/packages/svelte/src/hooks/useSendTransaction.svelte.test.ts
@@ -0,0 +1,27 @@
+import { connect, disconnect } from '@wagmi/core'
+import { config, transactionHashRegex } from '@wagmi/test'
+import { parseEther } from 'viem'
+import { expect, test } from 'vitest'
+
+import { setups, teardowns, testHook } from '@wagmi/test/svelte'
+import { useSendTransaction } from './useSendTransaction.svelte'
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const sendTransaction = $derived.by(useSendTransaction())
+
+ sendTransaction.sendTransaction({
+ to: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
+ value: parseEther('0.01'),
+ })
+ await expect.poll(() => sendTransaction.isSuccess).toBeTruthy()
+
+ expect(sendTransaction.data).toMatch(transactionHashRegex)
+ },
+ {},
+ setups.connect,
+ teardowns.disconnect,
+ ),
+)
diff --git a/packages/svelte/src/hooks/useSendTransaction.svelte.ts b/packages/svelte/src/hooks/useSendTransaction.svelte.ts
new file mode 100644
index 0000000000..f3fc7a7b74
--- /dev/null
+++ b/packages/svelte/src/hooks/useSendTransaction.svelte.ts
@@ -0,0 +1,82 @@
+import { createMutation } from '@tanstack/svelte-query'
+import type {
+ Config,
+ ResolvedRegister,
+ SendTransactionErrorType,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type SendTransactionData,
+ type SendTransactionMutate,
+ type SendTransactionMutateAsync,
+ type SendTransactionVariables,
+ sendTransactionMutationOptions,
+} from '@wagmi/core/query'
+
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseSendTransactionParameters<
+ config extends Config = Config,
+ context = unknown,
+> = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ SendTransactionData,
+ SendTransactionErrorType,
+ SendTransactionVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseSendTransactionReturnType<
+ config extends Config = Config,
+ context = unknown,
+> = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ SendTransactionData,
+ SendTransactionErrorType,
+ SendTransactionVariables,
+ context
+ > & {
+ sendTransaction: SendTransactionMutate
+ sendTransactionAsync: SendTransactionMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useSendTransaction */
+export function useSendTransaction<
+ config extends Config = ResolvedRegister['config'],
+ context = unknown,
+>(
+ parameters: UseSendTransactionParameters = () => ({}),
+): UseSendTransactionReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(sendTransactionMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ return () => ({
+ ...result,
+ sendTransaction: mutate,
+ sendTransactionAsync: mutateAsync,
+ })
+}
diff --git a/packages/svelte/src/hooks/useSignMessage.svelte.test.ts b/packages/svelte/src/hooks/useSignMessage.svelte.test.ts
new file mode 100644
index 0000000000..5211bbf714
--- /dev/null
+++ b/packages/svelte/src/hooks/useSignMessage.svelte.test.ts
@@ -0,0 +1,49 @@
+import { connect, disconnect, getAccount } from '@wagmi/core'
+import { config, privateKey, wait } from '@wagmi/test'
+import { recoverMessageAddress } from 'viem'
+import { expect, test, vi } from 'vitest'
+
+import { setups, teardowns, testHook } from '@wagmi/test/svelte'
+import { privateKeyToAccount } from 'viem/accounts'
+import { useSignMessage } from './useSignMessage.svelte'
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const signMessage = $derived.by(useSignMessage())
+
+ signMessage.signMessage({ message: 'foo bar baz' })
+ await expect.poll(() => signMessage.isSuccess).toBeTruthy()
+
+ await expect(
+ recoverMessageAddress({
+ message: 'foo bar baz',
+ signature: signMessage.data!,
+ }),
+ ).resolves.toEqual(getAccount(config).address)
+ },
+ {},
+ setups.connect,
+ teardowns.disconnect,
+ ),
+)
+
+test(
+ 'behavior: local account',
+ testHook(async () => {
+ const signMessage = $derived.by(useSignMessage())
+
+ const account = privateKeyToAccount(privateKey)
+ signMessage.signMessage({ account, message: 'foo bar baz' })
+
+ await expect.poll(() => signMessage.isSuccess).toBeTruthy()
+
+ await expect(
+ recoverMessageAddress({
+ message: 'foo bar baz',
+ signature: signMessage.data!,
+ }),
+ ).resolves.toEqual(account.address)
+ }),
+)
diff --git a/packages/svelte/src/hooks/useSignMessage.svelte.ts b/packages/svelte/src/hooks/useSignMessage.svelte.ts
new file mode 100644
index 0000000000..b5f087dab3
--- /dev/null
+++ b/packages/svelte/src/hooks/useSignMessage.svelte.ts
@@ -0,0 +1,69 @@
+import { createMutation } from '@tanstack/svelte-query'
+import type { SignMessageErrorType } from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type SignMessageData,
+ type SignMessageMutate,
+ type SignMessageMutateAsync,
+ type SignMessageVariables,
+ signMessageMutationOptions,
+} from '@wagmi/core/query'
+
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseSignMessageParameters = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ SignMessageData,
+ SignMessageErrorType,
+ SignMessageVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseSignMessageReturnType = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ SignMessageData,
+ SignMessageErrorType,
+ SignMessageVariables,
+ context
+ > & {
+ signMessage: SignMessageMutate
+ signMessageAsync: SignMessageMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useSignMessage */
+export function useSignMessage(
+ parameters: UseSignMessageParameters = () => ({}),
+): UseSignMessageReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(signMessageMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ return () => ({
+ ...result,
+ signMessage: mutate,
+ signMessageAsync: mutateAsync,
+ })
+}
diff --git a/packages/svelte/src/hooks/useSwitchAccount.svelte.test.ts b/packages/svelte/src/hooks/useSwitchAccount.svelte.test.ts
new file mode 100644
index 0000000000..7ecc1f05fa
--- /dev/null
+++ b/packages/svelte/src/hooks/useSwitchAccount.svelte.test.ts
@@ -0,0 +1,45 @@
+import { connect, disconnect } from '@wagmi/core'
+import { config } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useAccount } from './useAccount.svelte.js'
+import { useSwitchAccount } from './useSwitchAccount.svelte.js'
+
+const connector1 = config.connectors[0]!
+const connector2 = config.connectors[1]!
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const account = $derived.by(useAccount())
+ const switchAccount = $derived.by(useSwitchAccount())
+
+ const address1 = account.address
+ expect(address1).toBeDefined()
+
+ switchAccount.switchAccount({ connector: connector2 })
+ await expect.poll(() => switchAccount.isSuccess).toBeTruthy()
+
+ const address2 = account.address
+ expect(address2).toBeDefined()
+ expect(address1).not.toBe(address2)
+
+ switchAccount.switchAccount({ connector: connector1 })
+ await expect.poll(() => switchAccount.isSuccess).toBeTruthy()
+
+ const address3 = account.address
+ expect(address3).toBeDefined()
+ expect(address1).toBe(address3)
+ },
+ {},
+ async () => {
+ await connect(config, { connector: connector2 })
+ await connect(config, { connector: connector1 })
+ },
+ async () => {
+ await disconnect(config, { connector: connector1 })
+ await disconnect(config, { connector: connector2 })
+ },
+ ),
+)
diff --git a/packages/svelte/src/hooks/useSwitchAccount.svelte.ts b/packages/svelte/src/hooks/useSwitchAccount.svelte.ts
new file mode 100644
index 0000000000..4a2d780fd6
--- /dev/null
+++ b/packages/svelte/src/hooks/useSwitchAccount.svelte.ts
@@ -0,0 +1,89 @@
+import { createMutation } from '@tanstack/svelte-query'
+import type {
+ Config,
+ Connector,
+ ResolvedRegister,
+ SwitchAccountErrorType,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type SwitchAccountData,
+ type SwitchAccountMutate,
+ type SwitchAccountMutateAsync,
+ type SwitchAccountVariables,
+ switchAccountMutationOptions,
+} from '@wagmi/core/query'
+
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+import { useConnections } from './useConnections.svelte.js'
+
+export type UseSwitchAccountParameters<
+ config extends Config = Config,
+ context = unknown,
+> = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ SwitchAccountData,
+ SwitchAccountErrorType,
+ SwitchAccountVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseSwitchAccountReturnType<
+ config extends Config = Config,
+ context = unknown,
+> = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ SwitchAccountData,
+ SwitchAccountErrorType,
+ SwitchAccountVariables,
+ context
+ > & {
+ connectors: readonly Connector[]
+ switchAccount: SwitchAccountMutate
+ switchAccountAsync: SwitchAccountMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useSwitchAccount */
+export function useSwitchAccount<
+ config extends Config = ResolvedRegister['config'],
+ context = unknown,
+>(
+ parameters: UseSwitchAccountParameters = () => ({}),
+): UseSwitchAccountReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(switchAccountMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ const connections = $derived.by(useConnections(() => ({ config })))
+ const connectors = $derived(connections.map((c) => c.connector))
+
+ return () => ({
+ ...result,
+ connectors,
+ switchAccount: mutate,
+ switchAccountAsync: mutateAsync,
+ })
+}
diff --git a/packages/svelte/src/hooks/useSwitchChain.svelte.test.ts b/packages/svelte/src/hooks/useSwitchChain.svelte.test.ts
new file mode 100644
index 0000000000..7ffa3bbbe8
--- /dev/null
+++ b/packages/svelte/src/hooks/useSwitchChain.svelte.test.ts
@@ -0,0 +1,112 @@
+import { chain, config, wait } from '@wagmi/test'
+import { setups, teardowns, testHook } from '@wagmi/test/svelte'
+import { expect, test, vi } from 'vitest'
+import { useAccount } from './useAccount.svelte.js'
+import { useSwitchChain } from './useSwitchChain.svelte.js'
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const account = $derived.by(useAccount())
+ const switchChain = $derived.by(useSwitchChain())
+
+ const chainId1 = account.chainId
+ expect(chainId1).toBeDefined()
+
+ switchChain.switchChain({ chainId: chain.mainnet2.id })
+ await expect.poll(() => switchChain.isSuccess).toBeTruthy()
+
+ const chainId2 = account.chainId
+ expect(chainId2).toBeDefined()
+ expect(chainId1).not.toBe(chainId2)
+
+ switchChain.switchChain({ chainId: chain.mainnet.id })
+ await wait(1000) // TODO: why is this needed?
+ await expect.poll(() => switchChain.isSuccess).toBeTruthy()
+
+ const chainId3 = account.chainId
+ expect(chainId3).toBeDefined()
+ expect(chainId1).toBe(chainId3)
+ },
+ {},
+ setups.connect,
+ teardowns.disconnect,
+ ),
+)
+
+test(
+ 'behavior: chains updates',
+ testHook(async () => {
+ const switchChain = $derived.by(useSwitchChain())
+
+ const chains = switchChain.chains
+
+ expect(
+ switchChain.chains.map(({ id, name }) => ({
+ id,
+ name,
+ })),
+ ).toMatchInlineSnapshot(`
+ [
+ {
+ "id": 1,
+ "name": "Ethereum",
+ },
+ {
+ "id": 456,
+ "name": "Ethereum",
+ },
+ {
+ "id": 10,
+ "name": "OP Mainnet",
+ },
+ ]
+ `)
+
+ config._internal.chains.setState([chain.mainnet, chain.mainnet2])
+
+ await vi.waitFor(() => switchChain.isSuccess)
+ expect(
+ switchChain.chains.map(({ id, name }) => ({
+ id,
+ name,
+ })),
+ ).toMatchInlineSnapshot(`
+ [
+ {
+ "id": 1,
+ "name": "Ethereum",
+ },
+ {
+ "id": 456,
+ "name": "Ethereum",
+ },
+ ]
+ `)
+
+ config._internal.chains.setState(chains)
+
+ expect(
+ switchChain.chains.map(({ id, name }) => ({
+ id,
+ name,
+ })),
+ ).toMatchInlineSnapshot(`
+ [
+ {
+ "id": 1,
+ "name": "Ethereum",
+ },
+ {
+ "id": 456,
+ "name": "Ethereum",
+ },
+ {
+ "id": 10,
+ "name": "OP Mainnet",
+ },
+ ]
+ `)
+ }),
+)
diff --git a/packages/svelte/src/hooks/useSwitchChain.svelte.ts b/packages/svelte/src/hooks/useSwitchChain.svelte.ts
new file mode 100644
index 0000000000..b66a85d6e1
--- /dev/null
+++ b/packages/svelte/src/hooks/useSwitchChain.svelte.ts
@@ -0,0 +1,88 @@
+import { createMutation } from '@tanstack/svelte-query'
+import type {
+ Config,
+ ResolvedRegister,
+ SwitchChainErrorType,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type SwitchChainData,
+ type SwitchChainMutate,
+ type SwitchChainMutateAsync,
+ type SwitchChainVariables,
+ switchChainMutationOptions,
+} from '@wagmi/core/query'
+
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useChains } from './useChains.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseSwitchChainParameters<
+ config extends Config = Config,
+ context = unknown,
+> = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ SwitchChainData,
+ SwitchChainErrorType,
+ SwitchChainVariables,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseSwitchChainReturnType<
+ config extends Config = Config,
+ context = unknown,
+> = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ SwitchChainData,
+ SwitchChainErrorType,
+ SwitchChainVariables,
+ context
+ > & {
+ chains: config['chains']
+ switchChain: SwitchChainMutate
+ switchChainAsync: SwitchChainMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useSwitchChain */
+export function useSwitchChain<
+ config extends Config = ResolvedRegister['config'],
+ context = unknown,
+>(
+ parameters: UseSwitchChainParameters = () => ({}),
+): UseSwitchChainReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(switchChainMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ const chains = $derived.by(useChains(() => ({ config })))
+
+ type Return = ReturnType>
+ return () => ({
+ ...result,
+ chains: chains as unknown as Return['chains'],
+ switchChain: mutate as Return['switchChain'],
+ switchChainAsync: mutateAsync as Return['switchChainAsync'],
+ })
+}
diff --git a/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.test.ts b/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.test.ts
new file mode 100644
index 0000000000..b051c326f6
--- /dev/null
+++ b/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.test.ts
@@ -0,0 +1,81 @@
+import { wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test, vi } from 'vitest'
+import { useWaitForTransactionReceipt } from './useWaitForTransactionReceipt.svelte'
+
+test(
+ 'default',
+ testHook(async () => {
+ const result = $derived.by(
+ useWaitForTransactionReceipt(() => ({
+ hash: '0x60668ed8c2dc110d61d945a936fcd45b8f13654e5c78481c8c825d1148c7ef30',
+ })),
+ )
+
+ await expect.poll(() => result.isSuccess).toBeTruthy()
+
+ expect(result).toMatchInlineSnapshot(`
+ {
+ "data": {
+ "blockHash": "0xd725a38b51e5ceec8c5f6c9ccfdb2cc423af993bb650af5eedca5e4be7156ba7",
+ "blockNumber": 15189204n,
+ "chainId": 1,
+ "contractAddress": null,
+ "cumulativeGasUsed": 12949744n,
+ "effectiveGasPrice": 9371645552n,
+ "from": "0xa0cf798816d4b9b9866b5330eea46a18382f251e",
+ "gasUsed": 21000n,
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "status": "success",
+ "to": "0xd2135cfb216b74109775236e36d4b433f1df507b",
+ "transactionHash": "0x60668ed8c2dc110d61d945a936fcd45b8f13654e5c78481c8c825d1148c7ef30",
+ "transactionIndex": 144,
+ "type": "eip1559",
+ },
+ "dataUpdatedAt": 1675209600000,
+ "error": null,
+ "errorUpdateCount": 0,
+ "errorUpdatedAt": 0,
+ "failureCount": 0,
+ "failureReason": null,
+ "fetchStatus": "idle",
+ "isError": false,
+ "isFetched": true,
+ "isFetchedAfterMount": true,
+ "isFetching": false,
+ "isInitialLoading": false,
+ "isLoading": false,
+ "isLoadingError": false,
+ "isPaused": false,
+ "isPending": false,
+ "isPlaceholderData": false,
+ "isRefetchError": false,
+ "isRefetching": false,
+ "isStale": true,
+ "isSuccess": true,
+ "queryKey": [
+ "waitForTransactionReceipt",
+ {
+ "chainId": 1,
+ "hash": "0x60668ed8c2dc110d61d945a936fcd45b8f13654e5c78481c8c825d1148c7ef30",
+ },
+ ],
+ "refetch": [Function],
+ "status": "success",
+ }
+ `)
+ }),
+)
+
+test(
+ 'disabled when hash is undefined',
+ testHook(async () => {
+ const result = $derived.by(
+ useWaitForTransactionReceipt(() => ({ hash: undefined })),
+ )
+
+ await wait(100)
+ await expect.poll(() => result.isPending).toBeTruthy()
+ }),
+)
diff --git a/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.ts b/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.ts
new file mode 100644
index 0000000000..0384f2f20d
--- /dev/null
+++ b/packages/svelte/src/hooks/useWaitForTransactionReceipt.svelte.ts
@@ -0,0 +1,79 @@
+import type {
+ Config,
+ ResolvedRegister,
+ WaitForTransactionReceiptErrorType,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type WaitForTransactionReceiptData,
+ type WaitForTransactionReceiptOptions,
+ type WaitForTransactionReceiptQueryFnData,
+ type WaitForTransactionReceiptQueryKey,
+ waitForTransactionReceiptQueryOptions,
+} from '@wagmi/core/query'
+
+import { type CreateQueryReturnType, createQuery } from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter, QueryParameter } from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseWaitForTransactionReceiptParameters<
+ config extends Config = Config,
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = WaitForTransactionReceiptData,
+> = RuneParameters<
+ Compute<
+ WaitForTransactionReceiptOptions &
+ ConfigParameter &
+ QueryParameter<
+ WaitForTransactionReceiptQueryFnData,
+ WaitForTransactionReceiptErrorType,
+ selectData,
+ WaitForTransactionReceiptQueryKey
+ >
+ >
+>
+
+export type UseWaitForTransactionReceiptReturnType<
+ config extends Config = Config,
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = WaitForTransactionReceiptData,
+> = RuneReturnType<
+ CreateQueryReturnType
+>
+
+/** https://wagmi.sh/react/api/hooks/useWaitForTransactionReceipt */
+export function useWaitForTransactionReceipt<
+ config extends Config = ResolvedRegister['config'],
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+ selectData = WaitForTransactionReceiptData,
+>(
+ parameters: UseWaitForTransactionReceiptParameters<
+ config,
+ chainId,
+ selectData
+ > = () => ({}),
+): UseWaitForTransactionReceiptReturnType {
+ const { hash, query = {} } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const chainId = $derived.by(useChainId(() => ({ config })))
+
+ const options = $derived(
+ waitForTransactionReceiptQueryOptions(config, {
+ ...parameters(),
+ chainId: parameters().chainId ?? chainId,
+ }),
+ )
+ const enabled = $derived(Boolean(hash && (query.enabled ?? true)))
+
+ return createQuery(() => ({
+ ...(query as any),
+ ...options,
+ enabled,
+ }))
+}
diff --git a/packages/svelte/src/hooks/useWatchBlockNumber.svelte.test.ts b/packages/svelte/src/hooks/useWatchBlockNumber.svelte.test.ts
new file mode 100644
index 0000000000..f1f39e4fb1
--- /dev/null
+++ b/packages/svelte/src/hooks/useWatchBlockNumber.svelte.test.ts
@@ -0,0 +1,28 @@
+import { testClient, wait } from '@wagmi/test'
+import { testHook } from '@wagmi/test/svelte'
+import { expect, test } from 'vitest'
+import { useWatchBlockNumber } from './useWatchBlockNumber.svelte.js'
+
+test(
+ 'default',
+ testHook(async () => {
+ const blockNumbers: bigint[] = []
+ useWatchBlockNumber(() => ({
+ onBlockNumber(blockNumber) {
+ blockNumbers.push(blockNumber)
+ },
+ }))
+
+ await testClient.mainnet.mine({ blocks: 1 })
+ await wait(100)
+ await testClient.mainnet.mine({ blocks: 1 })
+ await wait(100)
+ await testClient.mainnet.mine({ blocks: 1 })
+ await wait(100)
+
+ expect(blockNumbers.length).toBe(3)
+ expect(
+ blockNumbers.map((blockNumber) => blockNumber - blockNumbers[0]!),
+ ).toEqual([0n, 1n, 2n])
+ }),
+)
diff --git a/packages/svelte/src/hooks/useWatchBlockNumber.svelte.ts b/packages/svelte/src/hooks/useWatchBlockNumber.svelte.ts
new file mode 100644
index 0000000000..20c82ffc1f
--- /dev/null
+++ b/packages/svelte/src/hooks/useWatchBlockNumber.svelte.ts
@@ -0,0 +1,76 @@
+import {
+ type Config,
+ type ResolvedRegister,
+ type WatchBlockNumberParameters,
+ watchBlockNumber,
+} from '@wagmi/core'
+import type { UnionCompute, UnionExactPartial } from '@wagmi/core/internal'
+
+import type {
+ ConfigParameter,
+ EnabledParameter,
+ RuneParameters,
+} from '../types.js'
+import { useChainId } from './useChainId.svelte.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseWatchBlockNumberParameters<
+ config extends Config = Config,
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+> = RuneParameters<
+ UnionCompute<
+ UnionExactPartial> &
+ ConfigParameter &
+ EnabledParameter
+ >
+>
+
+export type UseWatchBlockNumberReturnType = void
+
+/** https://wagmi.sh/react/api/hooks/useWatchBlockNumber */
+export function useWatchBlockNumber<
+ config extends Config = ResolvedRegister['config'],
+ chainId extends
+ config['chains'][number]['id'] = config['chains'][number]['id'],
+>(
+ parameters: UseWatchBlockNumberParameters = () =>
+ ({}) as any,
+): UseWatchBlockNumberReturnType {
+ const {
+ enabled = true,
+ onBlockNumber,
+ config: _,
+ ...rest
+ } = $derived(parameters())
+
+ const config = $derived.by(useConfig(parameters))
+ const configChainId = $derived.by(useChainId(parameters))
+ const chainId = $derived(rest.chainId ?? configChainId)
+
+ $effect(() => {
+ ;[
+ // deps
+ chainId,
+ config,
+ enabled,
+ onBlockNumber,
+ rest.onError,
+ rest.emitMissed,
+ rest.emitOnBegin,
+ rest.poll,
+ rest.pollingInterval,
+ rest.syncConnectedChain,
+ ]
+ if (!enabled) return
+ if (!onBlockNumber) return
+
+ const unsubscribe = watchBlockNumber(config, {
+ ...(rest as any),
+ chainId,
+ onBlockNumber,
+ })
+
+ return unsubscribe
+ })
+}
diff --git a/packages/svelte/src/hooks/useWriteContract.svelte.test.ts b/packages/svelte/src/hooks/useWriteContract.svelte.test.ts
new file mode 100644
index 0000000000..3a25342a6a
--- /dev/null
+++ b/packages/svelte/src/hooks/useWriteContract.svelte.test.ts
@@ -0,0 +1,26 @@
+import { abi, address, config } from '@wagmi/test'
+import { expect, test } from 'vitest'
+
+import { setups, teardowns, testHook } from '@wagmi/test/svelte'
+import { useWriteContract } from './useWriteContract.svelte'
+
+test(
+ 'default',
+ testHook(
+ async () => {
+ const writeContract = $derived.by(useWriteContract())
+
+ writeContract.writeContract({
+ abi: abi.wagmiMintExample,
+ address: address.wagmiMintExample,
+ functionName: 'mint',
+ })
+ await expect.poll(() => writeContract.isSuccess).toBeTruthy()
+
+ expect(writeContract.data).toBeDefined()
+ },
+ {},
+ setups.connect,
+ teardowns.disconnect,
+ ),
+)
diff --git a/packages/svelte/src/hooks/useWriteContract.svelte.ts b/packages/svelte/src/hooks/useWriteContract.svelte.ts
new file mode 100644
index 0000000000..c54b2193e0
--- /dev/null
+++ b/packages/svelte/src/hooks/useWriteContract.svelte.ts
@@ -0,0 +1,96 @@
+import { createMutation } from '@tanstack/svelte-query'
+import type {
+ Config,
+ ResolvedRegister,
+ WriteContractErrorType,
+} from '@wagmi/core'
+import type { Compute } from '@wagmi/core/internal'
+import {
+ type WriteContractData,
+ type WriteContractMutate,
+ type WriteContractMutateAsync,
+ type WriteContractVariables,
+ writeContractMutationOptions,
+} from '@wagmi/core/query'
+import type { Abi } from 'viem'
+
+import type {
+ CreateMutationParameters,
+ CreateMutationReturnType,
+} from '../query.svelte.js'
+import type { RuneParameters, RuneReturnType } from '../types.js'
+import type { ConfigParameter } from '../types.js'
+import { useConfig } from './useConfig.svelte.js'
+
+export type UseWriteContractParameters<
+ config extends Config = Config,
+ context = unknown,
+> = RuneParameters<
+ Compute<
+ ConfigParameter & {
+ mutation?:
+ | CreateMutationParameters<
+ WriteContractData,
+ WriteContractErrorType,
+ WriteContractVariables<
+ Abi,
+ string,
+ readonly unknown[],
+ config,
+ config['chains'][number]['id']
+ >,
+ context
+ >
+ | undefined
+ }
+ >
+>
+
+export type UseWriteContractReturnType<
+ config extends Config = Config,
+ context = unknown,
+> = RuneReturnType<
+ Compute<
+ CreateMutationReturnType<
+ WriteContractData,
+ WriteContractErrorType,
+ WriteContractVariables<
+ Abi,
+ string,
+ readonly unknown[],
+ config,
+ config['chains'][number]['id']
+ >,
+ context
+ > & {
+ writeContract: WriteContractMutate
+ writeContractAsync: WriteContractMutateAsync
+ }
+ >
+>
+
+/** https://wagmi.sh/react/api/hooks/useWriteContract */
+export function useWriteContract<
+ config extends Config = ResolvedRegister['config'],
+ context = unknown,
+>(
+ parameters: UseWriteContractParameters = () => ({}),
+): UseWriteContractReturnType {
+ const { mutation } = $derived.by(parameters)
+
+ const config = $derived.by(useConfig(parameters))
+
+ const mutationOptions = $derived(writeContractMutationOptions(config))
+ const query = createMutation(() => ({
+ ...mutation,
+ ...mutationOptions,
+ }))
+ const { mutate, mutateAsync, ...result } = $derived(query)
+
+ type Return = ReturnType>
+ return () => ({
+ ...result,
+ writeContract: mutate as Return['writeContract'],
+ writeContractAsync: mutateAsync as Return['writeContractAsync'],
+ })
+}
diff --git a/packages/svelte/src/index.ts b/packages/svelte/src/index.ts
new file mode 100644
index 0000000000..8b90f9416b
--- /dev/null
+++ b/packages/svelte/src/index.ts
@@ -0,0 +1,3 @@
+// biome-ignore lint/performance/noBarrelFile: entrypoint module
+// biome-ignore lint/performance/noReExportAll: entrypoint module
+export * from './exports/index.js'
diff --git a/packages/svelte/src/query.svelte.ts b/packages/svelte/src/query.svelte.ts
new file mode 100644
index 0000000000..cdea665a71
--- /dev/null
+++ b/packages/svelte/src/query.svelte.ts
@@ -0,0 +1,91 @@
+import {
+ type CreateMutationOptions,
+ type CreateMutationResult,
+ type CreateQueryOptions,
+ type CreateQueryResult,
+ type DefaultError,
+ type QueryKey,
+ createMutation,
+ createQuery as tanstack_createQuery,
+} from '@tanstack/svelte-query'
+import type {
+ Compute,
+ ExactPartial,
+ UnionStrictOmit,
+} from '@wagmi/core/internal'
+import { hashFn } from '@wagmi/core/query'
+import type { RuneParameters, RuneReturnType } from './types.js'
+
+export type CreateQueryParameters<
+ queryFnData = unknown,
+ error = DefaultError,
+ data = queryFnData,
+ queryKey extends QueryKey = QueryKey,
+> = Compute<
+ ExactPartial<
+ Omit, 'initialData'>
+ > & {
+ // Fix `initialData` type
+ initialData?:
+ | CreateQueryOptions['initialData']
+ | undefined
+ }
+>
+
+export type CreateQueryReturnType<
+ data = unknown,
+ error = DefaultError,
+> = Compute<
+ CreateQueryResult & {
+ queryKey: QueryKey
+ }
+>
+
+export function createQuery<
+ queryFnData,
+ error,
+ data,
+ queryKey extends QueryKey,
+>(
+ parameters: RuneParameters<
+ CreateQueryParameters & {
+ queryKey: QueryKey
+ }
+ >,
+): RuneReturnType> {
+ const result = tanstack_createQuery(() => ({
+ ...parameters(),
+ queryKeyHashFn: hashFn, // for bigint support
+ }))
+ const resultWithQueryKey = $derived({
+ ...result,
+ queryKey: parameters().queryKey,
+ })
+ return () => resultWithQueryKey
+}
+
+export type CreateMutationParameters<
+ data = unknown,
+ error = Error,
+ variables = void,
+ context = unknown,
+> = Compute<
+ Omit<
+ CreateMutationOptions, context>,
+ 'mutationFn' | 'mutationKey' | 'throwOnError'
+ >
+>
+
+export type CreateMutationReturnType<
+ data = unknown,
+ error = Error,
+ variables = void,
+ context = unknown,
+> = Compute<
+ UnionStrictOmit<
+ CreateMutationResult,
+ 'mutate' | 'mutateAsync'
+ >
+>
+
+export { createMutation }
diff --git a/packages/svelte/src/types.ts b/packages/svelte/src/types.ts
new file mode 100644
index 0000000000..465fc087b3
--- /dev/null
+++ b/packages/svelte/src/types.ts
@@ -0,0 +1,31 @@
+import type {
+ CreateQueryOptions,
+ DefaultError,
+ QueryKey,
+} from '@tanstack/svelte-query'
+import type { Config } from '@wagmi/core'
+
+export type RuneParameters = () => T
+export type RuneReturnType = () => T
+
+export type ConfigParameter = {
+ config?: Config | config | undefined
+}
+
+export type EnabledParameter = {
+ enabled?: boolean | undefined
+}
+
+export type QueryParameter<
+ queryFnData = unknown,
+ error = DefaultError,
+ data = queryFnData,
+ queryKey extends QueryKey = QueryKey,
+> = {
+ query?:
+ | Omit<
+ CreateQueryOptions,
+ 'queryFn' | 'queryHash' | 'queryKey' | 'queryKeyHashFn' | 'throwOnError'
+ >
+ | undefined
+}
diff --git a/packages/svelte/src/version.test.ts b/packages/svelte/src/version.test.ts
new file mode 100644
index 0000000000..a545b00f84
--- /dev/null
+++ b/packages/svelte/src/version.test.ts
@@ -0,0 +1,6 @@
+import { expect, test } from 'vitest'
+import { getVersion } from './version.js'
+
+test('default', () => {
+ expect(getVersion()).toMatchInlineSnapshot(`"@wagmi/svelte@x.y.z"`)
+})
diff --git a/packages/svelte/src/version.ts b/packages/svelte/src/version.ts
new file mode 100644
index 0000000000..cebf26d12e
--- /dev/null
+++ b/packages/svelte/src/version.ts
@@ -0,0 +1 @@
+export const getVersion = () => `@wagmi/svelte@${__VERSION__}`
diff --git a/packages/svelte/svelte.config.js b/packages/svelte/svelte.config.js
new file mode 100644
index 0000000000..fb094f9abd
--- /dev/null
+++ b/packages/svelte/svelte.config.js
@@ -0,0 +1,21 @@
+import adapter from '@sveltejs/adapter-auto'
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ // Consult https://svelte.dev/docs/kit/integrations#preprocessors
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+
+ kit: {
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
+ adapter: adapter(),
+ files: {
+ lib: './src',
+ },
+ },
+}
+
+export default config
diff --git a/packages/svelte/test/setup.ts b/packages/svelte/test/setup.ts
new file mode 100644
index 0000000000..a47233ce75
--- /dev/null
+++ b/packages/svelte/test/setup.ts
@@ -0,0 +1,12 @@
+import { beforeEach, vi } from 'vitest'
+
+vi.mock('svelte')
+
+beforeEach(async () => {
+ // Make dates stable across runs
+ Date.now = vi.fn(() => new Date(Date.UTC(2023, 1, 1)).valueOf())
+
+ globalThis.__VERSION__ = 'x.y.z'
+
+ vi.restoreAllMocks()
+})
diff --git a/packages/svelte/tsconfig.json b/packages/svelte/tsconfig.json
new file mode 100644
index 0000000000..8ed3dd7f25
--- /dev/null
+++ b/packages/svelte/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext"
+ }
+}
diff --git a/packages/svelte/vite.config.ts b/packages/svelte/vite.config.ts
new file mode 100644
index 0000000000..66d24534c8
--- /dev/null
+++ b/packages/svelte/vite.config.ts
@@ -0,0 +1,21 @@
+import { sveltekit } from '@sveltejs/kit/vite'
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ plugins: [sveltekit()],
+ define: {
+ __VERSION__: JSON.stringify(require('./package.json').version),
+ },
+ test: {
+ name: '@wagmi/svelte',
+ include: ['./src/**/*.test.ts'],
+ environment: 'happy-dom',
+ testTimeout: 20_000,
+ setupFiles: ['./test/setup.ts'],
+ expect: {
+ poll: {
+ timeout: 10_000,
+ },
+ },
+ },
+})
diff --git a/packages/test/package.json b/packages/test/package.json
index f4e1f9fff4..f34bac074c 100644
--- a/packages/test/package.json
+++ b/packages/test/package.json
@@ -22,7 +22,8 @@
"!src/**/*.test.ts",
"!src/**/*.test-d.ts",
"react/**",
- "vue/**"
+ "vue/**",
+ "svelte/**"
],
"sideEffects": false,
"type": "module",
@@ -42,16 +43,22 @@
"types": "./dist/types/exports/vue.d.ts",
"default": "./dist/esm/exports/vue.js"
},
+ "./svelte": {
+ "types": "./dist/types/exports/svelte.svelte.d.ts",
+ "default": "./dist/esm/exports/svelte.svelte.js"
+ },
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"react": ["./dist/types/exports/react.d.ts"],
- "vue": ["./dist/types/exports/vue.d.ts"]
+ "vue": ["./dist/types/exports/vue.d.ts"],
+ "svelte": ["./dist/types/exports/svelte.svelte.d.ts"]
}
},
"peerDependencies": {
"@tanstack/react-query": ">=5.0.0",
+ "@tanstack/svelte-query": "^5.59.20",
"@tanstack/vue-query": ">=5.0.0",
"@testing-library/react": ">=14.0.0",
"@types/react": ">=18",
@@ -73,6 +80,9 @@
"@tanstack/vue-query": {
"optional": true
},
+ "@tanstack/svelte-query": {
+ "optional": true
+ },
"@testing-library/react": {
"optional": true
},
@@ -99,6 +109,7 @@
}
},
"devDependencies": {
+ "@tanstack/svelte-query": "^5.59.20",
"@tanstack/react-query": "catalog:",
"@tanstack/vue-query": "catalog:",
"@testing-library/dom": "catalog:",
diff --git a/packages/test/src/exports/svelte.svelte.ts b/packages/test/src/exports/svelte.svelte.ts
new file mode 100644
index 0000000000..a5ac75b0b0
--- /dev/null
+++ b/packages/test/src/exports/svelte.svelte.ts
@@ -0,0 +1,68 @@
+import { QueryClient } from '@tanstack/svelte-query'
+import { type Config, connect, disconnect, hydrate } from '@wagmi/core'
+import { vi } from 'vitest'
+import { config } from '../config.js'
+
+type TestHookOptions = {
+ shouldMockConfig?: boolean
+ mockConfigOverride?: Config
+ reconnectOnMount?: boolean
+}
+
+const noop = () => {}
+
+export const setups = {
+ connect: async () => {
+ const connector = config.connectors[0]!
+ await connect(config, { connector })
+ },
+}
+
+export const teardowns = {
+ disconnect: async () => {
+ const connector = config.connectors[0]!
+ await disconnect(config, { connector })
+ },
+}
+
+export const testHook =
+ (
+ fn: () => void,
+ options: TestHookOptions = {},
+ setup: () => void = noop,
+ teardown: () => void = noop,
+ ) =>
+ async () => {
+ const queryClient = new QueryClient()
+ const svelte = await import('svelte')
+ svelte.getContext = vi.fn((key: any) => {
+ if (key === '$$_queryClient') return queryClient
+ if (key === '$$_isRestoring') return () => false
+
+ if (options.shouldMockConfig ?? true) {
+ return options.mockConfigOverride ?? config
+ }
+
+ return undefined
+ }) as (key: any) => T // match type signature of svelte.getContext
+
+ const { onMount } = hydrate(config, {
+ reconnectOnMount: options.reconnectOnMount ?? false,
+ })
+
+ await onMount()
+
+ await Promise.resolve(setup())
+
+ let promise: Promise | void
+ const cleanup = $effect.root(() => {
+ promise = fn()
+ })
+ try {
+ // @ts-ignore - this is a hack to wait for the test to finish
+ return await Promise.resolve(promise)
+ } finally {
+ await Promise.resolve(teardown())
+ cleanup()
+ }
+ }
diff --git a/playgrounds/sveltekit/.gitignore b/playgrounds/sveltekit/.gitignore
new file mode 100644
index 0000000000..79518f7164
--- /dev/null
+++ b/playgrounds/sveltekit/.gitignore
@@ -0,0 +1,21 @@
+node_modules
+
+# Output
+.output
+.vercel
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/playgrounds/sveltekit/.npmrc b/playgrounds/sveltekit/.npmrc
new file mode 100644
index 0000000000..b6f27f1359
--- /dev/null
+++ b/playgrounds/sveltekit/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/playgrounds/sveltekit/README.md b/playgrounds/sveltekit/README.md
new file mode 100644
index 0000000000..b5b295070b
--- /dev/null
+++ b/playgrounds/sveltekit/README.md
@@ -0,0 +1,38 @@
+# sv
+
+Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
+
+## Creating a project
+
+If you're seeing this, you've probably already done this step. Congrats!
+
+```bash
+# create a new project in the current directory
+npx sv create
+
+# create a new project in my-app
+npx sv create my-app
+```
+
+## Developing
+
+Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
+
+```bash
+npm run dev
+
+# or start the server and open the app in a new browser tab
+npm run dev -- --open
+```
+
+## Building
+
+To create a production version of your app:
+
+```bash
+npm run build
+```
+
+You can preview the production build with `npm run preview`.
+
+> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
diff --git a/playgrounds/sveltekit/package.json b/playgrounds/sveltekit/package.json
new file mode 100644
index 0000000000..b1b699c854
--- /dev/null
+++ b/playgrounds/sveltekit/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "sveltekit",
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.0.0",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "typescript": "^5.0.0",
+ "vite": "^5.0.3"
+ },
+ "dependencies": {
+ "@tanstack/svelte-query": "https://pkg.pr.new/@tanstack/svelte-query@ccce0b8",
+ "@wagmi/svelte": "workspace:*",
+ "viem": "^2.21.44"
+ }
+}
diff --git a/playgrounds/sveltekit/src/app.d.ts b/playgrounds/sveltekit/src/app.d.ts
new file mode 100644
index 0000000000..c0c081684f
--- /dev/null
+++ b/playgrounds/sveltekit/src/app.d.ts
@@ -0,0 +1,13 @@
+// See https://svelte.dev/docs/kit/types#app.d.ts
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+}
+
+export {}
diff --git a/playgrounds/sveltekit/src/app.html b/playgrounds/sveltekit/src/app.html
new file mode 100644
index 0000000000..77a5ff52c9
--- /dev/null
+++ b/playgrounds/sveltekit/src/app.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/playgrounds/sveltekit/src/lib/index.ts b/playgrounds/sveltekit/src/lib/index.ts
new file mode 100644
index 0000000000..856f2b6c38
--- /dev/null
+++ b/playgrounds/sveltekit/src/lib/index.ts
@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.
diff --git a/playgrounds/sveltekit/src/routes/+layout.svelte b/playgrounds/sveltekit/src/routes/+layout.svelte
new file mode 100644
index 0000000000..306f926abb
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/+layout.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+ {@render children()}
+
+
diff --git a/playgrounds/sveltekit/src/routes/+page.svelte b/playgrounds/sveltekit/src/routes/+page.svelte
new file mode 100644
index 0000000000..755089a86e
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/+page.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playgrounds/sveltekit/src/routes/_components/Account.svelte b/playgrounds/sveltekit/src/routes/_components/Account.svelte
new file mode 100644
index 0000000000..43e57344d0
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/Account.svelte
@@ -0,0 +1,30 @@
+
+
+
+
Account
+
+
+ account: {account.address}
+ {ensName}
+
+ chainId: {account.chainId}
+
+ status: {account.status}
+
+
+ {#if account.status !== 'disconnected'}
+
+ {/if}
+
diff --git a/playgrounds/sveltekit/src/routes/_components/Balance.svelte b/playgrounds/sveltekit/src/routes/_components/Balance.svelte
new file mode 100644
index 0000000000..d69dcb591c
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/Balance.svelte
@@ -0,0 +1,34 @@
+
+
+
+
Balance
+
+
+ Balance (Default Chain):
+ {#if !!default_?.value}{formatEther(default_.value)}{/if}
+
+
+ Balance (Account Chain):
+ {#if !!account_?.value}{formatEther(account_.value)}{/if}
+
+
+ Balance (Optimism Chain):
+ {#if !!optimism_?.value}{formatEther(optimism_.value)}{/if}
+
+
diff --git a/playgrounds/sveltekit/src/routes/_components/BlockNumber.svelte b/playgrounds/sveltekit/src/routes/_components/BlockNumber.svelte
new file mode 100644
index 0000000000..291a43346a
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/BlockNumber.svelte
@@ -0,0 +1,16 @@
+
+
+Block Number
+
+Block Number (Default Chain): {defaultBlock.data?.toString()}
+Block Number (Account Chain): {accountBlock.data?.toString()}
+Block Number (Optimism): {optimismBlock.data?.toString()}
diff --git a/playgrounds/sveltekit/src/routes/_components/Connect.svelte b/playgrounds/sveltekit/src/routes/_components/Connect.svelte
new file mode 100644
index 0000000000..c609e01e3c
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/Connect.svelte
@@ -0,0 +1,18 @@
+
+
+
+
Connect
+ {#each connectors as connector (connector.uid)}
+
+ {/each}
+
{status}
+
{error?.message}
+
diff --git a/playgrounds/sveltekit/src/routes/_components/Connections.svelte b/playgrounds/sveltekit/src/routes/_components/Connections.svelte
new file mode 100644
index 0000000000..6dbe871473
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/Connections.svelte
@@ -0,0 +1,17 @@
+
+
+
+
Connections
+
+ {#each connections as connection (connection.connector.uid)}
+
+
connector {connection.connector.name}
+
accounts: {JSON.stringify(connection.accounts)}
+
chainId: {connection.chainId}
+
+ {/each}
+
diff --git a/playgrounds/sveltekit/src/routes/_components/ReadContract.svelte b/playgrounds/sveltekit/src/routes/_components/ReadContract.svelte
new file mode 100644
index 0000000000..ba7bb55d32
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/ReadContract.svelte
@@ -0,0 +1,17 @@
+
+
+
+
Read Contract
+
Balance: {balance?.toString()} (isLoading: {isLoading})
+
diff --git a/playgrounds/sveltekit/src/routes/_components/ReadContracts.svelte b/playgrounds/sveltekit/src/routes/_components/ReadContracts.svelte
new file mode 100644
index 0000000000..a1dac91895
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/ReadContracts.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+
Read Contract
+
Balance: {balance?.toString()}
+
Owner of Token 69: {ownerOf?.toString()}
+
Total Supply: {totalSupply?.toString()}
+
\ No newline at end of file
diff --git a/playgrounds/sveltekit/src/routes/_components/SendTransaction.svelte b/playgrounds/sveltekit/src/routes/_components/SendTransaction.svelte
new file mode 100644
index 0000000000..7f2bb546d2
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/SendTransaction.svelte
@@ -0,0 +1,50 @@
+
+
+
+
Send Transaction
+
+ {#if hash}
+
Transaction Hash: {hash}
+ {/if}
+ {#if isConfirming}
+ Waiting for confirmation...
+ {/if}
+ {#if isConfirmed}
+ Transaction confirmed.
+ {/if}
+ {#if error}
+
Error: {(error as BaseError).shortMessage || error.message}
+ {/if}
+
diff --git a/playgrounds/sveltekit/src/routes/_components/SignMessage.svelte b/playgrounds/sveltekit/src/routes/_components/SignMessage.svelte
new file mode 100644
index 0000000000..267163fb74
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/SignMessage.svelte
@@ -0,0 +1,23 @@
+
+
+Sign Message
+
+
+
+{#if data}
+ {data}
+{/if}
diff --git a/playgrounds/sveltekit/src/routes/_components/SwitchAccount.svelte b/playgrounds/sveltekit/src/routes/_components/SwitchAccount.svelte
new file mode 100644
index 0000000000..4248343252
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/SwitchAccount.svelte
@@ -0,0 +1,19 @@
+
+
+Switch Account
+
+{#each connectors as connector}
+
+{/each}
diff --git a/playgrounds/sveltekit/src/routes/_components/SwitchChain.svelte b/playgrounds/sveltekit/src/routes/_components/SwitchChain.svelte
new file mode 100644
index 0000000000..0768254f5b
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/SwitchChain.svelte
@@ -0,0 +1,23 @@
+
+
+Switch Chain
+
+{#each chains as chain}
+
+{/each}
+
+{#if error}
+ {error.message}
+{/if}
diff --git a/playgrounds/sveltekit/src/routes/_components/WriteContract.svelte b/playgrounds/sveltekit/src/routes/_components/WriteContract.svelte
new file mode 100644
index 0000000000..f46feff2cb
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/WriteContract.svelte
@@ -0,0 +1,55 @@
+
+
+Write Contract
+
+
+{#if hash}
+ Transaction Hash: {hash}
+{/if}
+{#if isConfirming}
+ Waiting for confirmation...
+{/if}
+{#if isConfirmed}
+ Transaction confirmed.
+{/if}
+{#if error}
+ Error: {error.shortMessage || error.message}
+{/if}
diff --git a/playgrounds/sveltekit/src/routes/_components/contracts.ts b/playgrounds/sveltekit/src/routes/_components/contracts.ts
new file mode 100644
index 0000000000..d7d66754a2
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/_components/contracts.ts
@@ -0,0 +1,202 @@
+export const wagmiContractConfig = {
+ address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
+ abi: [
+ { inputs: [], stateMutability: 'nonpayable', type: 'constructor' },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ name: 'approved',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'ApprovalForAll',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'from',
+ type: 'address',
+ },
+ { indexed: true, name: 'to', type: 'address' },
+ {
+ indexed: true,
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ inputs: [
+ { name: 'to', type: 'address' },
+ { name: 'tokenId', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ name: 'owner', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ name: 'tokenId', type: 'uint256' }],
+ name: 'getApproved',
+ outputs: [{ name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { name: 'owner', type: 'address' },
+ { name: 'operator', type: 'address' },
+ ],
+ name: 'isApprovedForAll',
+ outputs: [{ name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'mint',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],
+ name: 'mint',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ name: 'tokenId', type: 'uint256' }],
+ name: 'ownerOf',
+ outputs: [{ name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { name: 'from', type: 'address' },
+ { name: 'to', type: 'address' },
+ { name: 'tokenId', type: 'uint256' },
+ ],
+ name: 'safeTransferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { name: 'from', type: 'address' },
+ { name: 'to', type: 'address' },
+ { name: 'tokenId', type: 'uint256' },
+ { name: '_data', type: 'bytes' },
+ ],
+ name: 'safeTransferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { name: 'operator', type: 'address' },
+ { name: 'approved', type: 'bool' },
+ ],
+ name: 'setApprovalForAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ name: 'interfaceId', type: 'bytes4' }],
+ name: 'supportsInterface',
+ outputs: [{ name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ name: 'tokenId', type: 'uint256' }],
+ name: 'tokenURI',
+ outputs: [{ name: '', type: 'string' }],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { name: 'from', type: 'address' },
+ { name: 'to', type: 'address' },
+ { name: 'tokenId', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ ],
+} as const
diff --git a/playgrounds/sveltekit/src/routes/index.css b/playgrounds/sveltekit/src/routes/index.css
new file mode 100644
index 0000000000..0733a7ee6b
--- /dev/null
+++ b/playgrounds/sveltekit/src/routes/index.css
@@ -0,0 +1,21 @@
+:root {
+ background-color: #181818;
+ color: rgba(255, 255, 255, 0.87);
+ color-scheme: light dark;
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ font-synthesis: none;
+ font-weight: 400;
+ line-height: 1.5;
+ text-rendering: optimizeLegibility;
+
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ background-color: #f8f8f8;
+ color: #181818;
+ }
+}
diff --git a/playgrounds/sveltekit/static/favicon.png b/playgrounds/sveltekit/static/favicon.png
new file mode 100644
index 0000000000..825b9e65af
Binary files /dev/null and b/playgrounds/sveltekit/static/favicon.png differ
diff --git a/playgrounds/sveltekit/svelte.config.js b/playgrounds/sveltekit/svelte.config.js
new file mode 100644
index 0000000000..e92eb5e127
--- /dev/null
+++ b/playgrounds/sveltekit/svelte.config.js
@@ -0,0 +1,18 @@
+import adapter from '@sveltejs/adapter-auto'
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ // Consult https://svelte.dev/docs/kit/integrations
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+
+ kit: {
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
+ adapter: adapter(),
+ },
+}
+
+export default config
diff --git a/playgrounds/sveltekit/tsconfig.json b/playgrounds/sveltekit/tsconfig.json
new file mode 100644
index 0000000000..f4d0a0e167
--- /dev/null
+++ b/playgrounds/sveltekit/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "moduleResolution": "bundler"
+ }
+ // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
+ // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+ //
+ // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
+ // from the referenced tsconfig.json - TypeScript does not merge them in
+}
diff --git a/playgrounds/sveltekit/vite.config.ts b/playgrounds/sveltekit/vite.config.ts
new file mode 100644
index 0000000000..dd1b8b7fa1
--- /dev/null
+++ b/playgrounds/sveltekit/vite.config.ts
@@ -0,0 +1,6 @@
+import { sveltekit } from '@sveltejs/kit/vite'
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ plugins: [sveltekit()],
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 96f33a1e9f..e460dcd2b6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -58,7 +58,7 @@ importers:
version: 1.1.10
'@vitest/coverage-v8':
specifier: ^2.1.1
- version: 2.1.1(vitest@2.1.1(@types/node@20.12.10)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(msw@2.4.9(typescript@5.5.4))(terser@5.31.0))
+ version: 2.1.1(vitest@2.1.1)
'@vitest/ui':
specifier: ^2.1.1
version: 2.1.1(vitest@2.1.1)
@@ -327,11 +327,63 @@ importers:
specifier: 'catalog:'
version: 3.4.27(typescript@5.5.4)
+ packages/svelte:
+ dependencies:
+ '@wagmi/connectors':
+ specifier: workspace:*
+ version: link:../connectors
+ '@wagmi/core':
+ specifier: workspace:*
+ version: link:../core
+ devDependencies:
+ '@sveltejs/adapter-auto':
+ specifier: ^3.0.0
+ version: 3.3.0(@sveltejs/kit@2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))
+ '@sveltejs/kit':
+ specifier: ^2.0.0
+ version: 2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ '@sveltejs/package':
+ specifier: ^2.0.0
+ version: 2.3.6(svelte@5.0.5)(typescript@5.5.4)
+ '@sveltejs/vite-plugin-svelte':
+ specifier: ^4.0.0
+ version: 4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ '@tanstack/svelte-query':
+ specifier: https://pkg.pr.new/@tanstack/svelte-query@ccce0b8
+ version: https://pkg.pr.new/@tanstack/svelte-query@ccce0b8(svelte@5.0.5)
+ '@wagmi/test':
+ specifier: workspace:*
+ version: link:../test
+ globals:
+ specifier: ^15.0.0
+ version: 15.11.0
+ publint:
+ specifier: ^0.2.0
+ version: 0.2.11
+ svelte:
+ specifier: ^5.0.0
+ version: 5.0.5
+ svelte-check:
+ specifier: ^4.0.0
+ version: 4.0.5(picomatch@4.0.2)(svelte@5.0.5)(typescript@5.5.4)
+ typescript:
+ specifier: ^5.0.0
+ version: 5.5.4
+ vite:
+ specifier: ^5.0.11
+ version: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+ vitest:
+ specifier: ^2.0.4
+ version: 2.1.1(@types/node@20.12.10)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(msw@2.4.9(typescript@5.5.4))(terser@5.31.0)
+
packages/test:
devDependencies:
'@tanstack/react-query':
specifier: 'catalog:'
version: 5.49.2(react@18.3.1)
+ '@tanstack/svelte-query':
+ specifier: ^5.59.20
+ version: 5.59.20(svelte@5.0.5)
'@tanstack/vue-query':
specifier: 'catalog:'
version: 5.49.1(vue@3.4.27(typescript@5.5.4))
@@ -464,6 +516,40 @@ importers:
specifier: ^4.3.2
version: 4.3.2(vue@3.4.27(typescript@5.5.4))
+ playgrounds/sveltekit:
+ dependencies:
+ '@tanstack/svelte-query':
+ specifier: https://pkg.pr.new/@tanstack/svelte-query@ccce0b8
+ version: https://pkg.pr.new/@tanstack/svelte-query@ccce0b8(svelte@5.0.5)
+ '@wagmi/svelte':
+ specifier: workspace:*
+ version: link:../../packages/svelte
+ viem:
+ specifier: ^2.21.44
+ version: 2.21.44(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4)
+ devDependencies:
+ '@sveltejs/adapter-auto':
+ specifier: ^3.0.0
+ version: 3.3.0(@sveltejs/kit@2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))
+ '@sveltejs/kit':
+ specifier: ^2.0.0
+ version: 2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ '@sveltejs/vite-plugin-svelte':
+ specifier: ^4.0.0
+ version: 4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ svelte:
+ specifier: ^5.0.0
+ version: 5.0.5
+ svelte-check:
+ specifier: ^4.0.0
+ version: 4.0.5(picomatch@4.0.2)(svelte@5.0.5)(typescript@5.5.4)
+ typescript:
+ specifier: ^5.0.0
+ version: 5.5.4
+ vite:
+ specifier: ^5.0.3
+ version: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+
playgrounds/vite-core:
dependencies:
'@wagmi/connectors':
@@ -595,6 +681,9 @@ importers:
'@wagmi/core':
specifier: workspace:*
version: link:../packages/core
+ '@wagmi/svelte':
+ specifier: workspace:*
+ version: link:../packages/svelte
'@wagmi/vue':
specifier: workspace:*
version: link:../packages/vue
@@ -1912,9 +2001,6 @@ packages:
'@noble/curves@1.2.0':
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
- '@noble/curves@1.4.0':
- resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==}
-
'@noble/curves@1.6.0':
resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==}
engines: {node: ^14.21.3 || >=16}
@@ -1930,10 +2016,6 @@ packages:
resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
engines: {node: '>= 16'}
- '@noble/hashes@1.4.0':
- resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
- engines: {node: '>= 16'}
-
'@noble/hashes@1.5.0':
resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==}
engines: {node: ^14.21.3 || >=16}
@@ -2640,9 +2722,6 @@ packages:
'@scure/base@1.1.3':
resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==}
- '@scure/base@1.1.7':
- resolution: {integrity: sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==}
-
'@scure/base@1.1.9':
resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==}
@@ -2655,9 +2734,6 @@ packages:
'@scure/bip32@1.3.2':
resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==}
- '@scure/bip32@1.4.0':
- resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==}
-
'@scure/bip32@1.5.0':
resolution: {integrity: sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==}
@@ -2667,9 +2743,6 @@ packages:
'@scure/bip39@1.2.1':
resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==}
- '@scure/bip39@1.3.0':
- resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==}
-
'@scure/bip39@1.4.0':
resolution: {integrity: sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==}
@@ -2829,6 +2902,42 @@ packages:
'@stablelib/x25519@1.0.3':
resolution: {integrity: sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==}
+ '@sveltejs/adapter-auto@3.3.0':
+ resolution: {integrity: sha512-EJZqY7eMM+bdbR898Xt9ufawUHLPJu7w3wPr4Cc+T1iIDf3fufVLWg4C71OluIqsdJqv85E4biKuHo3XXIY0PQ==}
+ peerDependencies:
+ '@sveltejs/kit': ^2.0.0
+
+ '@sveltejs/kit@2.7.2':
+ resolution: {integrity: sha512-bFwrl+0bNr0/DHQZM0INwwSPNYqDjfsKRhUoa6rj9d8tDZzszBrJ3La6/HVFxWGONEigtG+SzHXa1BEa1BLdwA==}
+ engines: {node: '>=18.13'}
+ hasBin: true
+ peerDependencies:
+ '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1
+ svelte: ^4.0.0 || ^5.0.0-next.0
+ vite: ^5.0.3
+
+ '@sveltejs/package@2.3.6':
+ resolution: {integrity: sha512-XzbXWXrdeGbiPj3xICtmh66XrLXApoB/s17LIf0X25bEowAWjEnmukzHVJXaMeSuaFukggdFYoxqcfy4SxucbA==}
+ engines: {node: ^16.14 || >=18}
+ hasBin: true
+ peerDependencies:
+ svelte: ^3.44.0 || ^4.0.0 || ^5.0.0-next.1
+
+ '@sveltejs/vite-plugin-svelte-inspector@3.0.0':
+ resolution: {integrity: sha512-hBxSYW/66989cq9dN248omD/ziskSdIV1NqfuueuAI1z6jGcg14k9Zd98pDIEnoA6wC9kWUGuQ6adzBbWwQyRg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+ peerDependencies:
+ '@sveltejs/vite-plugin-svelte': ^4.0.0-next.0||^4.0.0
+ svelte: ^5.0.0-next.96 || ^5.0.0
+ vite: ^5.0.0
+
+ '@sveltejs/vite-plugin-svelte@4.0.0':
+ resolution: {integrity: sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+ peerDependencies:
+ svelte: ^5.0.0-next.96 || ^5.0.0
+ vite: ^5.0.0
+
'@swc/counter@0.1.3':
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
@@ -2845,6 +2954,13 @@ packages:
'@tanstack/query-core@5.49.1':
resolution: {integrity: sha512-JnC9ndmD1KKS01Rt/ovRUB1tmwO7zkyXAyIxN9mznuJrcNtOrkmOnQqdJF2ib9oHzc2VxHomnEG7xyfo54Npkw==}
+ '@tanstack/query-core@5.59.20':
+ resolution: {integrity: sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==}
+
+ '@tanstack/query-core@https://pkg.pr.new/TanStack/query/@tanstack/query-core@ccce0b8':
+ resolution: {tarball: https://pkg.pr.new/TanStack/query/@tanstack/query-core@ccce0b8}
+ version: 5.56.2
+
'@tanstack/query-devtools@5.0.5':
resolution: {integrity: sha512-xjuOhOrrO50sPoJ4WG9yPe3imQ0Ds/nutnmwdTqjM2ZTIkflh//p7q2iB6IxFBY9sB106h+PULlma8sgTuOKAQ==}
@@ -2873,6 +2989,17 @@ packages:
peerDependencies:
react: ^18.0.0
+ '@tanstack/svelte-query@5.59.20':
+ resolution: {integrity: sha512-DFRTz9i6OXIF+o4GFDRF4g3Q6BSBKWxoahZPcPbCAdXAS4NRhTnVFR4HgEtzlhfoQx8yMJsLXMhDiGUw365HsA==}
+ peerDependencies:
+ svelte: ^3.54.0 || ^4.0.0 || ^5.0.0-next.0
+
+ '@tanstack/svelte-query@https://pkg.pr.new/@tanstack/svelte-query@ccce0b8':
+ resolution: {tarball: https://pkg.pr.new/@tanstack/svelte-query@ccce0b8}
+ version: 5.56.2
+ peerDependencies:
+ svelte: ^5.0.0-next.259
+
'@tanstack/vue-query@5.49.1':
resolution: {integrity: sha512-/nTqP8PNCRzMcqTGEuFQE3ntUD3A+K05r6Dw/0hNwNS3PLEaKUKlxytmAhIoaoloQwbbAghjLyKRQZ+CMWv90A==}
peerDependencies:
@@ -3606,17 +3733,6 @@ packages:
zod:
optional: true
- abitype@1.0.5:
- resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==}
- peerDependencies:
- typescript: '>=5.0.4'
- zod: ^3 >=3.22.0
- peerDependenciesMeta:
- typescript:
- optional: true
- zod:
- optional: true
-
abitype@1.0.6:
resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==}
peerDependencies:
@@ -3637,6 +3753,11 @@ packages:
peerDependencies:
acorn: ^8
+ acorn-typescript@1.4.13:
+ resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==}
+ peerDependencies:
+ acorn: '>=8.9.0'
+
acorn-walk@8.3.2:
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
engines: {node: '>=0.4.0'}
@@ -3651,6 +3772,11 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ acorn@8.13.0:
+ resolution: {integrity: sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
adm-zip@0.4.16:
resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==}
engines: {node: '>=0.3.0'}
@@ -3749,6 +3875,10 @@ packages:
aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
array-union@1.0.2:
resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==}
engines: {node: '>=0.10.0'}
@@ -3801,6 +3931,10 @@ packages:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
b4a@1.6.6:
resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==}
@@ -4198,6 +4332,10 @@ packages:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
+ cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+
copy-anything@3.0.5:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'}
@@ -4378,6 +4516,9 @@ packages:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
+ dedent-js@1.0.1:
+ resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==}
+
dedent@0.7.0:
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
@@ -4452,6 +4593,9 @@ packages:
devalue@4.3.3:
resolution: {integrity: sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg==}
+ devalue@5.1.1:
+ resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
+
devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
@@ -4640,11 +4784,17 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
+ esm-env@1.0.0:
+ resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
+
esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
+ esrap@1.2.2:
+ resolution: {integrity: sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==}
+
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
@@ -4984,6 +5134,13 @@ packages:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
+ globals@15.11.0:
+ resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==}
+ engines: {node: '>=18'}
+
+ globalyzer@0.1.0:
+ resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
+
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
@@ -4996,6 +5153,9 @@ packages:
resolution: {integrity: sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==}
engines: {node: '>=4'}
+ globrex@0.1.2:
+ resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
+
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@@ -5200,6 +5360,9 @@ packages:
immutable@4.3.5:
resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==}
+ import-meta-resolve@4.1.0:
+ resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
+
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -5334,6 +5497,9 @@ packages:
is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
+ is-reference@3.0.2:
+ resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
+
is-ssh@1.4.0:
resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==}
@@ -5520,6 +5686,10 @@ packages:
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
engines: {node: '>=6'}
+ kleur@4.1.5:
+ resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
+ engines: {node: '>=6'}
+
klona@2.0.6:
resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==}
engines: {node: '>= 8'}
@@ -5574,6 +5744,9 @@ packages:
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
+ locate-character@3.0.0:
+ resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+
locate-path@2.0.0:
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
engines: {node: '>=4'}
@@ -5638,6 +5811,9 @@ packages:
loupe@3.1.1:
resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
+ lower-case@2.0.2:
+ resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
+
lru-cache@10.2.2:
resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
engines: {node: 14 || >=16.14}
@@ -6073,6 +6249,9 @@ packages:
xml2js:
optional: true
+ no-case@3.0.4:
+ resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+
node-addon-api@2.0.2:
resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==}
@@ -6308,6 +6487,14 @@ packages:
outvariant@1.4.3:
resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==}
+ ox@0.1.2:
+ resolution: {integrity: sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww==}
+ peerDependencies:
+ typescript: '>=5.4.0'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
p-filter@2.1.0:
resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
engines: {node: '>=8'}
@@ -6398,6 +6585,9 @@ packages:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
+ pascal-case@3.1.2:
+ resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
+
path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
@@ -7070,6 +7260,9 @@ packages:
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+ set-cookie-parser@2.7.1:
+ resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
@@ -7168,6 +7361,10 @@ packages:
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
engines: {node: '>= 10'}
+ sirv@3.0.0:
+ resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==}
+ engines: {node: '>=18'}
+
sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
@@ -7442,6 +7639,24 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ svelte-check@4.0.5:
+ resolution: {integrity: sha512-icBTBZ3ibBaywbXUat3cK6hB5Du+Kq9Z8CRuyLmm64XIe2/r+lQcbuBx/IQgsbrC+kT2jQ0weVpZSSRIPwB6jQ==}
+ engines: {node: '>= 18.0.0'}
+ hasBin: true
+ peerDependencies:
+ svelte: ^4.0.0 || ^5.0.0-next.0
+ typescript: '>=5.0.0'
+
+ svelte2tsx@0.7.22:
+ resolution: {integrity: sha512-hf55ujq17ufVpDQlJzaQfRr9EjlLIwGmFlpKq4uYrQAQFw/99q1OcVYyBT6568iJySgBUY9PdccURrORmfetmQ==}
+ peerDependencies:
+ svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0
+ typescript: ^4.9.4 || ^5.0.0
+
+ svelte@5.0.5:
+ resolution: {integrity: sha512-f4WBlP5g8W6pEoDfx741lewMlemy+LIGpEqjGPWqnHVP92wqlQXl87U5O5Bi2tkSUrO95OxOoqwU8qlqiHmFKA==}
+ engines: {node: '>=18'}
+
svg-tags@1.0.0:
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
@@ -7503,6 +7718,9 @@ packages:
thread-stream@0.15.2:
resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==}
+ tiny-glob@0.2.9:
+ resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
+
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -7864,16 +8082,16 @@ packages:
typescript:
optional: true
- viem@2.17.0:
- resolution: {integrity: sha512-+gaVlsfDsHL1oYdjpatdRxW1WK/slLYVvpOws3fEdLfQFUToezKI6YLC9l1g2uKm4Hg3OdGX1KQy/G7/58tTKQ==}
+ viem@2.21.28:
+ resolution: {integrity: sha512-CbS2Ldq+SdZYYSG+P4oNLi1s6xq7JnZoJsIkMhFcZUMRz3w2J1OvC1izUp6E1/Zp/XXo3wt6g/Ae+f3SGzup2A==}
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
typescript:
optional: true
- viem@2.21.28:
- resolution: {integrity: sha512-CbS2Ldq+SdZYYSG+P4oNLi1s6xq7JnZoJsIkMhFcZUMRz3w2J1OvC1izUp6E1/Zp/XXo3wt6g/Ae+f3SGzup2A==}
+ viem@2.21.44:
+ resolution: {integrity: sha512-oyLTCt7OQUetQN2m9KPNgSA//MzpnQLABAyglPKh+fAypU8cTT/hC5UyLQvaYt4WPg6dkbKOxfsahV4739pu9w==}
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
@@ -8000,6 +8218,14 @@ packages:
terser:
optional: true
+ vitefu@1.0.3:
+ resolution: {integrity: sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0-beta.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
vitepress@1.5.0:
resolution: {integrity: sha512-q4Q/G2zjvynvizdB3/bupdYkCJe2umSAMv9Ju4d92E6/NXJ59z70xB0q5p/4lpRyAwflDsbwy1mLV9Q5+nlB+g==}
hasBin: true
@@ -8353,6 +8579,9 @@ packages:
zhead@2.2.4:
resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==}
+ zimmerframe@1.1.2:
+ resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
+
zip-stream@6.0.1:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
engines: {node: '>= 14'}
@@ -9860,10 +10089,6 @@ snapshots:
dependencies:
'@noble/hashes': 1.3.2
- '@noble/curves@1.4.0':
- dependencies:
- '@noble/hashes': 1.4.0
-
'@noble/curves@1.6.0':
dependencies:
'@noble/hashes': 1.5.0
@@ -9874,8 +10099,6 @@ snapshots:
'@noble/hashes@1.3.2': {}
- '@noble/hashes@1.4.0': {}
-
'@noble/hashes@1.5.0': {}
'@noble/secp256k1@1.7.1': {}
@@ -10771,7 +10994,7 @@ snapshots:
'@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4)':
dependencies:
'@safe-global/safe-gateway-typescript-sdk': 3.8.0(encoding@0.1.13)
- viem: 2.17.0(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4)
+ viem: 2.21.28(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4)
transitivePeerDependencies:
- bufferutil
- encoding
@@ -10787,8 +11010,6 @@ snapshots:
'@scure/base@1.1.3': {}
- '@scure/base@1.1.7': {}
-
'@scure/base@1.1.9': {}
'@scure/bip32@1.1.5':
@@ -10801,7 +11022,7 @@ snapshots:
dependencies:
'@noble/curves': 1.1.0
'@noble/hashes': 1.3.2
- '@scure/base': 1.1.7
+ '@scure/base': 1.1.9
'@scure/bip32@1.3.2':
dependencies:
@@ -10809,17 +11030,11 @@ snapshots:
'@noble/hashes': 1.3.2
'@scure/base': 1.1.3
- '@scure/bip32@1.4.0':
- dependencies:
- '@noble/curves': 1.4.0
- '@noble/hashes': 1.4.0
- '@scure/base': 1.1.7
-
'@scure/bip32@1.5.0':
dependencies:
'@noble/curves': 1.6.0
'@noble/hashes': 1.5.0
- '@scure/base': 1.1.7
+ '@scure/base': 1.1.9
'@scure/bip39@1.1.1':
dependencies:
@@ -10831,11 +11046,6 @@ snapshots:
'@noble/hashes': 1.3.2
'@scure/base': 1.1.3
- '@scure/bip39@1.3.0':
- dependencies:
- '@noble/hashes': 1.4.0
- '@scure/base': 1.1.7
-
'@scure/bip39@1.4.0':
dependencies:
'@noble/hashes': 1.5.0
@@ -11076,6 +11286,62 @@ snapshots:
'@stablelib/random': 1.0.2
'@stablelib/wipe': 1.0.1
+ '@sveltejs/adapter-auto@3.3.0(@sveltejs/kit@2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))':
+ dependencies:
+ '@sveltejs/kit': 2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ import-meta-resolve: 4.1.0
+
+ '@sveltejs/kit@2.7.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))':
+ dependencies:
+ '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ '@types/cookie': 0.6.0
+ cookie: 0.6.0
+ devalue: 5.1.1
+ esm-env: 1.0.0
+ import-meta-resolve: 4.1.0
+ kleur: 4.1.5
+ magic-string: 0.30.11
+ mrmime: 2.0.0
+ sade: 1.8.1
+ set-cookie-parser: 2.7.1
+ sirv: 3.0.0
+ svelte: 5.0.5
+ tiny-glob: 0.2.9
+ vite: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+
+ '@sveltejs/package@2.3.6(svelte@5.0.5)(typescript@5.5.4)':
+ dependencies:
+ chokidar: 4.0.1
+ kleur: 4.1.5
+ sade: 1.8.1
+ semver: 7.6.2
+ svelte: 5.0.5
+ svelte2tsx: 0.7.22(svelte@5.0.5)(typescript@5.5.4)
+ transitivePeerDependencies:
+ - typescript
+
+ '@sveltejs/vite-plugin-svelte-inspector@3.0.0(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))':
+ dependencies:
+ '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ debug: 4.3.7
+ svelte: 5.0.5
+ vite: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))':
+ dependencies:
+ '@sveltejs/vite-plugin-svelte-inspector': 3.0.0(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)))(svelte@5.0.5)(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ debug: 4.3.7
+ deepmerge: 4.3.1
+ kleur: 4.1.5
+ magic-string: 0.30.12
+ svelte: 5.0.5
+ vite: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+ vitefu: 1.0.3(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0))
+ transitivePeerDependencies:
+ - supports-color
+
'@swc/counter@0.1.3': {}
'@swc/helpers@0.5.5':
@@ -11091,6 +11357,10 @@ snapshots:
'@tanstack/query-core@5.49.1': {}
+ '@tanstack/query-core@5.59.20': {}
+
+ '@tanstack/query-core@https://pkg.pr.new/TanStack/query/@tanstack/query-core@ccce0b8': {}
+
'@tanstack/query-devtools@5.0.5': {}
'@tanstack/query-persist-client-core@5.0.5':
@@ -11121,6 +11391,16 @@ snapshots:
'@tanstack/query-core': 5.49.1
react: 18.3.1
+ '@tanstack/svelte-query@5.59.20(svelte@5.0.5)':
+ dependencies:
+ '@tanstack/query-core': 5.59.20
+ svelte: 5.0.5
+
+ '@tanstack/svelte-query@https://pkg.pr.new/@tanstack/svelte-query@ccce0b8(svelte@5.0.5)':
+ dependencies:
+ '@tanstack/query-core': https://pkg.pr.new/TanStack/query/@tanstack/query-core@ccce0b8
+ svelte: 5.0.5
+
'@tanstack/vue-query@5.49.1(vue@3.4.27(typescript@5.5.4))':
dependencies:
'@tanstack/match-sorter-utils': 8.15.1
@@ -11574,7 +11854,7 @@ snapshots:
vite: 5.4.10(@types/node@20.12.10)(terser@5.31.0)
vue: 3.5.12(typescript@5.6.1-rc)
- '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@20.12.10)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(msw@2.4.9(typescript@5.5.4))(terser@5.31.0))':
+ '@vitest/coverage-v8@2.1.1(vitest@2.1.1)':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
@@ -12524,11 +12804,6 @@ snapshots:
typescript: 5.5.4
zod: 3.22.2
- abitype@1.0.5(typescript@5.5.4)(zod@3.22.4):
- optionalDependencies:
- typescript: 5.5.4
- zod: 3.22.4
-
abitype@1.0.6(typescript@5.5.4)(zod@3.22.4):
optionalDependencies:
typescript: 5.5.4
@@ -12542,12 +12817,18 @@ snapshots:
dependencies:
acorn: 8.11.3
+ acorn-typescript@1.4.13(acorn@8.13.0):
+ dependencies:
+ acorn: 8.13.0
+
acorn-walk@8.3.2: {}
acorn@8.10.0: {}
acorn@8.11.3: {}
+ acorn@8.13.0: {}
+
adm-zip@0.4.16: {}
agent-base@6.0.2:
@@ -12661,6 +12942,8 @@ snapshots:
dependencies:
dequal: 2.0.3
+ aria-query@5.3.2: {}
+
array-union@1.0.2:
dependencies:
array-uniq: 1.0.3
@@ -12713,6 +12996,8 @@ snapshots:
available-typed-arrays@1.0.5: {}
+ axobject-query@4.1.0: {}
+
b4a@1.6.6: {}
balanced-match@1.0.2: {}
@@ -13124,6 +13409,8 @@ snapshots:
cookie@0.5.0: {}
+ cookie@0.6.0: {}
+
copy-anything@3.0.5:
dependencies:
is-what: 4.1.16
@@ -13302,6 +13589,8 @@ snapshots:
decode-uri-component@0.2.2: {}
+ dedent-js@1.0.1: {}
+
dedent@0.7.0: {}
deep-eql@5.0.2: {}
@@ -13347,6 +13636,8 @@ snapshots:
devalue@4.3.3: {}
+ devalue@5.1.1: {}
+
devlop@1.1.0:
dependencies:
dequal: 2.0.3
@@ -13598,8 +13889,15 @@ snapshots:
escape-string-regexp@5.0.0: {}
+ esm-env@1.0.0: {}
+
esprima@4.0.1: {}
+ esrap@1.2.2:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@types/estree': 1.0.5
+
estree-walker@2.0.2: {}
estree-walker@3.0.3:
@@ -14052,6 +14350,10 @@ snapshots:
globals@11.12.0: {}
+ globals@15.11.0: {}
+
+ globalyzer@0.1.0: {}
+
globby@11.1.0:
dependencies:
array-union: 2.1.0
@@ -14079,6 +14381,8 @@ snapshots:
pify: 3.0.0
slash: 1.0.0
+ globrex@0.1.2: {}
+
gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.1
@@ -14331,6 +14635,8 @@ snapshots:
immutable@4.3.5: {}
+ import-meta-resolve@4.1.0: {}
+
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
@@ -14441,6 +14747,10 @@ snapshots:
dependencies:
'@types/estree': 1.0.5
+ is-reference@3.0.2:
+ dependencies:
+ '@types/estree': 1.0.5
+
is-ssh@1.4.0:
dependencies:
protocols: 2.0.1
@@ -14491,10 +14801,6 @@ snapshots:
dependencies:
ws: 8.13.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
- isows@1.0.4(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
- dependencies:
- ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)
-
isows@1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
dependencies:
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
@@ -14604,6 +14910,8 @@ snapshots:
kleur@3.0.3: {}
+ kleur@4.1.5: {}
+
klona@2.0.6: {}
knip@5.30.6(@types/node@20.12.10)(typescript@5.5.4):
@@ -14690,6 +14998,8 @@ snapshots:
mlly: 1.4.2
pkg-types: 1.0.3
+ locate-character@3.0.0: {}
+
locate-path@2.0.0:
dependencies:
p-locate: 2.0.0
@@ -14747,6 +15057,10 @@ snapshots:
dependencies:
get-func-name: 2.0.2
+ lower-case@2.0.2:
+ dependencies:
+ tslib: 2.5.0
+
lru-cache@10.2.2: {}
lru-cache@10.4.3: {}
@@ -15436,6 +15750,11 @@ snapshots:
- supports-color
- uWebSockets.js
+ no-case@3.0.4:
+ dependencies:
+ lower-case: 2.0.2
+ tslib: 2.5.0
+
node-addon-api@2.0.2: {}
node-addon-api@7.0.0: {}
@@ -15916,6 +16235,20 @@ snapshots:
outvariant@1.4.3: {}
+ ox@0.1.2(typescript@5.5.4)(zod@3.22.4):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.0
+ '@noble/curves': 1.6.0
+ '@noble/hashes': 1.5.0
+ '@scure/bip32': 1.5.0
+ '@scure/bip39': 1.4.0
+ abitype: 1.0.6(typescript@5.5.4)(zod@3.22.4)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.5.4
+ transitivePeerDependencies:
+ - zod
+
p-filter@2.1.0:
dependencies:
p-map: 2.1.0
@@ -16014,6 +16347,11 @@ snapshots:
parseurl@1.3.3: {}
+ pascal-case@3.1.2:
+ dependencies:
+ no-case: 3.0.4
+ tslib: 2.5.0
+
path-browserify@1.0.1: {}
path-exists@3.0.0: {}
@@ -16704,6 +17042,8 @@ snapshots:
set-blocking@2.0.0: {}
+ set-cookie-parser@2.7.1: {}
+
setimmediate@1.0.5: {}
setprototypeof@1.2.0: {}
@@ -16806,6 +17146,12 @@ snapshots:
mrmime: 2.0.0
totalist: 3.0.1
+ sirv@3.0.0:
+ dependencies:
+ '@polka/url': 1.0.0-next.25
+ mrmime: 2.0.0
+ totalist: 3.0.1
+
sisteransi@1.0.5: {}
skin-tone@2.0.0:
@@ -17057,6 +17403,41 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ svelte-check@4.0.5(picomatch@4.0.2)(svelte@5.0.5)(typescript@5.5.4):
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ chokidar: 4.0.1
+ fdir: 6.3.0(picomatch@4.0.2)
+ picocolors: 1.1.0
+ sade: 1.8.1
+ svelte: 5.0.5
+ typescript: 5.5.4
+ transitivePeerDependencies:
+ - picomatch
+
+ svelte2tsx@0.7.22(svelte@5.0.5)(typescript@5.5.4):
+ dependencies:
+ dedent-js: 1.0.1
+ pascal-case: 3.1.2
+ svelte: 5.0.5
+ typescript: 5.5.4
+
+ svelte@5.0.5:
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@types/estree': 1.0.5
+ acorn: 8.13.0
+ acorn-typescript: 1.4.13(acorn@8.13.0)
+ aria-query: 5.3.2
+ axobject-query: 4.1.0
+ esm-env: 1.0.0
+ esrap: 1.2.2
+ is-reference: 3.0.2
+ locate-character: 3.0.0
+ magic-string: 0.30.11
+ zimmerframe: 1.1.2
+
svg-tags@1.0.0: {}
svgo@3.3.2:
@@ -17133,6 +17514,11 @@ snapshots:
dependencies:
real-require: 0.1.0
+ tiny-glob@0.2.9:
+ dependencies:
+ globalyzer: 0.1.0
+ globrex: 0.1.2
+
tiny-invariant@1.3.3: {}
tinybench@2.9.0: {}
@@ -17597,16 +17983,17 @@ snapshots:
- utf-8-validate
- zod
- viem@2.17.0(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4):
+ viem@2.21.28(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4):
dependencies:
- '@adraffy/ens-normalize': 1.10.0
- '@noble/curves': 1.4.0
- '@noble/hashes': 1.4.0
- '@scure/bip32': 1.4.0
- '@scure/bip39': 1.3.0
- abitype: 1.0.5(typescript@5.5.4)(zod@3.22.4)
- isows: 1.0.4(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))
- ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)
+ '@adraffy/ens-normalize': 1.11.0
+ '@noble/curves': 1.6.0
+ '@noble/hashes': 1.5.0
+ '@scure/bip32': 1.5.0
+ '@scure/bip39': 1.4.0
+ abitype: 1.0.6(typescript@5.5.4)(zod@3.22.4)
+ isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))
+ webauthn-p256: 0.0.10
+ ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
optionalDependencies:
typescript: 5.5.4
transitivePeerDependencies:
@@ -17614,15 +18001,15 @@ snapshots:
- utf-8-validate
- zod
- viem@2.21.28(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4):
+ viem@2.21.44(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4):
dependencies:
- '@adraffy/ens-normalize': 1.11.0
'@noble/curves': 1.6.0
'@noble/hashes': 1.5.0
'@scure/bip32': 1.5.0
'@scure/bip39': 1.4.0
abitype: 1.0.6(typescript@5.5.4)(zod@3.22.4)
isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))
+ ox: 0.1.2(typescript@5.5.4)(zod@3.22.4)
webauthn-p256: 0.0.10
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
optionalDependencies:
@@ -17639,7 +18026,7 @@ snapshots:
vite-node@1.6.0(@types/node@20.12.10)(terser@5.31.0):
dependencies:
cac: 6.7.14
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.7
pathe: 1.1.2
picocolors: 1.1.0
vite: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
@@ -17766,6 +18153,10 @@ snapshots:
fsevents: 2.3.3
terser: 5.31.0
+ vitefu@1.0.3(vite@5.2.11(@types/node@20.12.10)(terser@5.31.0)):
+ optionalDependencies:
+ vite: 5.2.11(@types/node@20.12.10)(terser@5.31.0)
+
vitepress@1.5.0(@algolia/client-search@5.12.0)(@types/node@20.12.10)(@types/react@18.3.1)(change-case@5.4.4)(idb-keyval@6.2.1)(postcss@8.4.47)(qrcode@1.5.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.31.0)(typescript@5.6.1-rc):
dependencies:
'@docsearch/css': 3.6.3
@@ -18218,6 +18609,8 @@ snapshots:
zhead@2.2.4: {}
+ zimmerframe@1.1.2: {}
+
zip-stream@6.0.1:
dependencies:
archiver-utils: 5.0.2
diff --git a/site/.vitepress/config.ts b/site/.vitepress/config.ts
index 77f242cb09..088c193243 100644
--- a/site/.vitepress/config.ts
+++ b/site/.vitepress/config.ts
@@ -80,6 +80,7 @@ export default defineConfig({
nav: [
{ text: 'React', link: '/react/getting-started' },
{ text: 'Vue', link: '/vue/getting-started' },
+ { text: 'Svelte', link: '/svelte/getting-started' },
{ text: 'Core', link: '/core/getting-started' },
{ text: 'CLI', link: '/cli/getting-started' },
// { text: 'Examples', link: '/examples/connect-wallet' },
diff --git a/site/.vitepress/sidebar.ts b/site/.vitepress/sidebar.ts
index da4d4bf5e2..f3ce18f8d4 100644
--- a/site/.vitepress/sidebar.ts
+++ b/site/.vitepress/sidebar.ts
@@ -629,6 +629,15 @@ export function getSidebar() {
],
},
],
+ '/svelte': [
+ {
+ text: 'Introduction',
+ items: [
+ { text: 'Getting Started', link: '/svelte/getting-started' },
+ { text: 'Reactivity', link: '/svelte/reactivity' },
+ ],
+ },
+ ],
'/core': [
{
text: 'Introduction',
diff --git a/site/package.json b/site/package.json
index f683675231..89f384fc1f 100644
--- a/site/package.json
+++ b/site/package.json
@@ -15,6 +15,7 @@
"@types/react": "catalog:",
"@wagmi/connectors": "workspace:*",
"@wagmi/core": "workspace:*",
+ "@wagmi/svelte": "workspace:*",
"@wagmi/vue": "workspace:*",
"abitype": "*",
"nuxt": "^3.11.2",
diff --git a/site/snippets/svelte/config.ts b/site/snippets/svelte/config.ts
new file mode 100644
index 0000000000..8777811c8a
--- /dev/null
+++ b/site/snippets/svelte/config.ts
@@ -0,0 +1,10 @@
+import { http, createConfig } from '@wagmi/svelte'
+import { mainnet, sepolia } from '@wagmi/svelte/chains'
+
+export const config = createConfig({
+ chains: [mainnet, sepolia],
+ transports: {
+ [mainnet.id]: http(),
+ [sepolia.id]: http(),
+ },
+})
diff --git a/site/svelte/getting-started.md b/site/svelte/getting-started.md
new file mode 100644
index 0000000000..dd61841f00
--- /dev/null
+++ b/site/svelte/getting-started.md
@@ -0,0 +1,139 @@
+
+
+# Getting Started
+
+## Overview
+
+Wagmi is a Svelte library for Ethereum.
+
+## Manual Installation
+
+To manually add Wagmi to your project, install the required packages.
+
+::: code-group
+```bash-vue [pnpm]
+pnpm add @wagmi/svelte viem@{{viemVersion}} {{tanstackQuery}}
+```
+
+```bash-vue [npm]
+npm install @wagmi/svelte viem@{{viemVersion}} {{tanstackQuery}}
+```
+
+```bash-vue [yarn]
+yarn add @wagmi/svelte viem@{{viemVersion}} {{tanstackQuery}}
+```
+
+```bash-vue [bun]
+bun add @wagmi/svelte viem@{{viemVersion}} {{tanstackQuery}}
+```
+:::
+
+- [Viem](https://viem.sh) is a TypeScript interface for Ethereum that performs blockchain operations.
+- [TanStack Query](https://tanstack.com/query/v5) is an async state manager that handles requests, caching, and more.
+
+### Create Config
+
+Create and export a new Wagmi config using `createConfig`.
+
+::: code-group
+<<< @/snippets/svelte/config.ts[config.ts]
+:::
+
+### Wrap App in Context Provider
+
+Wrap your app in the `WagmiProvider` component and pass the `config` you created earlier to the `config` property. You may do this in the `+layout.svelte` file, or in another component for more fine-grained control.
+
+::: code-group
+```svelte [+layout.svelte]
+
+
+ // [!code focus]
+ {@render children()} // [!code focus]
+ // [!code focus]
+```
+<<< @/snippets/svelte/config.ts[config.ts]
+:::
+
+### Setup TanStack Query
+
+Inside the `WagmiProvider`, wrap your app in a TanStack Query Context Provider, e.g. `QueryClientProvider`, and pass a new `QueryClient` instance to the `client` property.
+
+::: code-group
+```svelte [+layout.svelte]
+
+
+
+ // [!code focus]
+ {@render children()} // [!code focus]
+ // [!code focus]
+
+```
+<<< @/snippets/react/config.ts[config.ts]
+:::
+
+Check out the [TanStack Query docs](https://tanstack.com/query/latest/docs/framework/svelte) to learn about the library, APIs, and more.
+
+### Use Wagmi
+
+Now that everything is set up, every component inside the Wagmi and TanStack Query Providers can use Wagmi React Hooks.
+
+::: code-group
+```svelte [+page.svelte]
+
+
+{#if ensName.status === 'loading'}
+ Loading ENS name
+{:else if ensName.status === 'error'}
+ Error fetching ENS name: {ensName.error.message}
+{:else}
+ ENS name: {ensName.data}
+{/if}
+```
+
+```svelte [+layout.svelte]
+
+
+
+
+ {@render children()}
+
+
+```
+<<< @/snippets/svelte/config.ts[config.ts]
+:::
+
+::: danger
+Reactivity in Svelte is different than other frameworks! I would highly suggest you read the page on [Reactivity](./reactivity.md)
+:::
diff --git a/site/svelte/reactivity.md b/site/svelte/reactivity.md
new file mode 100644
index 0000000000..0ff86c6bb0
--- /dev/null
+++ b/site/svelte/reactivity.md
@@ -0,0 +1,33 @@
+# Reactivity
+
+To ensure Svelte Runes are reactive, we have opted to return a function from each hook. This pairs very well with the [`$derived.by` rune](https://svelte.dev/docs/svelte/$derived#$derived.by):
+
+```svelte
+
+
+Your address: {account.address}
+```
+
+::: tip
+If you don't need the return value (such as for `useWatchBlockNumber()`), there is no need to wrap the function in `$derived.by`.
+:::
+
+Similarly, if you simply pass an object into the function, it will not be reactive. We have chosen to use Solid-style parameters, meaning you pass arguments as functions:
+
+```svelte
+
+
+Vitalik's ENS: {vitalikEns}
+```
diff --git a/vitest.workspace.ts b/vitest.workspace.ts
index 0c187c0401..c68e09ea8b 100644
--- a/vitest.workspace.ts
+++ b/vitest.workspace.ts
@@ -9,6 +9,7 @@ const alias = {
'@wagmi/core': path.resolve(__dirname, './packages/core/src/exports'),
'@wagmi/test': path.resolve(__dirname, './packages/test/src/exports'),
'@wagmi/vue': path.resolve(__dirname, './packages/vue/src/exports'),
+ '@wagmi/svelte': path.resolve(__dirname, './packages/svelte/src/exports'),
wagmi: path.resolve(__dirname, './packages/react/src/exports'),
}
@@ -68,6 +69,7 @@ export default defineWorkspace([
},
resolve: { alias },
},
+ './packages/svelte',
{
test: {
name: 'react-register',