Repository: ithacaxyz/porto
Pull request #238: feat: more docs
Author: login: o-az
Created: 2025-05-15T19:38:05Z | Merged: 2025-05-22T13:54:56Z



Diff:
diff --git a/apps/docs/pages/sdk/api/chains.mdx b/apps/docs/pages/sdk/api/chains.mdx
new file mode 100644
index 000000000..5e20d6ca8
--- /dev/null
+++ b/apps/docs/pages/sdk/api/chains.mdx
@@ -0,0 +1,51 @@
+# Chains
+
+Porto chains are re-exported from [Viem](https://viem.sh/docs/chains/introduction).
+
+## Usage
+
+```ts twoslash
+import { Chains } from 'porto'
+
+const chain = Chains.baseSepolia
+```
+
+## Supported Chains
+
+Porto currently supports the following chains:
+
+| Chain | Value |
+| ----- | ------ |
+| Base | 🚧 |
+| Base Sepolia | `Chains.baseSepolia` |
+
+## Wagmi Usage
+
+Chains can be directly used with [Wagmi's Config](https://wagmi.sh/react/api/createConfig)
+
+```ts twoslash
+import { Chains } from 'porto'
+import { porto } from 'porto/wagmi'
+import { createConfig, http } from 'wagmi'
+
+export const config = createConfig({
+  chains: [Chains.baseSepolia], // [!code hl]
+  connectors: [porto()],
+  transports: {
+    [Chains.baseSepolia.id]: http() // [!code hl]
+  }
+})
+```
+
+## Vanilla Usage
+
+Chains can be used directly with the [`Porto.create`](/sdk/api/porto/create#chains) method.
+
+```ts twoslash
+import { Porto, Chains } from 'porto'
+
+// Create a Porto instance that uses Base Sepolia
+const porto = Porto.create({
+  chains: [Chains.baseSepolia] // [!code hl]
+})
+```
\ No newline at end of file
diff --git a/apps/docs/pages/sdk/api/dialog/iframe.mdx b/apps/docs/pages/sdk/api/dialog/iframe.mdx
new file mode 100644
index 000000000..d63e686e4
--- /dev/null
+++ b/apps/docs/pages/sdk/api/dialog/iframe.mdx
@@ -0,0 +1,26 @@
+import { TryItOut } from '../../../../components/TryItOut'
+
+# `Dialog.iframe`
+
+The [`iframe`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe) dialog is Porto's default rendering option that displays the account interface in a modal dialog using an `iframe`.
+
+## Usage
+
+```ts twoslash
+import { Porto, Dialog, Mode } from 'porto'
+
+const porto = Porto.create({
+  mode: Mode.dialog({
+    renderer: Dialog.iframe()
+  })
+})
+```
+
+## Behavior
+
+- The dialog opens automatically when a request requires user confirmation
+- The dialog closes when:
+  - The user completes the requested action
+  - The user clicks outside the dialog
+  - The user presses the Escape key
+- When the dialog closes due to a user cancellation, all pending requests will be rejected with a `UserRejectedRequestError`
diff --git a/apps/docs/pages/sdk/api/storage/idb.mdx b/apps/docs/pages/sdk/api/storage/idb.mdx
new file mode 100644
index 000000000..2e01ce19e
--- /dev/null
+++ b/apps/docs/pages/sdk/api/storage/idb.mdx
@@ -0,0 +1,15 @@
+# `Storage.idb`
+
+The [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) storage backend for Porto.
+
+Porto uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) as the default storage in browser environments.
+
+## Usage
+
+```ts twoslash
+import { Porto, Storage } from 'porto'
+
+const porto = Porto.create({
+  storage: Storage.idb()
+})
+```
diff --git a/apps/docs/pages/sdk/api/storage/localstorage.mdx b/apps/docs/pages/sdk/api/storage/localstorage.mdx
new file mode 100644
index 000000000..a37e91b59
--- /dev/null
+++ b/apps/docs/pages/sdk/api/storage/localstorage.mdx
@@ -0,0 +1,14 @@
+# `Storage.localStorage`
+
+The [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) storage for Porto.
+
+## Usage
+
+```ts twoslash
+import { Porto, Storage } from 'porto'
+
+const porto = Porto.create({
+  storage: Storage.localStorage()
+})
+```
+
diff --git a/apps/docs/pages/sdk/api/storage/memory.mdx b/apps/docs/pages/sdk/api/storage/memory.mdx
new file mode 100644
index 000000000..e7e88b0bb
--- /dev/null
+++ b/apps/docs/pages/sdk/api/storage/memory.mdx
@@ -0,0 +1,21 @@
+# `Storage.memory`
+
+The memory storage for Porto, which stores data in-memory with no persistence.
+Under the hood, `Storage.memory` uses a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) to store data.
+
+Porto uses `Storage.memory` as the default storage in non-browser environments.
+
+## Usage
+
+```ts twoslash
+import { Porto, Storage } from 'porto'
+
+const porto = Porto.create({
+  storage: Storage.memory()
+})
+```
+
+## When to use `Storage.memory`
+
+- In browserless or serverless environments such as [Cloudflare Workers](https://developers.cloudflare.com/workers/) and [AWS Lambda](https://docs.aws.amazon.com/lambda/).
+- For testing purposes.
diff --git a/apps/docs/pages/sdk/wagmi/connect.mdx b/apps/docs/pages/sdk/wagmi/connect.mdx
new file mode 100644
index 000000000..6d163291f
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/connect.mdx
@@ -0,0 +1,135 @@
+# `connect`
+
+VanillaJS action for connecting an account. Uses [`wallet_connect`](/sdk/rpc/wallet_connect) under the hood.
+
+## Usage
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { Actions, porto } from 'porto/wagmi'
+import { config } from './config'
+
+const result = await Actions.connect(config, { // [!code focus]
+  connector: porto(), // [!code focus]
+}) // [!code focus]
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+### Grant Permissions
+
+You can grant permissions for an application to perform actions on behalf of the account by providing the `grantPermissions` parameter.
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { Actions, porto } from 'porto/wagmi'
+import { parseEther, toHex } from 'viem'
+import { config } from './config'
+
+const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+const result = await Actions.connect(config, {
+  connector: porto(),
+  grantPermissions: { // [!code focus]
+    expiry: Math.floor(Date.now() / 1_000) + 60 * 60, // 1 hour // [!code focus]
+    permissions: { // [!code focus]
+      calls: [{ // [!code focus]
+        signature: 'transfer(address,uint256)', // [!code focus]
+        to: token, // [!code focus]
+      }], // [!code focus]
+      spend: [{ // [!code focus]
+        limit: toHex(parseEther('50')), // 50 EXP // [!code focus]
+        period: 'day', // [!code focus]
+        token: token, // [!code focus]
+      }], // [!code focus]
+    }, // [!code focus]
+  }, // [!code focus]
+})
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+## Parameters
+
+### connector
+
+`Connector | CreateConnectorFn`
+
+The connector to use for the connection.
+
+### chainId
+
+`number | undefined`
+
+Chain ID to connect to.
+
+### force
+
+`boolean`
+
+Force connect even if already connected to the connector.
+
+### grantPermissions
+
+Permissions to grant to the account.
+
+```ts
+type GrantPermissions = {
+  /** Expiry timestamp for the permissions */
+  expiry: number
+
+  /** Key to grant permissions to. Defaults to a wallet-managed key. */
+  key?: {
+    /** Public key. Accepts an address for `address` & `secp256k1` types. */
+    publicKey?: `0x${string}`
+    /** Key type. */
+    type?: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
+  }
+
+  /** Permissions to grant */
+  permissions: {
+    /** Call permissions */
+    calls: {
+      /** Function signature or 4-byte signature */
+      signature?: string
+      /** Authorized target address */
+      to?: `0x${string}`
+    }[]
+
+    /** Spend permissions */
+    spend: {
+      /** Spending limit (in wei) per period */
+      limit: `0x${string}`
+      /** Period of the spend limit */
+      period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
+      /** ERC20 token to set the limit on (defaults to native token) */
+      token?: `0x${string}`
+    }[]
+  }
+}
+```
+
+## Return Value
+
+### accounts
+
+```readonly [`0x${string}`, ...`0x${string}`[]]```
+
+Connected accounts.
+
+### chainId
+
+`number`
+
+Connected chain ID.
+
diff --git a/apps/docs/pages/sdk/wagmi/disconnect.mdx b/apps/docs/pages/sdk/wagmi/disconnect.mdx
new file mode 100644
index 000000000..bd54efa83
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/disconnect.mdx
@@ -0,0 +1,38 @@
+# `disconnect`
+
+VanillaJS action for disconnecting an account. Uses [`wallet_disconnect`](/sdk/rpc/wallet_disconnect) under the hood.
+
+## Usage
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { Actions, porto } from 'porto/wagmi'
+import { config } from './config'
+
+// Disconnect from the current account
+await Actions.disconnect(config)
+
+// Disconnect from a specific connector
+await Actions.disconnect(config, {
+  connector: porto(),
+})
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+## Parameters
+
+### connector
+
+`Connector | CreateConnectorFn`
+
+The connector to disconnect from. If not provided, the current connector will be used.
+
+## Return Value
+
+`void`
\ No newline at end of file
diff --git a/apps/docs/pages/sdk/wagmi/getPermissions.mdx b/apps/docs/pages/sdk/wagmi/getPermissions.mdx
new file mode 100644
index 000000000..aec37b9ce
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/getPermissions.mdx
@@ -0,0 +1,105 @@
+# `getPermissions`
+
+VanillaJS action for retrieving active permissions for an account. Uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions) under the hood.
+
+## Usage
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { Actions } from 'porto/wagmi'
+import { config } from './config'
+
+const permissions = await Actions.getPermissions(config)
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to get permissions for.
+
+### chainId
+
+`number | undefined`
+
+Chain ID to get permissions for.
+
+### connector
+
+`Connector | CreateConnectorFn`
+
+The connector to use.
+
+## Return Value
+
+### address
+
+`Address`
+
+Address of the account.
+
+### chainId
+
+`number`
+
+Chain ID of the account.
+
+### expiry
+
+`number`
+
+Expiry timestamp of the permissions.
+
+### id
+
+`string`
+
+Permission ID.
+
+### key
+
+Key assigned to the permission.
+
+```ts
+type Key = {
+  /** Public key */
+  publicKey: `0x${string}`
+  /** Key type */
+  type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
+}
+```
+
+### permissions
+
+Permissions granted to the account.
+
+```ts
+type Permissions = {
+  /** Call permissions */
+  calls: {
+    /** Function signature or 4-byte signature */
+    signature?: string
+    /** Authorized target address */
+    to: `0x${string}`
+  }[]
+
+  /** Spend permissions */
+  spend: {
+    /** Spending limit */
+    limit: `0x${string}`
+    /** Period of the spend limit */
+    period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
+    /** ERC20 token to set the limit on (defaults to native token) */
+    token?: `0x${string}`
+  }[]
+}
+
diff --git a/apps/docs/pages/sdk/wagmi/grantPermissions.mdx b/apps/docs/pages/sdk/wagmi/grantPermissions.mdx
new file mode 100644
index 000000000..20bd9a40c
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/grantPermissions.mdx
@@ -0,0 +1,208 @@
+# `grantPermissions`
+
+VanillaJS action for granting permissions to an application. Uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions) under the hood.
+
+## Usage
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { toHex, parseEther } from 'viem'
+import { Actions, porto } from 'porto/wagmi'
+import { config } from './config'
+
+const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+const permissions = await Actions.grantPermissions(config, {
+  expiry: Math.floor(Date.now() / 1_000) + 60 * 60, // 1 hour
+  permissions: {
+    calls: [{
+      signature: 'transfer(address,uint256)',
+      to: token
+    }],
+    spend: [{
+      limit: toHex(parseEther('50')), // 50 EXP
+      period: 'day',
+      token: token,
+    }]
+  },
+})
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+
+### App-managed Keys
+
+Applications can also grant permissions to a specific signing key by providing the `key` parameter.
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { privateKeyToAccount, toHex, parseEther } from 'viem'
+import { Actions, porto } from 'porto/wagmi'
+import { config } from './config'
+
+const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+const account = privateKeyToAccount('0x...') // [!code focus]
+
+// Grant permissions with custom key
+const permission = await Actions.grantPermissions(config, {
+  expiry: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60, // 1 week
+  key: { // [!code focus]
+    publicKey: account.address, // [!code focus]
+    type: 'secp256k1', // [!code focus]
+  }, // [!code focus]
+  permissions: {
+    calls: [{
+      signature: 'transfer(address,uint256)',
+      to: token
+    }],
+    spend: [{
+      limit: toHex(parseEther('50')), // 50 EXP
+      period: 'day',
+      token: token,
+    }]
+  },
+})
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to grant permissions on. Defaults to the current account.
+
+### chainId
+
+`number | undefined`
+
+Chain ID to grant permissions on.
+
+### connector
+
+`Connector | CreateConnectorFn`
+
+The connector to use.
+
+### expiry
+
+`number`
+
+Expiry timestamp of the permissions.
+
+### key
+
+Key to grant permissions to. Defaults to a wallet-managed key.
+
+```ts
+type Key = {
+  /** Public key */
+  publicKey: `0x${string}`
+  /** Key type */
+  type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
+}
+```
+
+### permissions
+
+Permissions to grant.
+
+```ts
+type Permissions = {
+  /** Call permissions */
+  calls: {
+    /** Function signature or 4-byte signature */
+    signature?: string
+    /** Authorized target address */
+    to?: `0x${string}`
+  }[]
+
+  /** Spend permissions */
+  spend: {
+    /** Spending limit (in wei) per period */
+    limit: `0x${string}`
+    /** Period of the spend limit */
+    period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
+    /** ERC20 token to set the limit on (defaults to native token) */
+    token?: `0x${string}`
+  }[]
+}
+```
+
+## Return Value
+
+### address
+
+`Address`
+
+Address of the account.
+
+### chainId
+
+`number`
+
+Chain ID of the account.
+
+### expiry
+
+`number`
+
+Expiry timestamp of the permissions.
+
+### id
+
+`string`
+
+Permission ID.
+
+### key
+
+Key to grant permissions to.
+
+```ts
+type Key = {
+  /** Public key */
+  publicKey: `0x${string}`
+  /** Key type */
+  type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
+}
+```
+
+### permissions
+
+Permissions to grant to the account.
+
+```ts
+type Permissions = {
+  /** Call permissions */
+  calls: {
+    /** Function signature or 4-byte signature */
+    signature?: string
+    /** Authorized target address */
+    to?: `0x${string}`
+  }[]
+
+  /** Spend permissions */
+  spend: {
+    /** Spending limit (in wei) per period */
+    limit: `0x${string}`
+    /** Period of the spend limit */
+    period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
+    /** ERC20 token to set the limit on (defaults to native token) */
+    token?: `0x${string}`
+  }[]
+}
+```
diff --git a/apps/docs/pages/sdk/wagmi/revokePermissions.mdx b/apps/docs/pages/sdk/wagmi/revokePermissions.mdx
new file mode 100644
index 000000000..6082994a9
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/revokePermissions.mdx
@@ -0,0 +1,54 @@
+# `revokePermissions`
+
+VanillaJS action for revoking permissions. Uses [`experimental_revokePermissions`](/sdk/rpc/experimental_revokePermissions) under the hood.
+
+## Usage
+
+:::code-group
+
+```ts twoslash [example.ts]
+import { Actions } from 'porto/wagmi'
+import { config } from './config'
+
+await Actions.revokePermissions(config, {
+  id: '0x...', // Permission ID to revoke
+})
+```
+
+```ts twoslash [config.ts] filename="config.ts"
+// [!include ~/snippets/wagmi/config.ts]
+```
+
+:::
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to revoke permissions for. Defaults to the current account.
+
+### chainId
+
+`number | undefined`
+
+Chain ID to revoke permissions on.
+
+### connector
+
+`Connector | CreateConnectorFn`
+
+The connector to use.
+
+### feeToken
+
+`Address | undefined`
+
+Optional fee token to use for the transaction.
+
+### id
+
+`string`
+
+ID of the permission to revoke.
diff --git a/apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx b/apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
new file mode 100644
index 000000000..9fd0d6196
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
@@ -0,0 +1,284 @@
+import { TryItOut } from '../../../components/TryItOut'
+import { parseEther, toHex } from 'viem'
+
+# `useGrantPermissions`
+
+Hook for granting permissions for an Application to perform actions on behalf of the account.
+
+Internally uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions).
+
+```tsx twoslash
+import * as React from 'react'
+// ---cut---
+import { Hooks } from 'porto/wagmi'
+import { parseEther, toHex } from 'viem'
+
+const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+export function App() {
+  const grantPermissions = Hooks.useGrantPermissions()
+
+  return (
+    <button onClick={() => grantPermissions.mutate({
+      expiry: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour
+      permissions: {
+        calls: [{
+          signature: 'transfer(address,uint256)',
+          to: token
+        }],
+        spend: [{
+          limit: parseEther('50'), // 50 EXP
+          period: 'day',
+          token: token,
+        }]
+      },
+    })}>Grant Permissions</button>
+  )
+}
+```
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+    const response = await provider.request({
+      method: 'experimental_grantPermissions',
+      params: [{
+        expiry: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour
+        permissions: {
+          calls: [{ to: token }],
+          spend: [{
+            limit: toHex(parseEther('50')), // 50 EXP
+            period: 'minute',
+            token: token,
+          }],
+        },
+      }]
+    })
+
+    return response
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+### App-managed Keys
+
+You can also grant permissions to a specific signing key by providing the `key` parameter. This is useful for when the application wants to perform signing themselves, instead of the wallet.
+
+```tsx twoslash
+import * as React from 'react'
+// ---cut---
+import { Hooks } from 'porto/wagmi'
+import { parseEther, toHex } from 'viem'
+import { privateKeyToAccount } from 'viem/accounts'
+
+const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+export function App() {
+  const grantPermissions = Hooks.useGrantPermissions()
+  const account = privateKeyToAccount('0x...') // [!code focus]
+
+  return (
+    <button onClick={() => grantPermissions.mutate({
+      expiry: Math.floor(Date.now() / 1_000) + 7 * 24 * 60 * 60, // 1 week
+      key: { // [!code focus]
+        publicKey: account.address, // [!code focus]
+        type: 'secp256k1', // [!code focus]
+      }, // [!code focus]
+      permissions: {
+        calls: [{
+          signature: 'transfer(address,uint256)',
+          to: token
+        }],
+        spend: [{
+          limit: parseEther('50'), // 50 EXP
+          period: 'day',
+          token: token,
+        }]
+      },
+    })}>Grant Permissions</button>
+  )
+}
+```
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to grant permissions for. If not provided, will use the connected account.
+
+### expiry
+
+`number`
+
+Timestamp (in seconds) when the permission expires.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const grantPermissions = Hooks.useGrantPermissions()
+
+  // Grant permissions for 1 hour
+  grantPermissions.mutate({
+    expiry: Math.floor(Date.now() / 1000) + 60 * 60
+    // ...
+  })
+}
+```
+
+### key
+
+Optional key to use for signing. If provided, the application can use this key to sign transactions.
+
+```ts
+type Key = {
+  /** Public key */
+  publicKey: `0x${string}`
+  /** Key type */
+  type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
+}
+```
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+import { privateKeyToAccount } from 'viem/accounts'
+
+function Example() {
+  const grantPermissions = Hooks.useGrantPermissions()
+  const account = privateKeyToAccount('0x...')
+
+  grantPermissions.mutate({
+    key: {
+      publicKey: account.address,
+      type: 'secp256k1',
+    }
+    // ...
+  })
+}
+```
+
+### permissions
+
+Permissions to grant to the account.
+
+```ts
+type Permissions = {
+  /** Call permissions */
+  calls: {
+    /** Function signature or 4-byte signature */
+    signature?: string
+    /** Authorized target address */
+    to?: `0x${string}`
+  }[]
+
+  /** Spend permissions */
+  spend: {
+    /** Spending limit (in wei) per period */
+    limit: `0x${string}`
+    /** Period of the spend limit */
+    period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
+    /** ERC20 token to set the limit on (defaults to native token) */
+    token?: `0x${string}`
+  }[]
+}
+```
+
+### onError
+
+`((error: Error, variables: GrantPermissionsParameters, context: unknown) => void) | undefined`
+
+Function to invoke if the mutation encounters an error.
+
+### onMutate
+
+`((variables: GrantPermissionsParameters) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke before the mutation function and before `onSuccess` or `onError` are invoked.
+
+### onSettled
+
+`((data: unknown, error: Error | null, variables: GrantPermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke when the mutation is settled (either succeeded or failed).
+
+### onSuccess
+
+`((data: unknown, variables: GrantPermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke if the mutation is successful.
+
+## Return Type
+
+Returns a [`TanStack Query` mutation result](https://tanstack.com/query/latest/docs/react/reference/useMutation) with the following properties:
+
+### data
+
+`unknown`
+
+Data returned from the mutation.
+
+### error
+
+`Error | null`
+
+Error encountered during mutation execution, if any.
+
+### isError
+
+`boolean`
+
+True if the mutation encountered an error.
+
+### isIdle
+
+`boolean`
+
+True if the mutation has not been called yet.
+
+### isLoading
+
+`boolean`
+
+True if the mutation is in a loading state.
+
+### isPending
+
+`boolean`
+
+True if the mutation is in a pending state.
+
+### isSuccess
+
+`boolean`
+
+True if the mutation was successful.
+
+### mutate
+
+`(variables: GrantPermissionsParameters) => void`
+
+Function to trigger the mutation.
+
+### mutateAsync
+
+`(variables: GrantPermissionsParameters) => Promise<unknown>`
+
+Async function to trigger the mutation and get a promise that resolves when the mutation is complete.
+
+### reset
+
+`() => void`
+
+Function to reset the mutation state.
+
+### status
+
+`'error' | 'idle' | 'loading' | 'success'`
+
+Current status of the mutation.
\ No newline at end of file
diff --git a/apps/docs/pages/sdk/wagmi/usePermissions.mdx b/apps/docs/pages/sdk/wagmi/usePermissions.mdx
new file mode 100644
index 000000000..ef1eeb643
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/usePermissions.mdx
@@ -0,0 +1,103 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `usePermissions`
+
+Hook for retrieving active permissions for an account.
+
+Internally uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions).
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const result = Hooks.usePermissions()
+}
+```
+
+<TryItOut
+  exampleSlug="#example"
+  fn={({ provider }) => provider.request({ method: 'experimental_getPermissions' })}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to get permissions for. If not provided, will use the connected account.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const result = Hooks.usePermissions({
+    address: '0x...'
+  })
+}
+```
+
+### config
+
+`Config | undefined`
+
+Configuration to pass to the query.
+
+## Return Type
+
+```tsx
+UseQueryResult<PermissionInfo[]>
+```
+
+Returns a [`TanStack Query`](https://tanstack.com/query/latest) result object with the following properties:
+
+### data
+
+`PermissionInfo[] | undefined`
+
+Array of permission information objects.
+
+### error
+
+`Error | null`
+
+Error encountered during query execution, if any.
+
+### isError
+
+`boolean`
+
+True if the query encountered an error.
+
+### isIdle
+
+`boolean`
+
+True if the query has not started yet.
+
+### isLoading
+
+`boolean`
+
+True if the query is in a loading state.
+
+### isPending
+
+`boolean`
+
+True if the query is in a pending state.
+
+### isSuccess
+
+`boolean`
+
+True if the query was successful and data is available.
+
+### status
+
+`'error' | 'idle' | 'loading' | 'success'`
+
+Current status of the query.
diff --git a/apps/docs/pages/sdk/wagmi/useRevokePermissions.mdx b/apps/docs/pages/sdk/wagmi/useRevokePermissions.mdx
new file mode 100644
index 000000000..3086e0356
--- /dev/null
+++ b/apps/docs/pages/sdk/wagmi/useRevokePermissions.mdx
@@ -0,0 +1,196 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `useRevokePermissions`
+
+Hook for revoking permissions.
+
+Internally uses [`experimental_revokePermissions`](/sdk/rpc/experimental_revokePermissions).
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const revokePermissions = Hooks.useRevokePermissions()
+}
+```
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    // For demo purposes only, first get permissions to show one being revoked
+    const permissions = await provider.request({
+      method: 'experimental_getPermissions'
+    })
+
+    if (!permissions || permissions.length === 0) {
+      return { message: "No permissions to revoke" }
+    }
+
+    // Revoke the first permission
+    await provider.request({
+      method: 'experimental_revokePermissions',
+      params: [{ id: permissions[0].id }]
+    })
+
+    return { message: `Successfully revoked permission ${permissions[0].id}` }
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to revoke permissions for. If not provided, will use the connected account.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const revokePermissions = Hooks.useRevokePermissions()
+  
+  revokePermissions.mutate({
+    address: '0x...', // [!code focus]
+    id: '0x...'
+  })
+}
+```
+
+### id
+
+`string`
+
+The ID of the permission to revoke.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const revokePermissions = Hooks.useRevokePermissions()
+  
+  revokePermissions.mutate({
+    id: '0x123abc...' // [!code focus]
+  })
+}
+```
+
+### feeToken
+
+`Address | undefined`
+
+Optional fee token address to use for the revocation transaction.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const revokePermissions = Hooks.useRevokePermissions()
+  
+  revokePermissions.mutate({
+    id: '0x123abc...',
+    feeToken: '0x1234...' // [!code focus]
+  })
+}
+```
+
+### onError
+
+`((error: Error, variables: RevokePermissionsParameters, context: unknown) => void) | undefined`
+
+Function to invoke if the mutation encounters an error.
+
+### onMutate
+
+`((variables: RevokePermissionsParameters) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke before the mutation function and before `onSuccess` or `onError` are invoked.
+
+### onSettled
+
+`((data: unknown, error: Error | null, variables: RevokePermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke when the mutation is settled (either succeeded or failed).
+
+### onSuccess
+
+`((data: unknown, variables: RevokePermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke if the mutation is successful.
+
+## Return Type
+
+```tsx
+UseMutationResult<unknown, Error, RevokePermissionsParameters>
+```
+
+Returns a [`TanStack Query` mutation result](https://tanstack.com/query/latest/docs/react/reference/useMutation) with the following properties:
+
+### data
+
+`unknown`
+
+Data returned from the mutation.
+
+### error
+
+`Error | null`
+
+Error encountered during mutation execution, if any.
+
+### isError
+
+`boolean`
+
+True if the mutation encountered an error.
+
+### isIdle
+
+`boolean`
+
+True if the mutation has not been called yet.
+
+### isLoading
+
+`boolean`
+
+True if the mutation is in a loading state.
+
+### isPending
+
+`boolean`
+
+True if the mutation is in a pending state.
+
+### isSuccess
+
+`boolean`
+
+True if the mutation was successful.
+
+### mutate
+
+`(variables: RevokePermissionsParameters) => void`
+
+Function to trigger the mutation.
+
+### mutateAsync
+
+`(variables: RevokePermissionsParameters) => Promise<unknown>`
+
+Async function to trigger the mutation and get a promise that resolves when the mutation is complete.
+
+### reset
+
+`() => void`
+
+Function to reset the mutation state.
+
+### status
+
+`'error' | 'idle' | 'loading' | 'success'`
+
+Current status of the mutation.
diff --git a/apps/docs/snippets/wagmi/config.ts b/apps/docs/snippets/wagmi/config.ts
new file mode 100644
index 000000000..da196ab03
--- /dev/null
+++ b/apps/docs/snippets/wagmi/config.ts
@@ -0,0 +1,11 @@
+import { porto } from 'porto/wagmi'
+import { createConfig, http } from 'wagmi'
+import { baseSepolia } from 'wagmi/chains'
+
+export const config = createConfig({
+  chains: [baseSepolia],
+  connectors: [porto()],
+  transports: {
+    [baseSepolia.id]: http(),
+  },
+})
diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json
index 2150bf5ac..ab391759e 100644
--- a/apps/docs/tsconfig.json
+++ b/apps/docs/tsconfig.json
@@ -3,6 +3,9 @@
   "include": ["**/*.ts", "**/*.tsx"],
   "files": ["./vite-env.d.ts"],
   "compilerOptions": {
-    "types": ["unplugin-icons/types/react", "typed-query-selector/strict"]
+    "types": ["unplugin-icons/types/react", "typed-query-selector/strict"],
+    "paths": {
+      "~components/*": ["./components/*"]
+    }
   }
 }
diff --git a/apps/docs/vocs.config.tsx b/apps/docs/vocs.config.tsx
index 678bad5d3..8208b94c9 100644
--- a/apps/docs/vocs.config.tsx
+++ b/apps/docs/vocs.config.tsx
@@ -160,16 +160,13 @@ export default defineConfig({
             text: 'Porto',
           },
           {
-            disabled: true,
             link: '/sdk/api/chains',
-            text: 'Chains 🚧',
+            text: 'Chains',
           },
           {
             collapsed: true,
-            disabled: true,
             items: [
               {
-                disabled: true,
                 link: '/sdk/api/dialog/iframe',
                 text: '.iframe',
               },
@@ -180,7 +177,7 @@ export default defineConfig({
               },
             ],
             link: '/sdk/api/dialog',
-            text: 'Dialog 🚧',
+            text: 'Dialog',
           },
           {
             collapsed: true,
@@ -207,7 +204,6 @@ export default defineConfig({
           },
           {
             collapsed: true,
-            disabled: true,
             items: [
               {
                 disabled: true,
@@ -215,23 +211,19 @@ export default defineConfig({
                 text: '.cookie',
               },
               {
-                disabled: true,
                 link: '/sdk/api/storage/idb',
                 text: '.idb',
               },
               {
-                disabled: true,
                 link: '/sdk/api/storage/localstorage',
                 text: '.localStorage',
               },
               {
-                disabled: true,
                 link: '/sdk/api/storage/memory',
                 text: '.memory',
               },
             ],
-            link: '/sdk/api/storage',
-            text: 'Storage 🚧',
+            text: 'Storage',
           },
         ],
         text: 'API Reference',
@@ -243,35 +235,30 @@ export default defineConfig({
             text: 'Overview',
           },
           {
+            disabled: true,
             link: '/sdk/wagmi/connector',
             text: 'Connector 🚧',
           },
           {
             collapsed: true,
-            disabled: true,
             items: [
               {
-                disabled: true,
                 link: '/sdk/wagmi/connect',
                 text: 'connect',
               },
               {
-                disabled: true,
                 link: '/sdk/wagmi/disconnect',
                 text: 'disconnect',
               },
               {
-                disabled: true,
                 link: '/sdk/wagmi/grantPermissions',
                 text: 'grantPermissions',
               },
               {
-                disabled: true,
-                link: '/sdk/wagmi/permissions',
-                text: 'permissions',
+                link: '/sdk/wagmi/getPermissions',
+                text: 'getPermissions',
               },
               {
-                disabled: true,
                 link: '/sdk/wagmi/revokePermissions',
                 text: 'revokePermissions',
               },
@@ -281,34 +268,20 @@ export default defineConfig({
                 text: 'upgradeAccount',
               },
             ],
-            text: 'Actions 🚧',
+            text: 'Actions',
           },
           {
             collapsed: true,
-            disabled: true,
             items: [
               {
-                disabled: true,
-                link: '/sdk/wagmi/useConnect',
-                text: 'useConnect',
-              },
-              {
-                disabled: true,
-                link: '/sdk/wagmi/useDisconnect',
-                text: 'useDisconnect',
-              },
-              {
-                disabled: true,
                 link: '/sdk/wagmi/useGrantPermissions',
                 text: 'useGrantPermissions',
               },
               {
-                disabled: true,
                 link: '/sdk/wagmi/usePermissions',
                 text: 'usePermissions',
               },
               {
-                disabled: true,
                 link: '/sdk/wagmi/useRevokePermissions',
                 text: 'useRevokePermissions',
               },
@@ -318,7 +291,7 @@ export default defineConfig({
                 text: 'useUpgradeAccount',
               },
             ],
-            text: 'Hooks 🚧',
+            text: 'Hooks',
           },
         ],
         text: 'Wagmi Reference',
diff --git a/src/wagmi/internal/core.ts b/src/wagmi/internal/core.ts
index 0d886a10a..c6909e5ae 100644
--- a/src/wagmi/internal/core.ts
+++ b/src/wagmi/internal/core.ts
@@ -225,7 +225,7 @@ export declare namespace createAccount {
 
 export async function disconnect(
   config: Config,
-  parameters: disconnect.Parameters,
+  parameters: disconnect.Parameters = {},
 ): Promise<disconnect.ReturnType> {
   const connector = (() => {
     if (parameters.connector) return parameters.connector
@@ -301,7 +301,7 @@ export declare namespace getAdmins {
 
 export async function getPermissions<config extends Config>(
   config: config,
-  parameters: getPermissions.Parameters<config>,
+  parameters: getPermissions.Parameters<config> = {},
 ): Promise<getPermissions.ReturnType> {
   const { address, chainId, connector } = parameters
 


Reviews:
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:49:34Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:53:04Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:54:35Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:56:37Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:56:57Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:57:10Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:57:20Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:57:33Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T04:58:16Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T05:00:31Z
user: login: jxom
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-22T07:10:09Z

Review comments:
diff_hunk: @@ -0,0 +1,109 @@
+import { TryItOut } from '../../../components/TryItOut'
path: apps/docs/pages/sdk/wagmi/usePermissions.mdx
user: login: jxom
body: Let's include Parameters and Return Type in these docs like we do in Wagmi: https://wagmi.sh/react/api/hooks/useTransaction
created_at: 2025-05-21T04:49:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `usePermissions`
+
+React hook for retrieving active permissions for an account.
+
+Uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions) under the hood.
+
+<TryItOut
+  exampleSlug="#example"
+  fn={({ provider }) => provider.request({ method: 'experimental_getPermissions' })}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Example
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const permissions = Hooks.usePermissions()
+
+  if (permissions.isLoading) return <div>Loading permissions...</div>
+  if (permissions.isError) return <div>Error loading permissions</div>
+
+  return (
+    <div>
+      <h2>Active Permissions</h2>
+      {permissions.data && permissions.data.length > 0 ? (
+        <ul>
+          {permissions.data.map((permission) => (
+            <li key={permission.id}>
+              <div>ID: {permission.id}</div>
+              <div>Expiry: {new Date(permission.expiry * 1000).toLocaleString()}</div>
+              <div>
+                <strong>Calls:</strong>
+                <ul>
+                  {permission.permissions.calls.map((call, i) => (
+                    <li key={i}>
+                      {call.to && <div>To: {call.to}</div>}
+                      {call.signature && <div>Signature: {call.signature}</div>}
+                    </li>
+                  ))}
+                </ul>
+              </div>
+              <div>
+                <strong>Spend:</strong>
+                <ul>
+                  {permission.permissions?.spend?.map((spend, i) => (
+                    <li key={i}>
+                      <div>Limit: {spend.limit.toString()}</div>
+                      <div>Period: {spend.period}</div>
+                      {spend.token && <div>Token: {spend.token}</div>}
+                    </li>
+                  ))}
+                </ul>
+              </div>
+            </li>
+          ))}
+        </ul>
+      ) : (
+        <div>No active permissions</div>
+      )}
+    </div>
+  )
+}
+```
path: apps/docs/pages/sdk/wagmi/usePermissions.mdx
user: login: jxom
body: Let's make these examples super concise. We could just use TwoSlash logs to display an example return value.

```suggestion

```tsx twoslash
import { Hooks } from 'porto/wagmi'

function Example() {
  const result = Hooks.usePermissions()
// @log: {
// @log: ...
// @log: }
}
```

```
created_at: 2025-05-21T04:53:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `usePermissions`
+
+React hook for retrieving active permissions for an account.
+
+Uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions) under the hood.
+
+<TryItOut
+  exampleSlug="#example"
+  fn={({ provider }) => provider.request({ method: 'experimental_getPermissions' })}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Example
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const permissions = Hooks.usePermissions()
+
+  if (permissions.isLoading) return <div>Loading permissions...</div>
+  if (permissions.isError) return <div>Error loading permissions</div>
+
+  return (
+    <div>
+      <h2>Active Permissions</h2>
+      {permissions.data && permissions.data.length > 0 ? (
+        <ul>
+          {permissions.data.map((permission) => (
+            <li key={permission.id}>
+              <div>ID: {permission.id}</div>
+              <div>Expiry: {new Date(permission.expiry * 1000).toLocaleString()}</div>
+              <div>
+                <strong>Calls:</strong>
+                <ul>
+                  {permission.permissions.calls.map((call, i) => (
+                    <li key={i}>
+                      {call.to && <div>To: {call.to}</div>}
+                      {call.signature && <div>Signature: {call.signature}</div>}
+                    </li>
+                  ))}
+                </ul>
+              </div>
+              <div>
+                <strong>Spend:</strong>
+                <ul>
+                  {permission.permissions?.spend?.map((spend, i) => (
+                    <li key={i}>
+                      <div>Limit: {spend.limit.toString()}</div>
+                      <div>Period: {spend.period}</div>
+                      {spend.token && <div>Token: {spend.token}</div>}
+                    </li>
+                  ))}
+                </ul>
+              </div>
+            </li>
+          ))}
+        </ul>
+      ) : (
+        <div>No active permissions</div>
+      )}
+    </div>
+  )
+}
+```
+
+<TryItOut
+  fn={({ provider }) => provider.request({ method: 'experimental_getPermissions' })}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+### Query Specific Account
+
+You can query permissions for a specific account by passing an address:
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const specificAddress = '0x123...' // [!code focus]
+  const permissions = Hooks.usePermissions({
+    address: specificAddress // [!code focus]
+  })
+
+  if (permissions.isLoading) return <div>Loading permissions...</div>
+  if (permissions.isError) return <div>Error loading permissions</div>
+
+  return (
+    <div>
+      <h2>Active Permissions for {specificAddress}</h2>
+      {/* Display permissions as in the previous example */}
+    </div>
+  )
+}
+```
path: apps/docs/pages/sdk/wagmi/usePermissions.mdx
user: login: jxom
body: ```suggestion
```tsx twoslash
import { Hooks } from 'porto/wagmi'

function Example() {
  const result = Hooks.usePermissions({
    address: '0x...'
  })
// @log: {
// @log: ...
// @log: }
}
```
```
created_at: 2025-05-21T04:54:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+import { TryItOut } from '../../../components/TryItOut'
+import { parseEther, toHex } from 'viem'
+
+# `useGrantPermissions`
+
+React hook for granting permissions for an Application to perform actions on behalf of the account.
+
+Uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions) under the hood.
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+    const response = await provider.request({
+      method: 'experimental_grantPermissions',
+      params: [{
+        expiry: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour
+        permissions: {
+          calls: [{ to: token }],
+          spend: [{
+            limit: toHex(parseEther('50')), // 50 EXP
+            period: 'minute',
+            token: token,
+          }],
+        },
+      }]
+    })
+
+    return response
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Example
+
+```tsx
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+import { parseEther, toHex } from 'viem'
+
+const porto = Porto.create()
path: apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
user: login: jxom
body: ```suggestion
import { Hooks } from 'porto/wagmi'
import { parseEther, toHex } from 'viem'
```
created_at: 2025-05-21T04:56:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+import { TryItOut } from '../../../components/TryItOut'
+import { parseEther, toHex } from 'viem'
+
+# `useGrantPermissions`
+
+React hook for granting permissions for an Application to perform actions on behalf of the account.
path: apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
user: login: jxom
body: ```suggestion
Hook for granting permissions for an Application to perform actions on behalf of the account.
```
created_at: 2025-05-21T04:56:57Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,135 @@
+import { TryItOut } from '../../../components/TryItOut'
+import { parseEther, toHex } from 'viem'
+
+# `useGrantPermissions`
+
+React hook for granting permissions for an Application to perform actions on behalf of the account.
+
+Uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions) under the hood.
path: apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
user: login: jxom
body: ```suggestion
Internally uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions).
```
created_at: 2025-05-21T04:57:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `usePermissions`
+
+React hook for retrieving active permissions for an account.
path: apps/docs/pages/sdk/wagmi/usePermissions.mdx
user: login: jxom
body: ```suggestion
Hook for retrieving active permissions for an account.
```
created_at: 2025-05-21T04:57:20Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,109 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `usePermissions`
+
+React hook for retrieving active permissions for an account.
+
+Uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions) under the hood.
path: apps/docs/pages/sdk/wagmi/usePermissions.mdx
user: login: jxom
body: ```suggestion
Internally uses [`experimental_getPermissions`](/sdk/rpc/experimental_getPermissions).
```
created_at: 2025-05-21T04:57:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,129 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `useRevokePermissions`
+
+React hook for revoking permissions.
+
+Uses [`experimental_revokePermissions`](/sdk/rpc/experimental_revokePermissions) under the hood.
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    // For demo purposes only, first get permissions to show one being revoked
+    const permissions = await provider.request({
+      method: 'experimental_getPermissions'
+    })
+
+    if (!permissions || permissions.length === 0) {
+      return { message: "No permissions to revoke" }
+    }
+
+    // Revoke the first permission
+    await provider.request({
+      method: 'experimental_revokePermissions',
+      params: [{ id: permissions[0].id }]
+    })
+
+    return { message: `Successfully revoked permission ${permissions[0].id}` }
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Example
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const permissions = Hooks.usePermissions()
+  const revokePermissions = Hooks.useRevokePermissions()
+
+  if (permissions.isLoading) return <div>Loading permissions...</div>
+  if (permissions.isError) return <div>Error loading permissions</div>
+
+  return (
+    <div>
+      <h2>Active Permissions</h2>
+      {permissions.data && permissions.data.length > 0 ? (
+        <ul>
+          {permissions.data.map((permission) => (
+            <li key={permission.id}>
+              <div>ID: {permission.id}</div>
+              <div>Expiry: {new Date(permission.expiry * 1000).toLocaleString()}</div>
+              {/* Display other permission details */}
+              <button
+                onClick={() => revokePermissions.mutate({
+                  id: permission.id
+                })}
+              >
+                Revoke Permission
+              </button>
+            </li>
+          ))}
+        </ul>
+      ) : (
+        <div>No active permissions</div>
+      )}
+    </div>
+  )
+}
+```
+
+<TryItOut
+  fn={async ({ provider }) => {
+    // For demo purposes only, first get permissions to show one being revoked
+    const permissions = await provider.request({
+      method: 'experimental_getPermissions'
+    })
+
+    if (!permissions || permissions.length === 0) {
+      return { message: "No permissions to revoke" }
+    }
+
+    // Revoke the first permission
+    await provider.request({
+      method: 'experimental_revokePermissions',
+      params: [{ id: permissions[0].id }]
+    })
+
+    return { message: `Successfully revoked permission ${permissions[0].id}` }
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+### Revoke for Specific Account
+
+You can revoke permissions for a specific account by including the address:
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const revokePermissions = Hooks.useRevokePermissions()
+  const specificAddress = '0x123...' // [!code focus]
+  const permissionId = '0x456...' // [!code focus]
+
+  return (
+    <button
+      onClick={() => revokePermissions.mutate({
+        address: specificAddress, // [!code focus]
+        id: permissionId
+      })}
+    >
+      Revoke Permission for Specific Account
+    </button>
+  )
+}
+```
path: apps/docs/pages/sdk/wagmi/useRevokePermissions.mdx
user: login: jxom
body: ```suggestion
```tsx twoslash
import { Hooks } from 'porto/wagmi'

export function App() {
  const revokePermissions = Hooks.useRevokePermissions()

  return (
    <button
      onClick={() => revokePermissions.mutate({
        address: '0x...', // [!code focus]
        id: '0x...'
      })}
    >
      Revoke
    </button>
  )
}
```
```
created_at: 2025-05-21T04:58:16Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,129 @@
+import { TryItOut } from '../../../components/TryItOut'
+
+# `useRevokePermissions`
+
+React hook for revoking permissions.
+
+Uses [`experimental_revokePermissions`](/sdk/rpc/experimental_revokePermissions) under the hood.
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    // For demo purposes only, first get permissions to show one being revoked
+    const permissions = await provider.request({
+      method: 'experimental_getPermissions'
+    })
+
+    if (!permissions || permissions.length === 0) {
+      return { message: "No permissions to revoke" }
+    }
+
+    // Revoke the first permission
+    await provider.request({
+      method: 'experimental_revokePermissions',
+      params: [{ id: permissions[0].id }]
+    })
+
+    return { message: `Successfully revoked permission ${permissions[0].id}` }
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Example
+
+```tsx twoslash
+import { Porto } from 'porto'
+import * as React from 'react'
+import { Hooks } from 'porto/wagmi'
+
+const porto = Porto.create()
+
+export function App() {
+  const permissions = Hooks.usePermissions()
+  const revokePermissions = Hooks.useRevokePermissions()
+
+  if (permissions.isLoading) return <div>Loading permissions...</div>
+  if (permissions.isError) return <div>Error loading permissions</div>
+
+  return (
+    <div>
+      <h2>Active Permissions</h2>
+      {permissions.data && permissions.data.length > 0 ? (
+        <ul>
+          {permissions.data.map((permission) => (
+            <li key={permission.id}>
+              <div>ID: {permission.id}</div>
+              <div>Expiry: {new Date(permission.expiry * 1000).toLocaleString()}</div>
+              {/* Display other permission details */}
+              <button
+                onClick={() => revokePermissions.mutate({
+                  id: permission.id
+                })}
+              >
+                Revoke Permission
+              </button>
+            </li>
+          ))}
+        </ul>
+      ) : (
+        <div>No active permissions</div>
+      )}
+    </div>
+  )
+}
+```
path: apps/docs/pages/sdk/wagmi/useRevokePermissions.mdx
user: login: jxom
body: ```suggestion
```tsx twoslash
import { Hooks } from 'porto/wagmi'

export function App() {
  const permissions = Hooks.usePermissions()
  const revokePermissions = Hooks.useRevokePermissions()

  return permissions.data.map(permission => (
    <button
      onClick={() => revokePermissions.mutate({
        id: permission.id
      })}
    >
      Revoke Permission
    </button>
  ))
}
```
```
created_at: 2025-05-21T05:00:30Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,311 @@
+import { TryItOut } from '../../../components/TryItOut'
+import { parseEther, toHex } from 'viem'
+
+# `useGrantPermissions`
+
+Hook for granting permissions for an Application to perform actions on behalf of the account.
+
+Internally uses [`experimental_grantPermissions`](/sdk/rpc/experimental_grantPermissions).
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const grantPermissions = Hooks.useGrantPermissions()
+}
+```
+
+<TryItOut
+  exampleSlug="#example"
+  fn={async ({ provider }) => {
+    const token = '0x29f45fc3ed1d0ffafb5e2af9cc6c3ab1555cd5a2'
+
+    const response = await provider.request({
+      method: 'experimental_grantPermissions',
+      params: [{
+        expiry: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour
+        permissions: {
+          calls: [{ to: token }],
+          spend: [{
+            limit: toHex(parseEther('50')), // 50 EXP
+            period: 'minute',
+            token: token,
+          }],
+        },
+      }]
+    })
+
+    return response
+  }}
+  transformResultCode={(code) => {
+    return 'const response = ' + code
+  }}
+/>
+
+## Parameters
+
+### address
+
+`Address | undefined`
+
+Address of the account to grant permissions for. If not provided, will use the connected account.
+
+### expiry
+
+`number`
+
+Timestamp (in seconds) when the permission expires.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+
+function Example() {
+  const grantPermissions = Hooks.useGrantPermissions()
+
+  // Grant permissions for 1 hour
+  grantPermissions.mutate({
+    expiry: Math.floor(Date.now() / 1000) + 60 * 60
+    // ...
+  })
+}
+```
+
+### key
+
+`{ publicKey: Address, type: 'secp256k1' } | undefined`
+
+Optional key to use for signing. If provided, the application can use this key to sign transactions.
+
+```tsx
+import { Hooks } from 'porto/wagmi'
+import { privateKeyToAccount } from 'viem/accounts'
+
+function Example() {
+  const grantPermissions = Hooks.useGrantPermissions()
+  const account = privateKeyToAccount('0x...')
+
+  grantPermissions.mutate({
+    key: {
+      publicKey: account.address,
+      type: 'secp256k1',
+    }
+    // ...
+  })
+}
+```
+
+### permissions
+
+`{
+  calls?: { signature?: string, to?: Address }[],
+  signatureVerification?: { addresses: Address[] },
+  spend?: { limit: Hex, period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year', token?: Address }[]
+}`
+
+Permission configuration specifying which actions are allowed.
+
+#### calls
+
+Array of call permissions that define which contracts and functions can be called.
+
+#### signatureVerification
+
+Optional configuration for signature verification permissions.
+
+#### spend
+
+Array of spend permissions that define token spending limits.
+
+### onError
+
+`((error: Error, variables: GrantPermissionsParameters, context: unknown) => void) | undefined`
+
+Function to invoke if the mutation encounters an error.
+
+### onMutate
+
+`((variables: GrantPermissionsParameters) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke before the mutation function and before `onSuccess` or `onError` are invoked.
+
+### onSettled
+
+`((data: unknown, error: Error | null, variables: GrantPermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke when the mutation is settled (either succeeded or failed).
+
+### onSuccess
+
+`((data: unknown, variables: GrantPermissionsParameters, context: unknown) => Promise<unknown> | unknown) | undefined`
+
+Function to invoke if the mutation is successful.
+
+## Return Type
+
+```tsx
+UseMutationResult<unknown, Error, GrantPermissionsParameters>
+```
+
+Returns a [`TanStack Query` mutation result](https://tanstack.com/query/latest/docs/react/reference/useMutation) with the following properties:
+
+### data
+
+`unknown`
+
+Data returned from the mutation.
+
+### error
+
+`Error | null`
+
+Error encountered during mutation execution, if any.
+
+### isError
+
+`boolean`
+
+True if the mutation encountered an error.
+
+### isIdle
+
+`boolean`
+
+True if the mutation has not been called yet.
+
+### isLoading
+
+`boolean`
+
+True if the mutation is in a loading state.
+
+### isPending
+
+`boolean`
+
+True if the mutation is in a pending state.
+
+### isSuccess
+
+`boolean`
+
+True if the mutation was successful.
+
+### mutate
+
+`(variables: GrantPermissionsParameters) => void`
+
+Function to trigger the mutation.
+
+### mutateAsync
+
+`(variables: GrantPermissionsParameters) => Promise<unknown>`
+
+Async function to trigger the mutation and get a promise that resolves when the mutation is complete.
+
+### reset
+
+`() => void`
+
+Function to reset the mutation state.
+
+### status
+
+`'error' | 'idle' | 'loading' | 'success'`
+
+Current status of the mutation.
path: apps/docs/pages/sdk/wagmi/useGrantPermissions.mdx
user: login: jxom
body: Might be worth using [a snippet](https://vocs.dev/docs/guides/markdown-snippets) for this.
created_at: 2025-05-22T07:10:09Z
author_association: COLLABORATOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-15T19:38:10Z
body: ###  ⚠️  No Changeset found

Latest commit: e57930f14a807be6523e79aa1d46f8d615612b9a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/ithacaxyz/porto/new/o-az/docs-01?filename=.changeset/heavy-lemons-fetch.md&value=---%0A%22docs%22%3A%20patch%0A%22porto%22%3A%20patch%0A---%0A%0Afeat%3A%20more%20docs%0A)


author_association: NONE
user: login: vercel[bot]
created_at: 2025-05-15T19:38:11Z
body: [vc]: #G3u6N/jlmEsqzAuy7WMoRmgr3kqAFXxxkfeR6ottLUs=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ3YWdtaS5wb3J0byIsInJvb3REaXJlY3RvcnkiOiJhcHBzL3dhZ21pIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2l0aGFjYXh5ei93YWdtaS5wb3J0by81N2hZODc5MjdnaHdSRFNlVGVuc1U2WEgyd0RIIiwicHJldmlld1VybCI6IndhZ21pcG9ydG8tZ2l0LW8tYXotZG9jcy0wMS1pdGhhY2F4eXoudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJ3YWdtaXBvcnRvLWdpdC1vLWF6LWRvY3MtMDEtaXRoYWNheHl6LnZlcmNlbC5hcHAifX0seyJuYW1lIjoiZGlhbG9nLnBvcnRvIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvZGlhbG9nIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2l0aGFjYXh5ei9kaWFsb2cucG9ydG8vRVhiS1E1WDZOVzdXeW5WU3B5WUVac1ZlbWViYSIsInByZXZpZXdVcmwiOiJkaWFsb2dwb3J0by1naXQtby1hei1kb2NzLTAxLWl0aGFjYXh5ei52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImRpYWxvZ3BvcnRvLWdpdC1vLWF6LWRvY3MtMDEtaXRoYWNheHl6LnZlcmNlbC5hcHAifX0seyJuYW1lIjoibWFuYWdlLnBvcnRvIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvbWFuYWdlciIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9pdGhhY2F4eXovbWFuYWdlLnBvcnRvL0dzVVFQSFZ3VGVYc3MzaFNEMzRUemY0R252ZVUiLCJwcmV2aWV3VXJsIjoibWFuYWdlcG9ydG8tZ2l0LW8tYXotZG9jcy0wMS1pdGhhY2F4eXoudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJtYW5hZ2Vwb3J0by1naXQtby1hei1kb2NzLTAxLWl0aGFjYXh5ei52ZXJjZWwuYXBwIn19LHsibmFtZSI6ImlkLnBvcnRvIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvcHJveHkiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vaXRoYWNheHl6L2lkLnBvcnRvLzlUMlI4WkFKakhyQlBBSGN0RkFlR1FOc2tVa0giLCJwcmV2aWV3VXJsIjoiaWRwb3J0by1naXQtby1hei1kb2NzLTAxLWl0aGFjYXh5ei52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImlkcG9ydG8tZ2l0LW8tYXotZG9jcy0wMS1pdGhhY2F4eXoudmVyY2VsLmFwcCJ9fSx7Im5hbWUiOiJwbGF5Z3JvdW5kLnBvcnRvIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvcGxheWdyb3VuZCIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9pdGhhY2F4eXovcGxheWdyb3VuZC5wb3J0by9GUkxCZ200MWpkblA2RWp1ZXZRZlNhbWJ4RVNrIiwicHJldmlld1VybCI6InBsYXlncm91bmRwb3J0by1naXQtby1hei1kb2NzLTAxLWl0aGFjYXh5ei52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6InBsYXlncm91bmRwb3J0by1naXQtby1hei1kb2NzLTAxLWl0aGFjYXh5ei52ZXJjZWwuYXBwIn19LHsibmFtZSI6ImRvY3MucG9ydG8iLCJyb290RGlyZWN0b3J5IjoiYXBwcy9kb2NzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2l0aGFjYXh5ei9kb2NzLnBvcnRvLzh4ZmRxUVB1WTdDWjVvM0J0VTR0Qnd4MncxR0siLCJwcmV2aWV3VXJsIjoiZG9jc3BvcnRvLWdpdC1vLWF6LWRvY3MtMDEtaXRoYWNheHl6LnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiREVQTE9ZRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiZG9jc3BvcnRvLWdpdC1vLWF6LWRvY3MtMDEtaXRoYWNheHl6LnZlcmNlbC5hcHAifX1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **dialog.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/dialog.porto/EXbKQ5X6NW7WynVSpyYEZsVemeba)) | [Visit Preview](https://dialogporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/dialogporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |
| **docs.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/docs.porto/8xfdqQPuY7CZ5o3BtU4tBwx2w1GK)) | [Visit Preview](https://docsporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/docsporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |
| **id.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/id.porto/9T2R8ZAJjHrBPAHctFAeGQNskUkH)) | [Visit Preview](https://idporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/idporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |
| **manage.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/manage.porto/GsUQPHVwTeXss3hSD34Tzf4GnveU)) | [Visit Preview](https://manageporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/manageporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |
| **playground.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/playground.porto/FRLBgm41jdnP6EjuevQfSambxESk)) | [Visit Preview](https://playgroundporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/playgroundporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |
| **wagmi.porto** | ✅ Ready ([Inspect](https://vercel.com/ithacaxyz/wagmi.porto/57hY87927ghwRDSeTensU6XH2wDH)) | [Visit Preview](https://wagmiporto-git-o-az-docs-01-ithacaxyz.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/wagmiporto-git-o-az-docs-01-ithacaxyz.vercel.app?via=pr-comment-feedback-link) | May 22, 2025 2:05pm |







author_association: NONE