Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions delegation-toolkit/concepts/delegation/caveat-enforcers.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,23 +118,23 @@ This "all-or-nothing" approach ensures that delegations only execute exactly as

## Caveat builder

While caveat enforcers operate at the smart contract level, most developers interact with them through the [`CaveatBuilder`](../../guides/delegation/restrict-delegation.md) interface in the MetaMask Delegation Toolkit.
While caveat enforcers operate at the smart contract level, most developers interact with them through the `CaveatBuilder` interface in the MetaMask Delegation Toolkit.

The `CaveatBuilder` provides a developer-friendly TypeScript API that:

- Abstracts away the complexity of correctly formatting and encoding caveat terms.
- Provides type-checking and validation for caveat parameters.
- Handles the creation of the `caveats` array needed when creating a delegation.

Each [caveat type](../../reference/caveats.md) in the `CaveatBuilder`
Each [caveat type](../../reference/delegation/caveats.md) in the `CaveatBuilder`
corresponds to a specific caveat enforcer contract. For example, when you use:

```typescript
caveatBuilder.addCaveat("allowedTargets", ["0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92"]);
```

The builder is creating a caveat that references the
[`AllowedTargetsEnforcer`](../../reference/caveats.md#allowedtargets) contract address and
[`AllowedTargetsEnforcer`](../../reference/delegation/caveats.md#allowedtargets) contract address and
properly encodes the provided addresses as terms for that enforcer.

## Caveat enforcer best practices
Expand All @@ -144,14 +144,14 @@ When designing delegations with caveats, consider these best practices:
- **Combine caveat enforcers appropriately** - Use multiple caveat enforcers to create comprehensive restrictions.

- **Consider caveat enforcer order** - When using caveat enforcers that modify external contract states, the order matters.
For example, using [`NativeTokenPaymentEnforcer`](../../reference/caveats.md#nativetokenpayment) before
[`NativeBalanceChangeEnforcer`](../../reference/caveats.md#nativebalancechange) might cause validation failures.
For example, using [`NativeTokenPaymentEnforcer`](../../reference/delegation/caveats.md#nativetokenpayment) before
[`NativeBalanceChangeEnforcer`](../../reference/delegation/caveats.md#nativebalancechange) might cause validation failures.

- **Be careful with unbounded delegations** - Always include appropriate caveat enforcers to limit what a delegate can do.

## Available caveat enforcers

The Delegation Toolkit provides [out-of-the-box caveat enforcers](../../reference/caveats.md)
The Delegation Toolkit provides [out-of-the-box caveat enforcers](../../reference/delegation/caveats.md)
for common restriction patterns, including:

- Limiting target addresses and methods.
Expand Down
26 changes: 13 additions & 13 deletions delegation-toolkit/concepts/delegation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,28 @@ You can create the following delegation types:
In a chain of delegations, the first delegation is the root delegation.
For example, Alice delegates the ability to spend her USDC to Bob, limiting the amount to 100 USDC.

Use [`createDelegation`](../../reference/api/delegation.md#createdelegation) to create a root delegation.
Use [`createDelegation`](../../reference/delegation/index.md#createdelegation) to create a root delegation.

- **Open root delegation** - An open root delegation is a root delegation that doesn't specify a delegate.
This means that any account can redeem the delegation.
For example, Alice delegates the ability to spend 100 of her USDC to anyone.

You must create open root delegations carefully, to ensure that they are not misused.
Use [`createOpenDelegation`](../../reference/api/delegation.md#createopendelegation) to create an open root delegation.
Use [`createOpenDelegation`](../../reference/delegation/index.md#createopendelegation) to create an open root delegation.

- **Redelegation** - A delegate can redelegate permissions that have been granted to them, creating a chain of delegations across trusted parties.
For example, Alice delegates the ability to spend 100 of her USDC to Bob.
Bob redelegates the ability to spend 50 of Alice's 100 USDC to Carol.

Use [`createDelegation`](../../reference/api/delegation.md#createdelegation) to create a redelegation.
Use [`createDelegation`](../../reference/delegation/index.md#createdelegation) to create a redelegation.

- **Open redelegation** - An open redelegation is a redelegation that doesn't specify a delegate.
This means that any account can redeem the redelegation.
For example, Alice delegates the ability to spend 100 of her USDC to Bob.
Bob redelegates the ability to spend 50 of Alice's 100 USDC to anyone.

As with open root delegations, you must create open redelegations carefully, to ensure that they are not misused.
Use [`createOpenDelegation`](../../reference/api/delegation.md#createopendelegation) to create an open redelegation.
Use [`createOpenDelegation`](../../reference/delegation/index.md#createopendelegation) to create an open redelegation.

## Delegation Framework

Expand All @@ -79,7 +79,7 @@ It consists of the following components:
- **Delegation Manager** - The Delegation Manager validates delegations and triggers executions
on behalf of the delegator, ensuring tasks are executed accurately and securely.

When you redeem a delegation using [`redeemDelegations`](../../reference/api/delegation.md#redeemdelegations), the Delegation Manager performs the following steps.
When you redeem a delegation using [`redeemDelegations`](../../reference/delegation/index.md#redeemdelegations), the Delegation Manager performs the following steps.
It processes a single step for all redemptions before proceeding to the next one:

1. Validates the input data by ensuring the lengths of `delegations`, `modes`, and
Expand Down Expand Up @@ -150,30 +150,30 @@ sequenceDiagram

## Execution modes

When redeeming a delegation using [`redeemDelegations`](../../reference/api/delegation.md#redeemdelegations), you must pass an execution mode for each delegation chain you pass to the method.
When redeeming a delegation using [`redeemDelegations`](../../reference/delegation/index.md#redeemdelegations), you must pass an execution mode for each delegation chain you pass to the method.
The Delegation Toolkit supports the following execution modes, based on [ERC-7579](https://erc7579.com/):

| Execution mode | Number of delegation chains passed to `redeemDelegations` | Processing method | Does user operation continue execution if redemption reverts? |
|--|--|--|--|
| `SINGLE_DEFAULT_MODE` | One | Sequential | No |
| `SINGLE_TRY_MODE` | One | Sequential | Yes |
| `BATCH_DEFAULT_MODE` | Multiple | Interleaved | No |
| `BATCH_TRY_MODE` | Multiple | Interleaved | Yes |
| `SingleDefault` | One | Sequential | No |
| `SingleTry` | One | Sequential | Yes |
| `BatchDefault` | Multiple | Interleaved | No |
| `BatchTry` | Multiple | Interleaved | Yes |

### Sequential processing

In `SINGLE` modes, processing is sequential:
In `Single` modes, processing is sequential:

1. For each delegation in the chain, all caveats' `before` hooks are called.
2. The single redeemed action is executed.
3. For each delegation in the chain, all caveats' `after` hooks are called.

### Interleaved processing

In `BATCH` modes, processing is interleaved:
In `Batch` modes, processing is interleaved:

1. For each chain in the batch, and each delegation in the chain, all caveats' `before` hooks are called.
2. Each redeemed action is executed.
3. For each chain in the batch, and each delegation in the chain, all caveats' `after` hooks are called.

`BATCH` mode allows for powerful use cases, but the Delegation Framework currently does not include any `BATCH` compatible caveat enforcers.
`Batch` mode allows for powerful use cases, but the Delegation Framework currently does not include any `Batch` compatible caveat enforcers.
4 changes: 2 additions & 2 deletions delegation-toolkit/concepts/smart-accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ See [Create a smart account](../guides/smart-accounts/create-smart-account.md) t
### Hybrid smart account

The Hybrid smart account is a flexible implementation that supports both an externally owned account (EOA) owner and any number of passkey (WebAuthn) signers.
You can configure any of these signers as the signatory, and use them to sign any data, including user operations, on behalf of the smart account.
You can configure any of these signers, and use them to sign any data, including user operations, on behalf of the smart account.

This type is referenced in the toolkit as `Implementation.Hybrid`.

Expand Down Expand Up @@ -79,7 +79,7 @@ The MetaMask Smart Accounts flow is as follows:
tokens or third-party sponsorship.

2. **User operation creation** - For actions such as sending transactions, a user operation is created with
necessary details and signed by the configured signatory.
necessary details and signed by the configured signers.

3. **Bundlers and mempool** - The signed user operation is submitted to a special mempool, where bundlers
collect and package multiple user operations into a single transaction to save on gas costs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ This data encodes the authority that lets the delegate redeem the permission.
### Security considerations for `accountMeta`

When a user grants a permission, they can provide `accountMeta` which is an array of `factory` and `factoryData` values.
These calls must be executed before redeeming the permission (this is handled for you in [`sendUserOperationWithDelegation`](../reference/api/experimental-actions/bundler-client.md#senduseroperationwithdelegation)).
These calls must be executed before redeeming the permission (this is handled for you in [`sendUserOperationWithDelegation`](../reference/erc7715/bundler-client.md#senduseroperationwithdelegation)).

Because each `accountMeta` is an arbitrary call specified by the granter, it is important that these are executed carefully.
We recommend taking the following precautions:
Expand All @@ -86,7 +86,7 @@ Redeem a delegation with a [MetaMask smart account](#redeem-with-a-metamask-smar
To redeem a delegation with a MetaMask smart account, [create a smart account](../guides/smart-accounts/create-smart-account.md)
and a [Viem Bundler Client](https://viem.sh/account-abstraction/clients/bundler).

After setting up your Bundler Client, you can extend its functionality with `erc7710BundlerActions` actions to support ERC-7710. Once extended, use [`sendUserOperationWithDelegation`](../reference/api/experimental-actions/bundler-client.md#senduseroperationwithdelegation) to redeem the permission.
After setting up your Bundler Client, you can extend its functionality with `erc7710BundlerActions` actions to support ERC-7710. Once extended, use [`sendUserOperationWithDelegation`](../reference/erc7715/bundler-client.md#senduseroperationwithdelegation) to redeem the permission.

<Tabs>
<TabItem value="example.ts">
Expand Down Expand Up @@ -146,7 +146,7 @@ export const sessionAccount = await toMetaMaskSmartAccount({
implementation: Implementation.Hybrid,
deployParams: [account.address, [], [], []],
deploySalt: "0x",
signatory: { account },
signer: { account },
});

export const bundlerClient = createBundlerClient({
Expand All @@ -168,7 +168,7 @@ export const bundlerClient = createBundlerClient({

To redeem a delegation with an EOA, create a [Viem Wallet Client](https://viem.sh/docs/clients/wallet).

After creating your Wallet Client, you can extend its functionality with `erc7710WalletActions` actions to support ERC-7710. Once extended, use [`sendTransactionWithDelegation`](../reference/api/experimental-actions/wallet-client.md#sendtransactionwithdelegation) to redeem the permission.
After creating your Wallet Client, you can extend its functionality with `erc7710WalletActions` actions to support ERC-7710. Once extended, use [`sendTransactionWithDelegation`](../reference/erc7715/wallet-client.md#sendtransactionwithdelegation) to redeem the permission.

<Tabs>
<TabItem value="example.ts">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const sessionAccount = await toMetaMaskSmartAccount({
implementation: Implementation.Hybrid,
deployParams: [account.address, [], [], []],
deploySalt: "0x",
signatory: { account },
signer: { account },
});

export const walletClient = createWalletClient({
Expand Down Expand Up @@ -165,7 +165,7 @@ You should always verify the granted permissions and adjust your dapp's behavior
## Security considerations for `accountMeta`

When a user grants a permission, they can provide [`accountMeta`](erc-7710-redeem-delegations.md#extract-relevant-data) which is an array of `factory` and `factoryData` values.
These calls must be executed before redeeming the permission (this is handled for you in [`sendUserOperationWithDelegation`](../reference/api/experimental-actions/bundler-client.md#senduseroperationwithdelegation)).
These calls must be executed before redeeming the permission (this is handled for you in [`sendUserOperationWithDelegation`](../reference/erc7715/bundler-client.md#senduseroperationwithdelegation)).

Because each `accountMeta` is an arbitrary call specified by the granter, it is important that these are executed carefully.
We recommend taking the following precautions:
Expand Down
2 changes: 1 addition & 1 deletion delegation-toolkit/get-started/erc7715-quickstart.md
Comment thread
AyushBherwani1998 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const sessionAccount = await toMetaMaskSmartAccount({
implementation: Implementation.Hybrid,
deployParams: [account.address, [], [], []],
deploySalt: "0x",
signatory: { account },
signer: { account },
});
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const smartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Stateless7702,
address,
signatory: { walletClient },
signer: { walletClient },
});
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const smartAccount = await toMetaMaskSmartAccount({
implementation: Implementation.Hybrid,
deployParams: [account.address, [], [], []],
deploySalt: "0x",
signatory: { account },
signer: { account },
});
```

Expand Down
6 changes: 3 additions & 3 deletions delegation-toolkit/guides/configure-toolkit.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const delegatorSmartAccount = await toMetaMaskSmartAccount({
implementation: Implementation.Hybrid,
deployParams: [delegatorAccount.address, [], [], []],
deploySalt: "0x",
signatory: { account: delegatorAccount },
signer: { account: delegatorAccount },
});

export delegatorSmartAccount;
Expand All @@ -116,7 +116,7 @@ export delegatorSmartAccount;
See the changelog of the toolkit version you are using (in the left sidebar) for supported chains.
:::

Alternatively, you can use the [`getDelegatorEnvironment`](../reference/api/delegation.md#getdelegatorenvironment) function to resolve the environment.
Alternatively, you can use the [`getDelegatorEnvironment`](../reference/delegation/index.md#getdelegatorenvironment) function to resolve the environment.
This function is especially useful if your delegator is not a smart account when
creating a [redelegation](../concepts/delegation/index.md#delegation-types).

Expand All @@ -132,7 +132,7 @@ const environment: DeleGatorEnvironment = getDelegatorEnvironment(11155111);

### Deploy a custom environment

You can deploy the contracts using any method, but the toolkit provides a convenient [`deployDelegatorEnvironment`](../reference/api/delegation.md#deploydelegatorenvironment) function. This function simplifies deploying the Delegation Framework contracts to your desired EVM chain.
You can deploy the contracts using any method, but the toolkit provides a convenient [`deployDelegatorEnvironment`](../reference/delegation/index.md#deploydelegatorenvironment) function. This function simplifies deploying the Delegation Framework contracts to your desired EVM chain.

This function requires a Viem [Public Client](https://viem.sh/docs/clients/public.html), [Wallet Client](https://viem.sh/docs/clients/wallet.html), and [Chain](https://viem.sh/docs/glossary/types#chain)
to deploy the contracts and resolve the `DeleGatorEnvironment`.
Expand Down
104 changes: 104 additions & 0 deletions delegation-toolkit/guides/delegation/check-delegation-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
description: Learn how to check the delegation state.
sidebar_label: Check the delegation state
toc_max_heading_level: 3
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Check the delegation state

When using [spending limit delegation scopes](use-delegation-scopes/spending-limit.md) or relevant [caveat enforcers](../../reference/delegation/caveats.md),
you might need to check the remaining transferrable amount in a delegation.
For example, if a delegation allows a user to spend 10 USDC per week and they have already spent 10 - n USDC in the current period,
you can determine how much of the allowance is still available for transfer.

Use the `CaveatEnforcerClient` to check the available balances for specific scopes or caveats.

## Prerequisites

- [Install and set up the Delegation Toolkit.](../../get-started/install.md)
- [Create a delegator account.](execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)
- [Create a delegation with an ERC-20 periodic scope.](use-delegation-scopes/spending-limit.md#erc-20-periodic-scope)

## Create a `CaveatEnforcerClient`

To check the delegation state, create a [`CaveatEnforcerClient`](../../reference/delegation/caveat-enforcer-client.md).
This client allows you to interact with the caveat enforcers of the delegation, and read the required state.

<Tabs>
<TabItem value="example.ts">

```typescript
import { environment, publicClient as client } from './config.ts'
import { createCaveatEnforcerClient } from '@metamask/delegation-toolkit'

const caveatEnforcerClient = createCaveatEnforcerClient({
environment,
client,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript
import { sepolia as chain } from 'viem/chains'
import { createPublicClient, http } from 'viem'
import { getDeleGatorEnvironment } from '@metamask/delegation-toolkit'

export const environment = getDeleGatorEnvironment(chain.id)

export const publicClient = createPublicClient({
chain,
transport: http(),
})
```

</TabItem>
</Tabs>

## Read the caveat enforcer state

This example uses the [`getErc20PeriodTransferEnforcerAvailableAmount`](../../reference/delegation/caveat-enforcer-client.md#geterc20periodtransferenforceravailableamount) method to read the state and retrieve the remaining amount for the current transfer period.

<Tabs>
<TabItem value="example.ts">

```typescript
import { delegation } './config.ts'

// Returns the available amount for current period.
const { availableAmount } = await caveatEnforcerClient.getErc20PeriodTransferEnforcerAvailableAmount({
delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript
import { createDelegation } from '@metamask/delegation-toolkit'

export const delegation = createDelegation({
scope: {
type: 'erc20PeriodTransfer',
tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
periodAmount: 1000000000000000000n,
periodDuration: 86400,
startDate: 1743763600,
},
to: delegateAccount,
from: delegatorAccount,
environment: delegatorAccount.environment,
})
```

</TabItem>
</Tabs>

## Next steps

See the [Caveat Enforcer Client reference](../../reference/delegation/caveat-enforcer-client.md) for the full list of available methods.
Loading
Loading