diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 2a869fcb..1f081dcd 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -24,9 +24,9 @@ Fixes #???
-- [ ] I have read the [Contributing Guide](CONTRIBUTING.md)
-- [ ] I have added tests that prove my fix is effective or that my feature works
-- [ ] I have added documentation of new methods and any new behavior or changes to existing behavior
+- [ ] I have read the [Contributing Guide](../CONTRIBUTING.md#your-first-code-contribution)
+- [ ] I have added tests that prove my fix is effective or that my feature works. See [GUIDELINES.md#testing](../GUIDELINES.md#testing) for more information.
+- [ ] I have added documentation for new methods or changes to existing method behavior. See [GUIDELINES.md#documentation](../GUIDELINES.md#documentation) for more information.
- [ ] CI Workflows Are Passing
#### Further comments
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 55b77153..5819d7bf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -88,7 +88,7 @@ Explain the problem and include additional details to help maintainers reproduce
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
-* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
+* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
Include details about your configuration and environment:
diff --git a/GUIDELINES.md b/GUIDELINES.md
index c80fe1ca..c831ce49 100644
--- a/GUIDELINES.md
+++ b/GUIDELINES.md
@@ -27,6 +27,10 @@ TypeScript code should be written in a consistent format enforced by the project
## Documentation
+The online version of the Compact contracts documentation is maintained at [OpenZeppelin/docs](https://github.com/OpenZeppelin/docs).
+It should mirror all documentation embedded within the contracts themselves with additional context and usage examples if applicable.
+Pull requests in [OpenZeppelin/docs](https://github.com/OpenZeppelin/docs) should be linked to the corresponding pull request in this repo.
+
For contributors, project guidelines and processes must be documented publicly.
For users, features must be abundantly documented. Documentation should include answers to common questions, solutions to common problems, and recommendations for critical decisions that the user may face.
diff --git a/docs/.github/pull_request_template.md b/docs/.github/pull_request_template.md
new file mode 100644
index 00000000..df582dbb
--- /dev/null
+++ b/docs/.github/pull_request_template.md
@@ -0,0 +1,27 @@
+## Documentation Pull Request
+
+### Summary
+
+
+### Type of Change
+
+- [ ] New documentation
+- [ ] Documentation update/revision
+- [ ] Fix typos or grammar
+- [ ] Restructure/reorganize content
+- [ ] Add examples or tutorials
+- [ ] Update API documentation
+- [ ] Other: ___________
+
+### Related Issues
+
+Fixes #
+Relates to #
+
+### Checklist
+- [ ] Build succeeds locally with `pnpm run build`
+- [ ] Lint is successful when running `pnpm run check`
+- [ ] Docs follow [OpenZeppelin Documentation Standards](https://github.com/OpenZeppelin/docs/blob/main/STANDARDS.md)
+
+### Additional Notes
+
diff --git a/docs/.github/workflows/lint.yml b/docs/.github/workflows/lint.yml
new file mode 100644
index 00000000..d1f9d6bb
--- /dev/null
+++ b/docs/.github/workflows/lint.yml
@@ -0,0 +1,40 @@
+name: Lint & Format
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+env:
+ NEXT_TELEMETRY_DISABLED: 1
+
+jobs:
+ lint:
+ name: Lint and Format Check
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [22]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v5
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: "pnpm"
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Run lint and format checks
+ run: pnpm run check
+
+ - name: Build check
+ run: pnpm run build
diff --git a/docs/.github/workflows/sync-search.yml b/docs/.github/workflows/sync-search.yml
new file mode 100644
index 00000000..d3bd3391
--- /dev/null
+++ b/docs/.github/workflows/sync-search.yml
@@ -0,0 +1,27 @@
+name: Sync Search Content
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ sync-search:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Setup Bun
+ uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+
+ - name: Install dependencies
+ run: bun install
+
+ - name: Run sync search content
+ run: bun run scripts/sync-search-content.ts
+ env:
+ NEXT_PUBLIC_ALGOLIA_ID: ${{ secrets.NEXT_PUBLIC_ALGOLIA_ID }}
+ ALGOLIA_PRIVATE_KEY: ${{ secrets.ALGOLIA_PRIVATE_KEY }}
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..cee20a5c
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,35 @@
+# deps
+/node_modules
+
+# generated content
+.contentlayer
+.content-collections
+.source
+
+# test & build
+/coverage
+/.next/
+/out/
+/build
+*.tsbuildinfo
+
+# misc
+.DS_Store
+*.pem
+/.pnp
+.pnp.js
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# others
+.env*.local
+.vercel
+next-env.d.ts
+old-docs
+.claude
+TODO.md
+broken-links.md
+
+# Local Netlify folder
+.netlify
diff --git a/docs/AGENTS.md b/docs/AGENTS.md
new file mode 100644
index 00000000..2895004c
--- /dev/null
+++ b/docs/AGENTS.md
@@ -0,0 +1,118 @@
+# AGENTS.md - OpenZeppelin Docs Codebase Guide
+
+## Build/Lint/Test Commands
+- `pnpm run build` - Build the Next.js application
+- `pnpm run dev` - Start development server with turbo
+- `pnpm run start` - Start production server
+- `pnpm run postinstall` - Process MDX files with fumadocs-mdx
+- `pnpm run lint` - Lint code with Biome
+- `pnpm run lint:fix` - Lint and auto-fix issues with Biome
+- `pnpm run format` - Check code formatting with Biome
+- `pnpm run format:fix` - Format code with Biome
+- `pnpm run check` - Run both linting and formatting checks
+- `pnpm run check:fix` - Run both linting and formatting with auto-fix
+- No test commands configured - this is a documentation site
+
+## Navigation Management
+The site uses a **modular JSON navigation system** instead of fumadocs meta.json files:
+
+### Navigation Structure
+- `src/navigation/` - Modular navigation configuration
+ - `types.ts` - TypeScript interfaces for navigation
+ - `contracts.json` - All contract-related navigation
+ - `tools.json` - Tools section navigation
+ - `ecosystems.json` - Ecosystem-specific sections
+ - `index.ts` - Combines all sections into navigationTree
+
+### Editing Navigation
+- **Add new pages**: Edit the relevant JSON file (contracts/tools/ecosystems)
+- **Reorder sections**: Modify array order in respective JSON files
+- **Add new sections**: Create new JSON file and import in `index.ts`
+- **Do NOT use meta.json files** - they have been removed and are not supported
+
+## Code Style Guidelines
+
+### TypeScript/JavaScript
+- Use TypeScript strict mode (enabled in tsconfig.json)
+- Prefer named imports: `import { RootProvider } from 'fumadocs-ui/provider'`
+- Use path aliases: `@/*` for src/, `@/.source` for .source/
+- Function components with explicit return types when needed
+- Use React 19+ features and patterns
+
+### File Structure
+- Source files in `src/` directory
+- Documentation content in `content/` with nested version folders (v2.x, v3.x, etc.)
+- Examples in `examples/` directory organized by feature
+- Public assets in `public/` directory
+- Navigation config in `src/navigation/` directory
+
+### Naming Conventions
+- PascalCase for React components and interfaces
+- camelCase for variables and functions
+- kebab-case for file names in content directories
+
+## Markdown Link Cleanup Strategy
+
+### Problem
+Legacy markdown files often contain complex, unreadable link syntax that creates URL-encoded URLs like:
+```
+http://localhost:3000/api/access#has_role(role:-felt252,-account:-contractaddress)-%E2%86%92-bool-external
+```
+
+### Solution Approach
+When cleaning up markdown files with complex link syntax, follow this systematic approach:
+
+#### 1. Identify Complex Link Patterns
+Look for these problematic patterns:
+- **Function list links**: `[`+function_name+`](#`[.contract-item-name]#`function_name`#`(params)``-[.item-kind]#external#)`
+- **Event list links**: `[`+EventName+`](#`[.contract-item-name]#`eventname`#`(params)``-[.item-kind]#event#)`
+- **Function headings**: `#### `[.contract-item-name]#`function_name`#`(params)`` [.item-kind]#external#`
+
+#### 2. Create Clean Link Strategy
+Replace with simple, readable format:
+- **Clean list links**: `[`function_name`](#prefix-function_name)`
+- **Clean headings with anchors**:
+ ```markdown
+
+ #### `function_name(params) → return_type`
+ ```
+
+#### 3. Anchor ID Naming Convention
+Use descriptive prefixes to avoid conflicts:
+- `iaccesscontrol-` for interface functions/events
+- `component-` for component functions/events
+- `extension-` for extension functions/events
+
+#### 4. Implementation Process
+1. **Use Task agent** for systematic fixes across large files
+2. **Fix by section** - group related functions/events together
+3. **Update both links and targets** - ensure table of contents links point to correct anchors
+4. **Verify no complex patterns remain** - search for `[.contract-item-name]#` and `[.item-kind]#`
+
+#### 5. Benefits
+- ✅ Clean, readable URLs
+- ✅ Better SEO and user experience
+- ✅ Easier maintenance and debugging
+- ✅ Consistent markdown formatting
+
+### Example Before/After
+
+**Before (Complex):**
+```markdown
+* [`+has_role(role, account)+`](#`[.contract-item-name]#`has_role`#`(role:-felt252,-account:-contractaddress)-→-bool``-[.item-kind]#external#)
+
+#### `[.contract-item-name]#`has_role`#`(role: felt252, account: ContractAddress) → bool`` [.item-kind]#external#
+```
+
+**After (Clean):**
+```markdown
+* [`has_role(role, account)`](#iaccesscontrol-has_role)
+
+
+#### `has_role(role: felt252, account: ContractAddress) → bool`
+```
+
+### Framework Compatibility Notes
+- **DO NOT use `{#anchor}` syntax** - breaks the framework parser
+- **USE HTML anchor tags** - `` format is safe
+- **Test locally** to ensure links work properly after changes
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 00000000..f6006a18
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,66 @@
+# Contributing
+
+Thank you for your interest in contributing to the OpenZeppelin Docs! We welcome contributions from everyone.
+
+## How to Contribute
+
+Please follow this guide if you have something to contribute.
+
+### Reporting Issues
+
+If you find a bug or have a suggestion for improvement:
+
+1. Check if the issue already exists in [GitHub issues](https://github.com/OpenZeppelin/docs/issues)
+2. If not, create a new issue with a clear description
+3. Wait for a team member to comment before moving forward with a pull request
+
+### Making Changes
+
+1. Fork the repository
+2. Create a new branch for your change
+3. Follow the local development guide in the [README](README.md) or with the steps [below](#development-setup)
+4. Use [conventional commits](https://www.conventionalcommits.org/) when making changes
+5. Make sure your changes follow the [OpenZeppelin Docs Standards](STANDARDS.md)
+6. Submit a pull request
+
+### Pull Request Guidelines
+
+- Keep pull requests focused on a single feature or fix
+- Write clear commit messages
+- Spelling fixes should be grouped as much as possible (i.e. fixing multiple errors instead of just one)
+
+### Development Setup
+
+1. Make sure [pnpm](https://pnpm.io) is installed
+
+```bash
+pnpm --version
+```
+
+2. Clone the repo and install dependencies
+
+```bash
+git clone https://github.com/OpenZeppelin/docs
+cd docs
+pnpm install
+```
+
+3. Run the `dev` server to see a live preview and have your changes reflected at `http://localhost:3000`
+
+```bash
+pnpm dev
+```
+
+4. After making changes run the lint command to make formatting rules are applied
+
+```bash
+pnpm run check:fix
+```
+
+## Code of Conduct
+
+Please be respectful and constructive in all interactions. We strive to maintain a welcoming and inclusive environment for all contributors.
+
+## Questions?
+
+If you have questions about contributing, feel free to open an issue or reach out to the maintainers.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..4236219e
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,208 @@
+# OpenZeppelin Docs
+
+
+
+Welcome to the OpenZeppelin Docs repo! Before opening an issue or creating a PR please consult our [contribution guide](CONTRIBUTING.md) as well as the [OpenZeppelin Documentation Standards](STANDARDS.md)
+
+## Development
+
+This is a Next.js application generated with [Fumadocs](https://github.com/fuma-nama/fumadocs).
+
+To start local development follow the steps below
+
+**1. Make sure [pnpm](https://pnpm.io) is installed**
+
+```bash
+pnpm --version
+```
+
+**2. Clone the repo and install dependencies**
+
+```bash
+git clone https://github.com/OpenZeppelin/docs
+cd docs
+pnpm install
+```
+
+**3. Run the `dev` server to see a live preview and have your changes reflected at `http://localhost:3000`**
+
+```bash
+pnpm dev
+```
+
+**4. Run `build` and `lint`**
+
+```bash
+pnpm run build
+pnpm run check
+```
+
+## Project Structure
+
+### Content Organization
+
+The documentation content is organized in the `content/` directory with the following structure:
+
+```
+content/
+├── community-contracts/ # Community-contributed contracts
+├── confidential-contracts/ # Confidential/privacy-focused contracts
+├── contracts/ # Core OpenZeppelin Contracts documentation
+├── contracts-cairo/ # Cairo contracts for StarkNet
+├── contracts-compact/ # Compact contract implementations
+├── contracts-stylus/ # Stylus contracts for Arbitrum
+├── ui-builder/ # UI Builder documentation
+├── defender/ # Defender platform documentation
+├── monitor/ # Monitoring tools documentation
+├── relayer/ # Relayer service documentation
+├── stellar-contracts/ # Stellar blockchain contracts
+├── substrate-runtimes/ # Substrate runtime documentation
+├── uniswap-hooks/ # Uniswap v4 hooks
+├── upgrades-plugins/ # Upgrade plugins documentation
+├── upgrades.mdx # General upgrades guide
+└── wizard.mdx # Contract wizard documentation
+```
+
+Each product directory contains:
+- `index.mdx` - Main documentation entry point
+- `changelog.mdx` - Version history and changes
+- Subdirectories for specific features/modules
+- API reference files
+
+### Application Structure
+
+| Path | Description |
+| --------------------------------------- | -------------------------------------------------------------- |
+| `src/app/(docs)/` | Documentation pages route group |
+| `src/app/(docs)/layout.tsx` | Docs layout wrapper |
+| `src/app/(docs)/[...slug]/page.tsx` | Dynamic documentation pages |
+| `src/app/page.tsx` | Homepage |
+| `src/app/layout.tsx` | Root application layout |
+| `src/app/layout.config.tsx` | Shared layout configuration and navigation |
+| `src/components/` | Reusable React components |
+| `src/components/layout/` | Layout-specific components |
+| `src/components/icons/` | Custom SVG icons for products |
+| `src/components/ui/` | UI component library |
+| `src/lib/source.ts` | Content source adapter with Fumadocs loader |
+
+### Configuration Files
+
+- `source.config.ts` - Fumadocs MDX configuration with math, mermaid, and code highlighting
+- `next.config.mjs` - Next.js configuration
+- `postcss.config.mjs` - PostCSS configuration for styling
+
+## Navigation & Components
+
+### Navigation Structure
+
+The top navigation is configured in `src/app/layout.config.tsx` and includes:
+
+- **Main Navigation**: Home, Forum, Website links
+- **Product Categories**: Auto-generated from content structure
+- **Search**: Full-text search across all documentation
+- **Theme Toggle**: Light/dark mode switching
+
+Sidebar navigation is handled in `src/navigation/` where multiple navigation JSON trees are exported and used inside `src/components/layout/docs-layout-client.tsx`
+
+### Key Components
+
+#### Layout Components
+- `DocsLayoutClient` - Client-side docs layout with sidebar
+- `BaseLayoutProps` - Shared layout configuration
+- `PageClient` - Individual page wrapper
+
+#### UI Components
+- `Card` & `SmallCard` - Content cards for homepage
+- `TOC` - Table of contents with scrollspy
+- `Search` - Search interface with custom results
+- `ThemeToggle` - Theme switching
+- `VersionBanner` - Version-specific messaging
+
+#### Custom Icons
+Product-specific icons located in `src/components/icons/`:
+- Ethereum, Arbitrum, StarkNet, Stellar, Polkadot chains
+- Product icons for Contracts, Defender, Monitor, etc.
+- Tool icons for Wizard, Ethernaut, etc.
+
+### Content Features
+
+#### MDX Enhancements
+- **Math Support**: LaTeX math rendering with KaTeX
+- **Mermaid Diagrams**: Flowcharts and diagrams
+- **Code Highlighting**: Multi-theme syntax highlighting
+- **OpenAPI Integration**: Automatic API documentation generation
+
+#### Interactive Elements
+- **OpenZeppelin Wizard**: Embedded contract generation tool
+- **Code Examples**: Copy-to-clipboard functionality
+- **Version Switching**: Multi-version documentation support
+- **Responsive Design**: Mobile-optimized navigation and content
+
+## Solidity Docgen
+
+Any library using Solidity Docgen can utilize the `docgen` templates and config file in their repo to generate markdown API references for the docs. To get started follow the instructions below:
+
+### 1. Add the templates to your repo
+
+Inside this docs repo is the [`docgen`](https://github.com/OpenZeppelin/docs/tree/main/docgen) folder which contains [`templates-md`](https://github.com/OpenZeppelin/docs/tree/main/docgen/templates-md) and [`config-md.js`](https://github.com/OpenZeppelin/docs/blob/main/docgen/config-md.js). Copy both of these items into your `docs` folder in your repo. Once there open the [`templates-md/helpers.js`](https://github.com/OpenZeppelin/docs/blob/main/docgen/templates-md/helpers.js) file and update the `API_DOCS_PATH` constant to match your export path.
+
+```js
+const API_DOCS_PATH = 'contracts/5.x/api';
+// const API_DOCS_PATH = 'community-contracts/api';
+// const API_DOCS_PATH = 'confidential-contracts/api';
+// const API_DOCS_PATH = 'uniswap-hooks/api';
+```
+
+### 2. Update the `hardhat.config.js` file
+
+With the `config-md.js` file now in the `docs` folder, update your `hardhat.config.js` to use the new config file.
+
+```js
+{
+ // other config options
+ docgen: require('./docs/config-md'),
+}
+```
+
+Once added make sure these are accessible in your branches going forward. If you are generating an API reference for previous branches you will need to repeat steps 1 and 2 for those branches.
+
+### 3. Run the `generate-api-docs.js` script
+
+With your remote repo setup with the new template files you can run the `scripts/generate-api-docs.js` script. Be sure to pass in the correct arguements for your docs
+
+```bash
+node scripts/generate-api-docs.js \
+ --repo https://github.com/OpenZeppelin/openzeppelin-community-contracts.git \
+ --branch release-v5.5 \
+ --api-output content/contracts/5.x/api \
+ --examples-output examples
+```
+
+This wil lexport the contents to
+
+### Automated Setup
+
+In the case you want to setup an automated GitHub workflow to create these API docs visit the [docs-api-generation-workflows](https://github.com/OpenZeppelin/docs-api-generation-workflows) for more info. This repo (`OpenZeppelin/docs`) is the `Docs Receiver` side of the equation.
+
+## Content Management
+
+### Adding New Content
+
+1. Create `.mdx` files in appropriate `content/` subdirectories
+2. Use frontmatter for metadata (title, description, etc.)
+3. Follow existing directory structure for consistency
+4. Update navigation if adding new product categories
+
+### Versioning
+
+- Version-specific content in numbered subdirectories (e.g., `contracts/4.x/`)
+- Latest content at root level of each product directory
+- Automatic version detection and routing
+
+## Learn More
+
+To learn more about the technologies used:
+
+- [Next.js Documentation](https://nextjs.org/docs) - React framework features and API
+- [Fumadocs](https://fumadocs.vercel.app) - Documentation framework
+- [MDX](https://mdxjs.com/) - Markdown with JSX components
diff --git a/docs/STANDARDS.md b/docs/STANDARDS.md
new file mode 100644
index 00000000..b5ef85a2
--- /dev/null
+++ b/docs/STANDARDS.md
@@ -0,0 +1,80 @@
+## OpenZeppelin Documentation Standards
+
+OpenZeppelin has implemented a categorization standard to be used across all ecosystems to help ensure our contributors cover the bases for the ideal documentation:
+
+](https://docs.divio.com/assets/images/overview-8b21327c9a55ca08c6712f26bda2113c.png)
+
+From [`https://docs.divio.com/documentation-system/`](https://docs.divio.com/documentation-system/)
+
+The OpenZeppelin approach to achieve this goal will include the following sections
+
+### Quickstart
+
+*Zero to working project in one page*
+
+👤 Primary Owner: Library Developers
+
+⊞ Quadrant: Problem-Oriented/How-To Guides
+
+📖 [Quickstart Example](https://docs.openzeppelin.com/relayer/quickstart)
+
+
+### Learn
+
+*Conceptual learning about the library or tool that include example usage code snippets*
+
+👤 Primary Owner: Library Developers
+
+⊞ Quadrant: Understanding-Oriented/Explanation
+
+📖 [Learn Example](https://docs.openzeppelin.com/contracts/5.x/utilities)
+
+
+### Guides / Tutorials
+
+*Step by step guides to achieve a particular goal or solve a specific problem*
+
+👤 Primary Owner: Devrel
+
+⊞ Quadrants: Problem-Oriented/How-To Guides & Learning-Oriented/Tutorials
+
+📖 [Guide Example](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts)
+
+
+### Reference
+
+*Easy to access answers for a specific implementation*
+
+👤 Primary Owner: Library Developers
+
+⊞ Quadrants: Information-Oriented/Reference
+
+📖 [Reference Example](https://docs.openzeppelin.com/contracts-cairo/alpha/api/access)
+
+
+It should be noted that not every library or tool may have every section, and that’s ok. This is purely a guide to help kickstart helpful documentation, not a strict pattern to follow.
+
+
+## Implementation
+
+- All developers should keep this pattern in mind as they build out their documentation
+- Devrel will step in to help create tutorials for releases, contributions from primary developers welcome if time allows
+- Devrel will review all documentation PRs for QA and provide feedback
+
+## FAQ
+
+- **Who should my Quickstart target?**
+
+ Write your quickstart as if the reader has basic dev knowledge (node.js, some solidity, CLI tools, etc) but knows nothing about your library or how to get it started with particular ecosystem tools. By all means link out to other instructions that help new users get their dev environment setup
+
+- **What if my tool or library has documentation that doesn’t fit into these categories?**
+
+ That’s ok! Ideally everything should fit into these categories, but if not then craft your docs for the optimal user experience first and foremost. If you’re unsure then contact @Steve Simkins
+
+- **What if I don’t have enough content to fill a category (ie there’s just one guide)**
+
+ If you find yourself in a case where the categorization doesn’t fit because there isn’t enough content to fill those sections, refactor them to fit your use-case. @Steve Simkins will review changes to make sure they align.
+
+- **What if I don’t know how to communicate the concepts or ideals behind what I’m building?**
+
+ This is normal! Writing and communication is a skill that takes time. If you find yourself stuck or need assistance with writing docs just let @Steve Simkins know!
diff --git a/docs/antora.yml b/docs/antora.yml
deleted file mode 100644
index c1059d1e..00000000
--- a/docs/antora.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: contracts-compact
-title: Contracts for Compact
-version: 0.0.1
-nav:
- - modules/ROOT/nav.adoc
-asciidoc:
- attributes:
- page-sidebar-collapse-default: 'Access,Security,FungibleToken,NonFungibleToken,MultiToken,Utils'
diff --git a/docs/biome.json b/docs/biome.json
new file mode 100644
index 00000000..8575558f
--- /dev/null
+++ b/docs/biome.json
@@ -0,0 +1,52 @@
+{
+ "$schema": "https://biomejs.dev/schemas/2.2.2/schema.json",
+ "vcs": {
+ "enabled": false,
+ "clientKind": "git",
+ "useIgnoreFile": false
+ },
+ "files": {
+ "ignoreUnknown": false
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "tab"
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "suspicious": {
+ "noUnknownAtRules": "off"
+ },
+ "security": {
+ "noDangerouslySetInnerHtml": "off"
+ },
+ "correctness": {
+ "useUniqueElementIds": "off"
+ },
+ "a11y": {
+ "useKeyWithClickEvents": "off",
+ "noStaticElementInteractions": "off"
+ }
+ }
+ },
+ "css": {
+ "linter": {
+ "enabled": true
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "double"
+ }
+ },
+ "assist": {
+ "enabled": true,
+ "actions": {
+ "source": {
+ "organizeImports": "on"
+ }
+ }
+ }
+}
diff --git a/docs/cli.json b/docs/cli.json
new file mode 100644
index 00000000..8a9e3361
--- /dev/null
+++ b/docs/cli.json
@@ -0,0 +1,11 @@
+{
+ "aliases": {
+ "uiDir": "./components/ui",
+ "componentsDir": "./components",
+ "blockDir": "./components",
+ "cssDir": "./styles",
+ "libDir": "./lib"
+ },
+ "baseDir": "src",
+ "commands": {}
+}
\ No newline at end of file
diff --git a/docs/components.json b/docs/components.json
new file mode 100644
index 00000000..e81dc038
--- /dev/null
+++ b/docs/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/app/global.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/docs/content/community-contracts/account-modules.mdx b/docs/content/community-contracts/account-modules.mdx
new file mode 100644
index 00000000..e00cd757
--- /dev/null
+++ b/docs/content/community-contracts/account-modules.mdx
@@ -0,0 +1,120 @@
+---
+title: Account Modules
+---
+
+Smart accounts built with [ERC-7579](https://eips.ethereum.org/EIPS/eip-7579) provide a standardized way to extend account functionality through modules (i.e. smart contract instances). This architecture allows accounts to support various features that are compatible with a wide variety of account implementations. See [compatible modules](https://erc7579.com/modules).
+
+## ERC-7579
+
+ERC-7579 defines a standardized interface for modular smart accounts. This standard enables accounts to install, uninstall, and interact with modules that extend their capabilities in a composable manner with different account implementations.
+
+### Accounts
+
+OpenZeppelin offers an implementation of an [`AccountERC7579`](/contracts/5.x/api/account#AccountERC7579) contract that allows installing modules compliant with this standard. There’s also an [`AccountERC7579Hooked`](/contracts/5.x/api/account#AccountERC7579Hooked) variant that supports installation of hooks. Like [most accounts](/contracts/5.x/accounts#handling-initialization), an instance should define an initializer function where the first module that controls the account will be set:
+
+./examples/account/MyAccountERC7579.sol
+
+
+For simplicity, the [`AccountERC7579Hooked`](/contracts/5.x/api/account#AccountERC7579Hooked) only supports a single hook. A common workaround is to install a [single hook with a multiplexer pattern](https://github.com/rhinestonewtf/core-modules/blob/7afffccb44d73dbaca2481e7b92bce0621ea6449/src/HookMultiPlexer/HookMultiPlexer.sol) to extend the functionality to multiple hooks.
+
+
+### Modules
+
+Functionality is added to accounts through encapsulated functionality deployed as smart contracts called _modules_. The standard defines four primary module types:
+
+* **Validator modules (type 1)**: Handle signature verification and user operation validation
+* **Executor modules (type 2)**: Execute operations on behalf of the account
+* **Fallback modules (type 3)**: Handle fallback calls for specific function selectors
+* **Hook modules (type 4)**: Execute logic before and after operations
+
+Modules can implement multiple types simultaneously, which means you could combine an executor module with hooks to enforce behaviors on an account, such as maintaining ERC-20 approvals or preventing the removal of certain permissions.
+
+See [popular module implementations](https://erc7579.com/modules).
+
+#### Building Custom Modules
+
+The library provides _standard composable modules_ as building blocks with an internal API for developers. By combining these components, you can create a rich set of variants without including unnecessary features.
+
+A good starting point is the [`ERC7579Executor`](/community-contracts/api/account#ERC7579Executor) or [`ERC7579Validator`](/community-contracts/api/account#ERC7579Validator), which include an opinionated base layer easily combined with other abstract modules. Hooks and fallback handlers are more straightforward to implement directly from interfaces:
+
+./examples/account/modules/MyERC7579Modules.sol
+
+
+Explore these abstract ERC-7579 modules in the [API Reference](/community-contracts/api/account#modules).
+
+
+#### Execution Modes
+
+ERC-7579 supports various execution modes, which are encoded as a `bytes32` value. The [`ERC7579Utils`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/account/utils/draft-ERC7579Utils.sol) library provides utility functions to work with these modes:
+
+```solidity
+// Parts of an execution mode
+type Mode is bytes32;
+type CallType is bytes1;
+type ExecType is bytes1;
+type ModeSelector is bytes4;
+type ModePayload is bytes22;
+```
+
+##### Call Types
+
+Call types determine the kind of execution:
+
+| Type | Value | Description |
+| --- | --- | --- |
+| `CALLTYPE_SINGLE` | `0x00` | A single `call` execution |
+| `CALLTYPE_BATCH` | `0x01` | A batch of `call` executions |
+| `CALLTYPE_DELEGATECALL` | `0xFF` | A `delegatecall` execution |
+
+##### Execution Types
+
+Execution types determine how failures are handled:
+
+| Type | Value | Description |
+| --- | --- | --- |
+| `EXECTYPE_DEFAULT` | `0x00` | Reverts on failure |
+| `EXECTYPE_TRY` | `0x01` | Does not revert on failure, emits an event instead |
+
+#### Execution Data Format
+
+The execution data format varies depending on the call type:
+
+* For single calls: `abi.encodePacked(target, value, callData)`
+* For batched calls: `abi.encode(Execution[])` where `Execution` is a struct containing `target`, `value`, and `callData`
+* For delegate calls: `abi.encodePacked(target, callData)`
+
+## Examples
+
+### Social Recovery
+
+Social recovery allows an account to be recovered when access is lost by relying on trusted parties ("guardians") who verify the user’s identity and help restore access.
+
+Social recovery is not a single solution but a design space with multiple configuration options:
+
+* Delay configuration
+* Expiration settings
+* Different guardian types
+* Cancellation windows
+* Confirmation requirements
+
+To support _different guardian types_, we can leverage ERC-7913 as discussed in the [multisig](/contracts/5.x/multisig#beyond-standard-signature-verification) section. For ERC-7579 modules, this is implemented through the [`ERC7579Multisig`](/community-contracts/api/account#ERC7579Multisig) validator.
+
+Combined with an [`ERC7579Executor`](/community-contracts/api/account#ERC7579Executor), it provides a basic foundation that can be extended with more sophisticated features:
+
+./examples/account/modules/MyERC7579SocialRecovery.sol
+
+For enhanced security, you can extend this foundation with scheduling, delays, and cancellations using [`ERC7579DelayedExecutor`](/community-contracts/api/account#ERC7579DelayedExecutor). This allows guardians to schedule recovery operations with a time delay, providing a security window to detect and cancel suspicious recovery attempts before they execute:
+
+./examples/account/modules/MyERC7579DelayedSocialRecovery.sol
+
+
+The delayed executor’s signature validation doesn’t require a nonce since operations are uniquely identified by their [operation id](/community-contracts/api/account#ERC7579DelayedExecutor-hashOperation-address-bytes32-bytes32-bytes-) and cannot be scheduled twice.
+
+
+These implementations demonstrate how to build progressively more secure social recovery mechanisms, from basic multi-signature recovery to time-delayed recovery with cancellation capabilities.
+
+For additional functionality, developers can use:
+
+* [`ERC7579MultisigWeighted`](/community-contracts/api/account#ERC7579MultisigWeighted) to assign different weights to signers
+* [`ERC7579MultisigConfirmation`](/community-contracts/api/account#ERC7579MultisigConfirmation) to implement a confirmation system that verifies signatures when adding signers
+* [`ERC7579MultisigStorage`](/community-contracts/api/account#ERC7579MultisigStorage) to allow guardians to presign recovery operations for more flexible coordination
diff --git a/docs/content/community-contracts/api/access.mdx b/docs/content/community-contracts/api/access.mdx
new file mode 100644
index 00000000..1ab5cae1
--- /dev/null
+++ b/docs/content/community-contracts/api/access.mdx
@@ -0,0 +1,463 @@
+---
+title: "Access"
+description: "Smart contract access utilities and implementations"
+---
+
+This directory contains utility contracts to restrict access control in smart contracts. These include:
+
+* [`AccessManagerLight`](#AccessManagerLight): A simpler version of an AccessManager that uses `bytes8` roles to allow function calls identified by their 4-bytes selector.
+
+## AccessManager
+
+[`AccessManagerLight`](#AccessManagerLight)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/access/manager/AccessManagerLight.sol";
+```
+
+Light version of an AccessManager contract that defines `bytes8` roles
+that are stored as requirements (see [`AccessManagerLight.getRequirements`](#AccessManagerLight-getRequirements-address-bytes4-)) for each function.
+
+Each requirement is a bitmask of roles that are allowed to call a function
+identified by its `bytes4` selector. Users have their permissioned stored
+as a bitmask of roles they belong to.
+
+The admin role is a special role that has access to all functions and can
+manage the roles of other users.
+
+
+
+Throws if the specified requirement is not met by the caller's permissions (see [`AccessManagerLight.getGroups`](#AccessManagerLight-getGroups-address-)).
+
+
+
+Internal version of [`AccessManagerLight._setRequirements`](#AccessManagerLight-_setRequirements-address-bytes4-Masks-Mask-) without access control.
+
+
diff --git a/docs/content/community-contracts/api/account.mdx b/docs/content/community-contracts/api/account.mdx
new file mode 100644
index 00000000..adab75d5
--- /dev/null
+++ b/docs/content/community-contracts/api/account.mdx
@@ -0,0 +1,4041 @@
+---
+title: "Account"
+description: "Smart contract account utilities and implementations"
+---
+
+This directory includes contracts to build accounts for ERC-4337. These include:
+
+* [`ERC7579Executor`](#ERC7579Executor): An executor module that enables executing calls from accounts where the it’s installed.
+* [`ERC7579DelayedExecutor`](#ERC7579DelayedExecutor): An executor module that adds a delay before executing an account operation.
+* [`ERC7579SelectorExecutor`](#ERC7579SelectorExecutor): An executor module that restricts execution to specific function selectors.
+* [`ERC7579Validator`](#ERC7579Validator): Abstract validator module for ERC-7579 accounts that provides base implementation for signature validation.
+* [`ERC7579Signature`](#ERC7579Signature): Implementation of [`ERC7579Validator`](#ERC7579Validator) using ERC-7913 signature verification for address-less cryptographic keys and account signatures.
+* [`ERC7579Multisig`](#ERC7579Multisig): An extension of [`ERC7579Validator`](#ERC7579Validator) that enables validation using ERC-7913 signer keys.
+* [`ERC7579MultisigWeighted`](#ERC7579MultisigWeighted): An extension of [`ERC7579Multisig`](#ERC7579Multisig) that allows different weights to be assigned to signers.
+* [`ERC7579MultisigConfirmation`](#ERC7579MultisigConfirmation): An extension of [`ERC7579Multisig`](#ERC7579Multisig) that requires each signer to provide a confirmation signature.
+* [`ERC7579MultisigStorage`](#ERC7579MultisigStorage): An extension of [`ERC7579Multisig`](#ERC7579Multisig) that allows storing presigned approvals in storage.
+* [`PaymasterCore`](#PaymasterCore): An ERC-4337 paymaster implementation that includes the core logic to validate and pay for user operations.
+* [`PaymasterERC20`](#PaymasterERC20): A paymaster that allows users to pay for user operations using ERC-20 tokens.
+* [`PaymasterERC20Guarantor`](#PaymasterERC20Guarantor): A paymaster that enables third parties to guarantee user operations by pre-funding gas costs, with the option for users to repay or for guarantors to absorb the cost.
+* [`PaymasterERC721Owner`](#PaymasterERC721Owner): A paymaster that allows users to pay for user operations based on ERC-721 ownership.
+* [`PaymasterSigner`](#PaymasterSigner): A paymaster that allows users to pay for user operations using an authorized signature.
+
+## Modules
+
+### Executors
+
+[`ERC7579Executor`](#ERC7579Executor)
+
+[`ERC7579DelayedExecutor`](#ERC7579DelayedExecutor)
+
+[`ERC7579SelectorExecutor`](#ERC7579SelectorExecutor)
+
+### Validators
+
+[`ERC7579Validator`](#ERC7579Validator)
+
+[`ERC7579Signature`](#ERC7579Signature)
+
+[`ERC7579Multisig`](#ERC7579Multisig)
+
+[`ERC7579MultisigWeighted`](#ERC7579MultisigWeighted)
+
+[`ERC7579MultisigConfirmation`](#ERC7579MultisigConfirmation)
+
+[`ERC7579MultisigStorage`](#ERC7579MultisigStorage)
+
+## Paymaster
+
+[`PaymasterCore`](#PaymasterCore)
+
+[`PaymasterERC20`](#PaymasterERC20)
+
+[`PaymasterERC20Guarantor`](#PaymasterERC20Guarantor)
+
+[`PaymasterERC721Owner`](#PaymasterERC721Owner)
+
+[`PaymasterSigner`](#PaymasterSigner)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579DelayedExecutor.sol";
+```
+
+Extension of [`ERC7579Executor`](#ERC7579Executor) that allows scheduling and executing delayed operations
+with expiration. This module enables time-delayed execution patterns for smart accounts.
+
+==== Operation Lifecycle
+
+1. Scheduling: Operations are scheduled via [`ERC7579DelayedExecutor.schedule`](#ERC7579DelayedExecutor-schedule-address-bytes32-bytes32-bytes-) with a specified delay period.
+The delay period is set during [`ERC7579DelayedExecutor.onInstall`](#ERC7579DelayedExecutor-onInstall-bytes-) and can be customized via [`ERC7579DelayedExecutor.setDelay`](#ERC7579DelayedExecutor-setDelay-uint32-). Each
+operation enters a `Scheduled` state and must wait for its delay period to elapse.
+
+2. Security Window: During the delay period, operations remain in `Scheduled` state but
+cannot be executed. Through this period, suspicious operations can be monitored and
+canceled via [`ERC7579DelayedExecutor.cancel`](#ERC7579DelayedExecutor-cancel-address-bytes32-bytes32-bytes-) if appropriate.
+
+3. Execution & Expiration: Once the delay period elapses, operations transition to `Ready` state.
+Operations can be executed via [`ERC7579Executor.execute`](#ERC7579Executor-execute-address-bytes32-bytes32-bytes-) and have an expiration period after becoming
+executable. If an operation is not executed within the expiration period, it becomes `Expired`
+and can't be executed. Expired operations must be rescheduled with a different salt.
+
+==== Delay Management
+
+Accounts can set their own delay periods during installation or via [`ERC7579DelayedExecutor.setDelay`](#ERC7579DelayedExecutor-setDelay-uint32-).
+The delay period is enforced even between installas and uninstalls to prevent
+immediate downgrades. When setting a new delay period, the new delay takes effect
+after a transition period defined by the current delay or [`ERC7579DelayedExecutor.minSetback`](#ERC7579DelayedExecutor-minSetback--), whichever
+is longer.
+
+==== Authorization
+
+Authorization for scheduling and canceling operations is controlled through the [`ERC7579DelayedExecutor._validateSchedule`](#ERC7579DelayedExecutor-_validateSchedule-address-bytes32-bytes32-bytes-)
+and [`ERC7579DelayedExecutor._validateCancel`](#ERC7579DelayedExecutor-_validateCancel-address-bytes32-bytes32-bytes-) functions. These functions can be overridden to implement custom
+authorization logic, such as requiring specific signers or roles.
+
+
+Use [`ERC7579DelayedExecutor._scheduleAt`](#ERC7579DelayedExecutor-_scheduleAt-address-bytes32-bytes32-bytes-uint48-uint32-) to schedule operations at a specific points in time. This is
+useful to pre-schedule operations for non-deployed accounts (e.g. subscriptions).
+
+
+
+
+Minimum delay after which [`ERC7579DelayedExecutor.setDelay`](#ERC7579DelayedExecutor-setDelay-uint32-) takes effect.
+Set as default delay if not provided during [`ERC7579DelayedExecutor.onInstall`](#ERC7579DelayedExecutor-onInstall-bytes-).
+
+
+
+Default expiration for account operations. Set if not provided during [`ERC7579DelayedExecutor.onInstall`](#ERC7579DelayedExecutor-onInstall-bytes-).
+
+
+
+Sets up the module's initial configuration when installed by an account.
+The account calling this function becomes registered with the module.
+
+The `initData` may be `abi.encode(uint32(initialDelay), uint32(initialExpiration))`.
+The delay will be set to the maximum of this value and the minimum delay if provided.
+Otherwise, the delay will be set to [`ERC7579DelayedExecutor.minSetback`](#ERC7579DelayedExecutor-minSetback--) and [`ERC7579DelayedExecutor.defaultExpiration`](#ERC7579DelayedExecutor-defaultExpiration--) respectively.
+
+Behaves as a no-op if the module is already installed.
+
+Requirements:
+
+* The account (i.e `msg.sender`) must implement the `IERC7579ModuleConfig` interface.
+* `initData` must be empty or decode correctly to `(uint32, uint32)`.
+
+
+
+Allows an account to update its execution delay (see [`ERC7579DelayedExecutor.getDelay`](#ERC7579DelayedExecutor-getDelay-address-)).
+
+The new delay will take effect after a transition period defined by the current delay
+or [`ERC7579DelayedExecutor.minSetback`](#ERC7579DelayedExecutor-minSetback--), whichever is longer. This prevents immediate security downgrades.
+Can only be called by the account itself.
+
+
+
+Allows an account to update its execution expiration (see [`ERC7579DelayedExecutor.getExpiration`](#ERC7579DelayedExecutor-getExpiration-address-)).
+
+
+
+Schedules an operation to be executed after the account's delay period (see [`ERC7579DelayedExecutor.getDelay`](#ERC7579DelayedExecutor-getDelay-address-)).
+Operations are uniquely identified by the combination of `salt`, `mode`, and `data`.
+See [`ERC7579DelayedExecutor._validateSchedule`](#ERC7579DelayedExecutor-_validateSchedule-address-bytes32-bytes32-bytes-) for authorization checks.
+
+
+
+Cancels a previously scheduled operation. Can only be called by the account that
+scheduled the operation. See [`ERC7579DelayedExecutor._cancel`](#ERC7579DelayedExecutor-_cancel-address-bytes32-bytes-bytes32-).
+
+
+
+Cleans up the [`ERC7579DelayedExecutor.getDelay`](#ERC7579DelayedExecutor-getDelay-address-) and [`ERC7579DelayedExecutor.getExpiration`](#ERC7579DelayedExecutor-getExpiration-address-) values by scheduling them to `0`
+and respecting the previous delay and expiration values.
+
+
+This function does not clean up scheduled operations. This means operations
+could potentially be re-executed if the module is reinstalled later. This is a deliberate
+design choice for efficiency, but module implementations may want to override this behavior
+to clear scheduled operations during uninstallation for their specific use cases.
+
+
+
+Calling this function directly will remove the expiration ([`ERC7579DelayedExecutor.getExpiration`](#ERC7579DelayedExecutor-getExpiration-address-)) value and
+will schedule a reset of the delay ([`ERC7579DelayedExecutor.getDelay`](#ERC7579DelayedExecutor-getDelay-address-)) to `0` for the account. Reinstalling the
+module will not immediately reset the delay if the delay reset hasn't taken effect yet.
+
+
+
+
+Returns `data` as the execution calldata. See [`ERC7579Executor._execute`](#ERC7579Executor-_execute-address-bytes32-bytes32-bytes-).
+
+
+This function relies on the operation state validation in [`ERC7579DelayedExecutor._execute`](#ERC7579DelayedExecutor-_execute-address-bytes32-bytes32-bytes-) for
+authorization. Extensions of this module should override this function to implement
+additional validation logic if needed.
+
+
+
+
+Internal implementation for setting an account's delay. See [`ERC7579DelayedExecutor.getDelay`](#ERC7579DelayedExecutor-getDelay-address-).
+
+Emits an [`ERC7579DelayedExecutor.ERC7579ExecutorDelayUpdated`](#ERC7579DelayedExecutor-ERC7579ExecutorDelayUpdated-address-uint32-uint48-) event.
+
+
+
+Internal implementation for setting an account's expiration. See [`ERC7579DelayedExecutor.getExpiration`](#ERC7579DelayedExecutor-getExpiration-address-).
+
+Emits an [`ERC7579DelayedExecutor.ERC7579ExecutorExpirationUpdated`](#ERC7579DelayedExecutor-ERC7579ExecutorExpirationUpdated-address-uint32-) event.
+
+
+
+Internal version of [`ERC7579DelayedExecutor.schedule`](#ERC7579DelayedExecutor-schedule-address-bytes32-bytes32-bytes-) that takes an `account` address to schedule
+an operation that starts its security window at `at` and expires after `delay`.
+
+Requirements:
+
+* The operation must be `Unknown`.
+
+Emits an [`ERC7579DelayedExecutor.ERC7579ExecutorOperationScheduled`](#ERC7579DelayedExecutor-ERC7579ExecutorOperationScheduled-address-bytes32-bytes32-bytes32-bytes-uint48-) event.
+
+
+
+See [`ERC7579Executor._execute`](#ERC7579Executor-_execute-address-bytes32-bytes32-bytes-).
+
+Requirements:
+
+* The operation must be `Ready`.
+
+
+
+Internal version of [`ERC7579DelayedExecutor.cancel`](#ERC7579DelayedExecutor-cancel-address-bytes32-bytes32-bytes-) that takes an `account` address as an argument.
+
+Requirements:
+
+* The operation must be `Scheduled` or `Ready`.
+
+Canceled operations can't be rescheduled. Emits an [`ERC7579DelayedExecutor.ERC7579ExecutorOperationCanceled`](#ERC7579DelayedExecutor-ERC7579ExecutorOperationCanceled-address-bytes32-) event.
+
+
+
+Check that the current state of a operation matches the requirements described by the `allowedStates` bitmap.
+This bitmap should be built using [`ERC7579DelayedExecutor._encodeStateBitmap`](#ERC7579DelayedExecutor-_encodeStateBitmap-enum-ERC7579DelayedExecutor-OperationState-).
+
+If requirements are not met, reverts with a [`ERC7579DelayedExecutor.ERC7579ExecutorUnexpectedOperationState`](#ERC7579DelayedExecutor-ERC7579ExecutorUnexpectedOperationState-bytes32-enum-ERC7579DelayedExecutor-OperationState-bytes32-) error.
+
+
+
+Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to
+the underlying position in the `OperationState` enum. For example:
+
+```
+0x000...10000
+ ^^^^^^------ ...
+ ^----- Canceled
+ ^---- Executed
+ ^--- Ready
+ ^-- Scheduled
+ ^- Unknown
+```
+
+
+
+The current state of a operation is not the expected. The `expectedStates` is a bitmap with the
+bits enabled for each OperationState enum position counting from right to left. See [`ERC7579DelayedExecutor._encodeStateBitmap`](#ERC7579DelayedExecutor-_encodeStateBitmap-enum-ERC7579DelayedExecutor-OperationState-).
+
+
+If `expectedState` is `bytes32(0)`, the operation is expected to not be in any state (i.e. not exist).
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579Executor.sol";
+```
+
+Basic implementation for ERC-7579 executor modules that provides execution functionality
+for smart accounts.
+
+The module enables accounts to execute arbitrary operations, leveraging the execution
+capabilities defined in the ERC-7579 standard. Developers can customize whether an operation
+can be executed with custom rules by implementing the [`ERC7579DelayedExecutor._validateExecution`](#ERC7579DelayedExecutor-_validateExecution-address-bytes32-bytes32-bytes-) function in
+derived contracts.
+
+
+This is a simplified executor that directly executes operations without delay or expiration
+mechanisms. For a more advanced implementation with time-delayed execution patterns and
+security features, see [`ERC7579DelayedExecutor`](#ERC7579DelayedExecutor).
+
+
+
+
+Executes an operation and returns the result data from the executed operation.
+Restricted to the account itself by default. See [`ERC7579DelayedExecutor._execute`](#ERC7579DelayedExecutor-_execute-address-bytes32-bytes32-bytes-) for requirements and
+[`ERC7579DelayedExecutor._validateExecution`](#ERC7579DelayedExecutor-_validateExecution-address-bytes32-bytes32-bytes-) for authorization checks.
+
+
+
+Validates whether the execution can proceed. This function is called before executing
+the operation and returns the execution calldata to be used.
+
+Example extension:
+
+```solidity
+ function _validateExecution(address account, bytes32 salt, bytes32 mode, bytes calldata data)
+ internal
+ override
+ returns (bytes calldata)
+ {
+ // custom logic
+ return data;
+ }
+```
+
+
+Pack extra data in the `data` arguments (e.g. a signature) to be used in the
+validation process. Calldata can be sliced to extract it and return only the
+execution calldata.
+
+
+
+
+Internal version of [`ERC7579Executor.execute`](#ERC7579Executor-execute-address-bytes32-bytes32-bytes-). Emits [`ERC7579Executor.ERC7579ExecutorOperationExecuted`](#ERC7579Executor-ERC7579ExecutorOperationExecuted-address-bytes32-bytes32-bytes-) event.
+
+Requirements:
+
+* The `account` must implement the `IERC7579Execution-executeFromExecutor` function.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579Multisig.sol";
+```
+
+Implementation of an [`ERC7579Validator`](#ERC7579Validator) that uses ERC-7913 signers for multisignature
+validation.
+
+This module provides a base implementation for multisignature validation that can be
+attached to any function through the [`ERC7579Multisig._rawERC7579Validation`](#ERC7579Multisig-_rawERC7579Validation-address-bytes32-bytes-) internal function. The signers
+are represented using the ERC-7913 format, which concatenates a verifier address and
+a key: `verifier || key`.
+
+A smart account with this module installed can require multiple signers to approve
+operations before they are executed, such as requiring 3-of-5 guardians to approve
+a social recovery operation.
+
+
+
+Sets up the module's initial configuration when installed by an account.
+See [`ERC7579DelayedExecutor.onInstall`](#ERC7579DelayedExecutor-onInstall-bytes-). Besides the delay setup, the `initdata` can
+include `signers` and `threshold`.
+
+The initData should be encoded as:
+`abi.encode(bytes[] signers, uint64 threshold)`
+
+If no signers or threshold are provided, the multisignature functionality will be
+disabled until they are added later.
+
+
+An account can only call onInstall once. If called directly by the account,
+the signer will be set to the provided data. Future installations will behave as a no-op.
+
+
+
+
+Cleans up module's configuration when uninstalled from an account.
+Clears all signers and resets the threshold.
+
+See [`ERC7579DelayedExecutor.onUninstall`](#ERC7579DelayedExecutor-onUninstall-bytes-).
+
+
+This function has unbounded gas costs and may become uncallable if the set grows too large.
+See `EnumerableSet-clear`.
+
+
+
+
+Returns a slice of the set of authorized signers for the specified account.
+
+Using `start = 0` and `end = type(uint64).max` will return the entire set of signers.
+
+
+Depending on the `start` and `end`, this operation can copy a large amount of data to memory, which
+can be expensive. This is designed for view accessors queried without gas fees. Using it in state-changing
+functions may become uncallable if the slice grows too large.
+
+
+
+
+Adds new signers to the authorized set for the calling account.
+Can only be called by the account itself.
+
+Requirements:
+
+* Each of `newSigners` must be at least 20 bytes long.
+* Each of `newSigners` must not be already authorized.
+
+
+
+Removes signers from the authorized set for the calling account.
+Can only be called by the account itself.
+
+Requirements:
+
+* Each of `oldSigners` must be authorized.
+* After removal, the threshold must still be reachable.
+
+
+
+Sets the threshold for the calling account.
+Can only be called by the account itself.
+
+Requirements:
+
+* The threshold must be reachable with the current number of signers.
+
+
+
+Returns whether the number of valid signatures meets or exceeds the
+threshold set for the target account.
+
+The signature should be encoded as:
+`abi.encode(bytes[] signingSigners, bytes[] signatures)`
+
+Where `signingSigners` are the authorized signers and signatures are their corresponding
+signatures of the operation `hash`.
+
+
+
+Adds the `newSigners` to those allowed to sign on behalf of the account.
+
+Requirements:
+
+* Each of `newSigners` must be at least 20 bytes long. Reverts with [`ERC7579Multisig.ERC7579MultisigInvalidSigner`](#ERC7579Multisig-ERC7579MultisigInvalidSigner-bytes-) if not.
+* Each of `newSigners` must not be authorized. Reverts with [`ERC7579Multisig.ERC7579MultisigAlreadyExists`](#ERC7579Multisig-ERC7579MultisigAlreadyExists-bytes-) if it already exists.
+
+
+
+Removes the `oldSigners` from the authorized signers for the account.
+
+Requirements:
+
+* Each of `oldSigners` must be authorized. Reverts with [`ERC7579Multisig.ERC7579MultisigNonexistentSigner`](#ERC7579Multisig-ERC7579MultisigNonexistentSigner-bytes-) if not.
+* The threshold must remain reachable after removal. See [`ERC7579Multisig._validateReachableThreshold`](#ERC7579Multisig-_validateReachableThreshold-address-) for details.
+
+
+
+Sets the signatures `threshold` required to approve a multisignature operation.
+
+Requirements:
+
+* The threshold must be greater than 0. Reverts with [`ERC7579Multisig.ERC7579MultisigZeroThreshold`](#ERC7579Multisig-ERC7579MultisigZeroThreshold--) if not.
+* The threshold must be reachable with the current number of signers. See [`ERC7579Multisig._validateReachableThreshold`](#ERC7579Multisig-_validateReachableThreshold-address-) for details.
+
+
+
+Validates the current threshold is reachable with the number of [`ERC7579Multisig._signersSetByAccount`](#ERC7579Multisig-_signersSetByAccount-mapping-address----struct-EnumerableSet-BytesSet-).
+
+Requirements:
+
+* The number of signers must be >= the threshold. Reverts with [`ERC7579Multisig.ERC7579MultisigUnreachableThreshold`](#ERC7579Multisig-ERC7579MultisigUnreachableThreshold-uint64-uint64-) if not.
+
+
+
+Validates the signatures using the signers and their corresponding signatures.
+Returns whether the signers are authorized and the signatures are valid for the given hash.
+
+The signers must be ordered by their `keccak256` hash to prevent duplications and to optimize
+the verification process. The function will return `false` if any signer is not authorized or
+if the signatures are invalid for the given hash.
+
+Requirements:
+
+* The `signatures` array must be at least the `signers` array's length.
+
+
+
+Validates that the number of signers meets the [`ERC7579Multisig.threshold`](#ERC7579Multisig-threshold-address-) requirement.
+Assumes the signers were already validated. See [`ERC7579Multisig._validateSignatures`](#ERC7579Multisig-_validateSignatures-address-bytes32-bytes---bytes---) for more details.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigConfirmation.sol";
+```
+
+Extension of [`ERC7579Multisig`](#ERC7579Multisig) that requires explicit confirmation signatures
+from new signers when they are being added to the multisig.
+
+This module ensures that only willing participants can be added as signers to a
+multisig by requiring each new signer to provide a valid signature confirming their
+consent to be added. Each signer must sign an EIP-712 message to confirm their addition.
+
+
+Use this module to ensure that all guardians in a social recovery or multisig setup have
+explicitly agreed to their roles.
+
+
+
+
+Extends [`ERC7579Multisig._addSigners`](#ERC7579Multisig-_addSigners-address-bytes---) _addSigners to require confirmation signatures
+Each entry in newSigners must be ABI-encoded as:
+
+```solidity
+abi.encode(deadline,signer,signature); // uint256, bytes, bytes
+```
+
+* signer: The ERC-7913 signer to add
+* signature: The signature from this signer confirming their addition
+
+The function verifies each signature before adding the signer. If any signature is invalid,
+the function reverts with [`ERC7579MultisigConfirmation.ERC7579MultisigInvalidConfirmationSignature`](#ERC7579MultisigConfirmation-ERC7579MultisigInvalidConfirmationSignature-bytes-).
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigStorage.sol";
+```
+
+Extension of [`ERC7579Multisig`](#ERC7579Multisig) that allows storing presigned approvals in storage.
+
+This module extends the multisignature module to allow signers to presign operations,
+which are then stored in a mapping and can be used during validation. This enables
+more flexible multisignature workflows where signatures can be collected over time
+without requiring all signers to be online simultaneously.
+
+When validating signatures, if a signature is empty, it indicates a presignature
+and the validation will check the storage mapping instead of cryptographic verification.
+
+
+
+Allows a signer to presign a hash by providing a valid signature.
+The signature will be verified and if valid, the presignature will be stored.
+
+Emits [`ERC7579MultisigStorage.ERC7579MultisigStoragePresigned`](#ERC7579MultisigStorage-ERC7579MultisigStoragePresigned-address-bytes32-bytes-) if the signature is valid and the hash is not already
+signed, otherwise acts as a no-op.
+
+
+Does not check if the signer is authorized for the account. Valid signatures from
+invalid signers won't be executable. See [`ERC7579Multisig._validateSignatures`](#ERC7579Multisig-_validateSignatures-address-bytes32-bytes---bytes---) for more details.
+
+
+
+
+See [`ERC7579Multisig._validateSignatures`](#ERC7579Multisig-_validateSignatures-address-bytes32-bytes---bytes---).
+
+If a signature is empty, it indicates a presignature and the validation will check the storage mapping
+instead of cryptographic verification. See [`ERC7579Multisig._signersSetByAccount`](#ERC7579Multisig-_signersSetByAccount-mapping-address----struct-EnumerableSet-BytesSet-) for more details.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579MultisigWeighted.sol";
+```
+
+Extension of [`ERC7579Multisig`](#ERC7579Multisig) that supports weighted signatures.
+
+This module extends the multisignature module to allow assigning different weights
+to each signer, enabling more flexible governance schemes. For example, some guardians
+could have higher weight than others, allowing for weighted voting or prioritized authorization.
+
+Example use case:
+
+A smart account with this module installed can schedule social recovery operations
+after obtaining approval from guardians with sufficient total weight (e.g., requiring
+a total weight of 10, with 3 guardians weighted as 5, 3, and 2), and then execute them
+after the time delay has passed.
+
+
+When setting a threshold value, ensure it matches the scale used for signer weights.
+For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require
+signatures with a total weight of at least 4 (e.g., one with weight 1 and one with weight 3).
+
+
+
+
+Sets up the module's initial configuration when installed by an account.
+Besides the standard delay and signer configuration, this can also include
+signer weights.
+
+The initData should be encoded as:
+`abi.encode(bytes[] signers, uint64 threshold, uint64[] weights)`
+
+If weights are not provided but signers are, all signers default to weight 1.
+
+
+An account can only call onInstall once. If called directly by the account,
+the signer will be set to the provided data. Future installations will behave as a no-op.
+
+
+
+
+Cleans up module's configuration when uninstalled from an account.
+Clears all signers, weights, and total weights.
+
+See [`ERC7579Multisig.onUninstall`](#ERC7579Multisig-onUninstall-bytes-).
+
+
+
+Sets weights for multiple signers at once. Internal version without access control.
+
+Requirements:
+
+* `signers` and `weights` arrays must have the same length. Reverts with [`ERC7579MultisigWeighted.ERC7579MultisigMismatchedLength`](#ERC7579MultisigWeighted-ERC7579MultisigMismatchedLength--) on mismatch.
+* Each signer must exist in the set of authorized signers. Reverts with [`ERC7579Multisig.ERC7579MultisigNonexistentSigner`](#ERC7579Multisig-ERC7579MultisigNonexistentSigner-bytes-) if not.
+* Each weight must be greater than 0. Reverts with [`ERC7579MultisigWeighted.ERC7579MultisigInvalidWeight`](#ERC7579MultisigWeighted-ERC7579MultisigInvalidWeight-bytes-uint64-) if not.
+* See [`ERC7579Multisig._validateReachableThreshold`](#ERC7579Multisig-_validateReachableThreshold-address-) for the threshold validation.
+
+Emits [`ERC7579MultisigWeighted.ERC7579MultisigWeightChanged`](#ERC7579MultisigWeighted-ERC7579MultisigWeightChanged-address-bytes-uint64-) for each signer.
+
+
+
+Override to add weight tracking. See [`ERC7579Multisig._addSigners`](#ERC7579Multisig-_addSigners-address-bytes---).
+Each new signer has a default weight of 1.
+
+In cases where [`ERC7579MultisigWeighted.totalWeight`](#ERC7579MultisigWeighted-totalWeight-address-) is almost `type(uint64).max` (due to a large `_totalExtraWeight`), adding new
+signers could cause the [`ERC7579MultisigWeighted.totalWeight`](#ERC7579MultisigWeighted-totalWeight-address-) computation to overflow. Adding a [`ERC7579MultisigWeighted.totalWeight`](#ERC7579MultisigWeighted-totalWeight-address-) call after the new
+signers are added ensures no such overflow happens.
+
+
+
+Override to handle weight tracking during removal. See [`ERC7579Multisig._removeSigners`](#ERC7579Multisig-_removeSigners-address-bytes---).
+
+Just like [`ERC7579Multisig._addSigners`](#ERC7579Multisig-_addSigners-address-bytes---), this function does not emit [`ERC7579MultisigWeighted.ERC7579MultisigWeightChanged`](#ERC7579MultisigWeighted-ERC7579MultisigWeightChanged-address-bytes-uint64-) events. The
+[`ERC7579Multisig.ERC7913SignerRemoved`](#ERC7579Multisig-ERC7913SignerRemoved-address-bytes-) event emitted by [`ERC7579Multisig._removeSigners`](#ERC7579Multisig-_removeSigners-address-bytes---) is enough to track weights here.
+
+
+
+Override to validate threshold against total weight instead of signer count.
+
+
+This function intentionally does not call `super._validateReachableThreshold` because the base implementation
+assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple
+implementations of this function may exist in the contract, so important side effects may be missed
+depending on the linearization order.
+
+
+
+
+Validates that the total weight of signers meets the [`ERC7579Multisig.threshold`](#ERC7579Multisig-threshold-address-) requirement.
+Overrides the base implementation to use weights instead of count.
+
+
+This function intentionally does not call `super._validateThreshold` because the base implementation
+assumes each signer has a weight of 1, which is incompatible with this weighted implementation.
+
+
+
+
+Emitted when a signer's weight is changed.
+
+
+Not emitted in [`ERC7579Multisig._addSigners`](#ERC7579Multisig-_addSigners-address-bytes---) or [`ERC7579Multisig._removeSigners`](#ERC7579Multisig-_removeSigners-address-bytes---). Indexers must rely on [`ERC7579Multisig.ERC7913SignerAdded`](#ERC7579Multisig-ERC7913SignerAdded-address-bytes-)
+and [`ERC7579Multisig.ERC7913SignerRemoved`](#ERC7579Multisig-ERC7913SignerRemoved-address-bytes-) to index a default weight of 1. See [`ERC7579MultisigWeighted.signerWeight`](#ERC7579MultisigWeighted-signerWeight-address-bytes-).
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579SelectorExecutor.sol";
+```
+
+Implementation of an [`ERC7579Executor`](#ERC7579Executor) that allows authorizing specific function selectors
+that can be executed on the account.
+
+This module provides a way to restrict which functions can be executed on the account by
+maintaining a set of allowed function selectors. Only calls to functions with selectors
+in the set will be allowed to execute.
+
+
+
+Returns the set of authorized selectors for the specified account.
+
+
+This operation copies the entire selectors set to memory, which
+can be expensive or may result in unbounded computation.
+
+
+
+
+Cleans up module's configuration when uninstalled from an account.
+Clears all selectors.
+
+
+This function has unbounded gas costs and may become uncallable if the set grows too large.
+See [`EnumerableSetExtended.clear`](./utils#EnumerableSetExtended-clear-struct-EnumerableSetExtended-Bytes32x2Set-).
+
+
+
+
+Internal version of [`ERC7579SelectorExecutor.addSelectors`](#ERC7579SelectorExecutor-addSelectors-bytes4---) that takes an `account` as argument
+
+
+
+Internal version of [`ERC7579SelectorExecutor.removeSelectors`](#ERC7579SelectorExecutor-removeSelectors-bytes4---) that takes an `account` as argument
+
+
+
+See [`ERC7579Executor._validateExecution`](#ERC7579Executor-_validateExecution-address-bytes32-bytes32-bytes-).
+Validates that the selector (first 4 bytes of the actual callData) is authorized before execution.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/modules/ERC7579Signature.sol";
+```
+
+Implementation of [`ERC7579Validator`](#ERC7579Validator) module using ERC-7913 signature verification.
+
+This validator allows ERC-7579 accounts to integrate with address-less cryptographic keys
+and account signatures through the ERC-7913 signature verification system. Each account
+can store its own ERC-7913 formatted signer (a concatenation of a verifier address and a
+key: `verifier || key`).
+
+This enables accounts to use signature schemes without requiring each key to have its own
+Ethereum address.A smart account with this module installed can keep an emergency key as a
+backup.
+
+
+
+See `IERC7579Module-onInstall`.
+
+
+An account can only call onInstall once. If called directly by the account,
+the signer will be set to the provided data. Future installations will behave as a no-op.
+
+
+
+
+See `IERC7579Module-onUninstall`.
+
+
+The signer's key will be removed if the account calls this function, potentially
+making the account unusable. As an account operator, make sure to uninstall to a predefined path
+in your account that properly handles side effects of uninstallation. See `AccountERC7579-uninstallModule`.
+
+
+
+
+Internal version of [`ERC7579Signature.setSigner`](#ERC7579Signature-setSigner-bytes-) that takes an `account` as argument without validating `signer_`.
+
+
+
+See [`ERC7579Validator._rawERC7579Validation`](#ERC7579Validator-_rawERC7579Validation-address-bytes32-bytes-).
+
+Validates a `signature` using ERC-7913 verification.
+
+This base implementation ignores the `sender` parameter and validates using
+the account's stored signer. Derived contracts can override this to implement
+custom validation logic based on the sender.
+
+
+
+See `IERC7579Validator-isValidSignatureWithSender`.
+
+Ignores the `sender` parameter and validates using [`ERC7579Multisig._rawERC7579Validation`](#ERC7579Multisig-_rawERC7579Validation-address-bytes32-bytes-).
+Consider overriding this function to implement custom validation logic
+based on the original sender.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/paymaster/PaymasterCore.sol";
+```
+
+A simple ERC4337 paymaster implementation. This base implementation only includes the minimal logic to validate
+and pay for user operations.
+
+Developers must implement the [`PaymasterCore._validatePaymasterUserOp`](#PaymasterCore-_validatePaymasterUserOp-struct-PackedUserOperation-bytes32-uint256-) function to define the paymaster's validation
+and payment logic. The `context` parameter is used to pass data between the validation and execution phases.
+
+The paymaster includes support to call the `IEntryPointStake` interface to manage the paymaster's deposits and stakes
+through the internal functions [`PaymasterCore.deposit`](#PaymasterCore-deposit--), [`PaymasterCore.withdraw`](#PaymasterCore-withdraw-address-payable-uint256-), [`PaymasterCore.addStake`](#PaymasterCore-addStake-uint32-), [`PaymasterCore.unlockStake`](#PaymasterCore-unlockStake--) and [`PaymasterCore.withdrawStake`](#PaymasterCore-withdrawStake-address-payable-).
+
+* Deposits are used to pay for user operations.
+* Stakes are used to guarantee the paymaster's reputation and obtain more flexibility in accessing storage.
+
+
+See [Paymaster's unstaked reputation rules](https://eips.ethereum.org/EIPS/eip-7562#unstaked-paymasters-reputation-rules)
+ for more details on the paymaster's storage access limitations.
+
+
+
+
+Validates whether the paymaster is willing to pay for the user operation. See
+`IAccount-validateUserOp` for additional information on the return value.
+
+
+Bundlers will reject this method if it modifies the state, unless it's whitelisted.
+
+
+
+
+Internal validation of whether the paymaster is willing to pay for the user operation.
+Returns the context to be passed to postOp and the validation data.
+
+The `requiredPreFund` is the amount the paymaster has to pay (in native tokens). It's calculated
+as `requiredGas * userOp.maxFeePerGas`, where `required` gas can be calculated from the user operation
+as `verificationGasLimit + callGasLimit + paymasterVerificationGasLimit + paymasterPostOpGasLimit + preVerificationGas`
+
+
+
+Handles post user operation execution logic. The caller must be the entry point.
+
+It receives the `context` returned by `_validatePaymasterUserOp`. Function is not called if no context
+is returned by [`PaymasterCore.validatePaymasterUserOp`](#PaymasterCore-validatePaymasterUserOp-struct-PackedUserOperation-bytes32-uint256-).
+
+
+The `actualUserOpFeePerGas` is not `tx.gasprice`. A user operation can be bundled with other transactions
+making the gas price of the user operation to differ.
+
+
+
+
+Checks whether `msg.sender` withdraw funds stake or deposit from the entrypoint on paymaster's behalf.
+
+Use of an [access control](https://docs.openzeppelin.com/contracts/5.x/access-control)
+modifier such as `Ownable-onlyOwner` is recommended.
+
+```solidity
+function _authorizeUpgrade() internal onlyOwner {}
+```
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC20.sol";
+```
+
+Extension of [`PaymasterCore`](#PaymasterCore) that enables users to pay gas with ERC-20 tokens.
+
+To enable this feature, developers must implement the [`PaymasterERC20._fetchDetails`](#PaymasterERC20-_fetchDetails-struct-PackedUserOperation-bytes32-) function:
+
+```solidity
+function _fetchDetails(
+ PackedUserOperation calldata userOp,
+ bytes32 userOpHash
+) internal view override returns (uint256 validationData, IERC20 token, uint256 tokenPrice) {
+ // Implement logic to fetch the token, and token price from the userOp
+}
+```
+
+The contract follows a pre-charge and refund model:
+1. During validation, it pre-charges the maximum possible gas cost
+2. After execution, it refunds any unused gas back to the user
+
+
+
+See [`PaymasterCore._validatePaymasterUserOp`](#PaymasterCore-_validatePaymasterUserOp-struct-PackedUserOperation-bytes32-uint256-).
+
+Attempts to retrieve the `token` and `tokenPrice` from the user operation (see [`PaymasterERC20._fetchDetails`](#PaymasterERC20-_fetchDetails-struct-PackedUserOperation-bytes32-))
+and prefund the user operation using these values and the `maxCost` argument (see [`PaymasterERC20._prefund`](#PaymasterERC20-_prefund-struct-PackedUserOperation-bytes32-contract-IERC20-uint256-address-uint256-)).
+
+Returns `abi.encodePacked(userOpHash, token, tokenPrice, prefundAmount, prefunder, prefundContext)` in
+`context` if the prefund is successful. Otherwise, it returns empty bytes.
+
+
+
+Prefunds the `userOp` by charging the maximum possible gas cost (`maxCost`) in ERC-20 `token`.
+
+The `token` and `tokenPrice` is obtained from the [`PaymasterERC20._fetchDetails`](#PaymasterERC20-_fetchDetails-struct-PackedUserOperation-bytes32-) function and are funded by the `prefunder_`,
+which is the user operation sender by default. The `prefundAmount` is calculated using [`PaymasterERC20._erc20Cost`](#PaymasterERC20-_erc20Cost-uint256-uint256-uint256-).
+
+Returns a `prefundContext` that's passed to the [`PaymasterCore._postOp`](#PaymasterCore-_postOp-enum-IPaymaster-PostOpMode-bytes-uint256-uint256-) function through its `context` return value.
+
+
+Consider not reverting if the prefund fails when overriding this function. This is to avoid reverting
+during the validation phase of the user operation, which may penalize the paymaster's reputation according
+to ERC-7562 validation rules.
+
+
+
+
+Attempts to refund the user operation after execution. See [`PaymasterERC20._refund`](#PaymasterERC20-_refund-contract-IERC20-uint256-uint256-uint256-address-uint256-bytes-).
+
+Reverts with [`PaymasterERC20.PaymasterERC20FailedRefund`](#PaymasterERC20-PaymasterERC20FailedRefund-contract-IERC20-uint256-uint256-bytes-) if the refund fails.
+
+
+This function may revert after the user operation has been executed without
+reverting the user operation itself. Consider implementing a mechanism to handle
+this case gracefully.
+
+
+
+
+Refunds any unused gas back to the user (i.e. `prefundAmount - actualAmount`) in `token`.
+
+The `actualAmount` is calculated using [`PaymasterERC20._erc20Cost`](#PaymasterERC20-_erc20Cost-uint256-uint256-uint256-) and the `actualGasCost`, `actualUserOpFeePerGas`, `prefundContext`
+and the `tokenPrice` from the [`PaymasterCore._postOp`](#PaymasterCore-_postOp-enum-IPaymaster-PostOpMode-bytes-uint256-uint256-)'s context.
+
+
+
+Retrieves payment details for a user operation.
+
+The values returned by this internal function are:
+
+* `validationData`: ERC-4337 validation data, indicating success/failure and optional time validity (`validAfter`, `validUntil`).
+* `token`: Address of the ERC-20 token used for payment to the paymaster.
+* `tokenPrice`: Price of the token in native currency, scaled by `_tokenPriceDenominator()`.
+
+==== Calculating the token price
+
+Given gas fees are paid in native currency, developers can use the `ERC20 price unit / native price unit` ratio to
+calculate the price of an ERC20 token price in native currency. However, the token may have a different number of decimals
+than the native currency. For a a generalized formula considering prices in USD and decimals, consider using:
+
+`( / 10**) / ( / 1e18) * _tokenPriceDenominator()`
+
+For example, suppose token is USDC ($1 with 6 decimals) and native currency is ETH (assuming $2524.86 with 18 decimals),
+then each unit (1e-6) of USDC is worth `(1 / 1e6) / ((252486 / 1e2) / 1e18) = 396061563.8094785` wei. The `_tokenPriceDenominator()`
+ensures precision by avoiding fractional value loss. (i.e. the 0.8094785 part).
+
+
+
+Denominator used for interpreting the `tokenPrice` returned by [`PaymasterERC20._fetchDetails`](#PaymasterERC20-_fetchDetails-struct-PackedUserOperation-bytes32-) as "fixed point" in [`PaymasterERC20._erc20Cost`](#PaymasterERC20-_erc20Cost-uint256-uint256-uint256-).
+
+
+
+Emitted when a user operation identified by `userOpHash` is sponsored by this paymaster
+using the specified ERC-20 `token`. The `tokenAmount` is the amount charged for the operation,
+and `tokenPrice` is the price of the token in native currency (e.g., ETH).
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC20Guarantor.sol";
+```
+
+Extension of [`PaymasterERC20`](#PaymasterERC20) that enables third parties to guarantee user operations.
+
+This contract allows a guarantor to pre-fund user operations on behalf of users. The guarantor
+pays the maximum possible gas cost upfront, and after execution:
+1. If the user repays the guarantor, the guarantor gets their funds back
+2. If the user fails to repay, the guarantor absorbs the cost
+
+A common use case is for guarantors to pay for the operations of users claiming airdrops. In this scenario:
+
+* The guarantor pays the gas fees upfront
+* The user claims their airdrop tokens
+* The user repays the guarantor from the claimed tokens
+* If the user fails to repay, the guarantor absorbs the cost
+
+The guarantor is identified through the [`PaymasterERC20Guarantor._fetchGuarantor`](#PaymasterERC20Guarantor-_fetchGuarantor-struct-PackedUserOperation-) function, which must be implemented
+by developers to determine who can guarantee operations. This allows for flexible guarantor selection
+logic based on the specific requirements of the application.
+
+
+
+Prefunds the user operation using either the guarantor or the default prefunder.
+See [`PaymasterERC20._prefund`](#PaymasterERC20-_prefund-struct-PackedUserOperation-bytes32-contract-IERC20-uint256-address-uint256-).
+
+Returns `abi.encodePacked(..., userOp.sender)` in `prefundContext` to allow
+the refund process to identify the user operation sender.
+
+
+
+Handles the refund process for guaranteed operations.
+
+If the operation was guaranteed, it attempts to get repayment from the user first and then refunds the guarantor.
+Otherwise, fallback to [`PaymasterERC20._refund`](#PaymasterERC20-_refund-contract-IERC20-uint256-uint256-uint256-address-uint256-bytes-).
+
+
+For guaranteed user operations where the user paid the `actualGasCost` back, this function
+doesn't call `super._refund`. Consider whether there are side effects in the parent contract that need to be executed.
+
+
+
+
+Fetches the guarantor address and validation data from the user operation.
+
+
+Return `address(0)` to disable the guarantor feature. If supported, ensure
+explicit consent (e.g., signature verification) to prevent unauthorized use.
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC721Owner.sol";
+```
+
+Extension of [`PaymasterCore`](#PaymasterCore) that supports account based on ownership of an ERC-721 token.
+
+This paymaster will sponsor user operations if the user has at least 1 token of the token specified
+during construction (or via [`PaymasterERC721Owner._setToken`](#PaymasterERC721Owner-_setToken-contract-IERC721-)).
+
+
+
+Internal validation of whether the paymaster is willing to pay for the user operation.
+Returns the context to be passed to postOp and the validation data.
+
+
+The default `context` is `bytes(0)`. Developers that add a context when overriding this function MUST
+also override [`PaymasterCore._postOp`](#PaymasterCore-_postOp-enum-IPaymaster-PostOpMode-bytes-uint256-uint256-) to process the context passed along.
+
+
+
+
+Virtual function that returns the signable hash for a user operations. Given the `userOpHash`
+contains the `paymasterAndData` itself, it's not possible to sign that value directly. Instead,
+this function must be used to provide a custom mechanism to authorize an user operation.
+
+
+
+Internal validation of whether the paymaster is willing to pay for the user operation.
+Returns the context to be passed to postOp and the validation data.
+
+
+The `context` returned is `bytes(0)`. Developers overriding this function MUST
+override [`PaymasterCore._postOp`](#PaymasterCore-_postOp-enum-IPaymaster-PostOpMode-bytes-uint256-uint256-) to process the context passed along.
+
+
+
+
+Decodes the user operation's data from `paymasterAndData`.
+
+
+
diff --git a/docs/content/community-contracts/api/crosschain.mdx b/docs/content/community-contracts/api/crosschain.mdx
new file mode 100644
index 00000000..99392b04
--- /dev/null
+++ b/docs/content/community-contracts/api/crosschain.mdx
@@ -0,0 +1,2013 @@
+---
+title: "Crosschain"
+description: "Smart contract crosschain utilities and implementations"
+---
+
+Gateways are contracts that enable cross-chain communication. These can either be a message source or a destination according to ERC-7786.
+
+* [`ERC7786Receiver`](#ERC7786Receiver): ERC-7786 cross-chain message receiver.
+* [`ERC7786OpenBridge`](#ERC7786OpenBridge): ERC-7786 "N out of M" gateway. Sends a message through M gateways and executes on the destination if N received it.
+
+Developers can access interoperability protocols through gateway adapters. The library includes the following gateway adapters:
+
+* [`AxelarGatewayAdapter`](#AxelarGatewayAdapter): ERC-7786 gateway adapter for Axelar.
+
+## Gateways
+
+[`ERC7786OpenBridge`](#ERC7786OpenBridge)
+
+## Clients
+
+[`ERC7786Receiver`](#ERC7786Receiver)
+
+## Adapters
+
+### Axelar
+
+[`AxelarGatewayAdapter`](#AxelarGatewayAdapter)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/crosschain/ERC7786OpenBridge.sol";
+```
+
+N of M gateway: Sends your message through M independent gateways. It will be delivered to the receiver by an
+equivalent bridge on the destination chain if N of the M gateways agree.
+
+
+
+This function serves a dual purpose:
+
+It will be called by ERC-7786 gateways with message coming from the the corresponding bridge on the source
+chain. These "signals" are tracked until the threshold is reached. At that point the message is sent to the
+destination.
+
+It can also be called by anyone (including an ERC-7786 gateway) to retry the execution. This can be useful if
+the automatic execution (that is triggered when the threshold is reached) fails, and someone wants to retry it.
+
+When a message is forwarded by a known gateway, a [`ERC7786OpenBridge.Received`](#ERC7786OpenBridge-Received-bytes32-address-) event is emitted. If a known gateway calls this
+function more than once (for a given message), only the first call is counts toward the threshold and emits an
+[`ERC7786OpenBridge.Received`](#ERC7786OpenBridge-Received-bytes32-address-) event.
+
+This function revert if:
+
+* the message is not properly formatted or does not originate from the registered bridge on the source
+ chain.
+* someone tries re-execute a message that was already successfully delivered. This includes gateways that call
+ this function a second time with a message that was already executed.
+* the execution of the message (on the [`IERC7786Receiver`](./interfaces#IERC7786Receiver) receiver) is successful but fails to return the
+ executed value.
+
+This function does not revert if:
+
+* A known gateway delivers a message for the first time, and that message was already executed. In that case
+ the message is NOT re-executed, and the correct "magic value" is returned.
+* The execution of the message (on the [`IERC7786Receiver`](./interfaces#IERC7786Receiver) receiver) reverts. In that case a [`ERC7786OpenBridge.ExecutionFailed`](#ERC7786OpenBridge-ExecutionFailed-bytes32-)
+ event is emitted.
+
+This function emits:
+
+* [`ERC7786OpenBridge.Received`](#ERC7786OpenBridge-Received-bytes32-address-) when a known ERC-7786 gateway delivers a message for the first time.
+* [`ERC7786OpenBridge.ExecutionSuccess`](#ERC7786OpenBridge-ExecutionSuccess-bytes32-) when a message is successfully delivered to the receiver.
+* [`ERC7786OpenBridge.ExecutionFailed`](#ERC7786OpenBridge-ExecutionFailed-bytes32-) when a message delivery to the receiver reverted (for example because of OOG error).
+
+
+interface requires this function to be payable. Even if we don't expect any value, a gateway may pass
+some value for unknown reason. In that case we want to register this gateway having delivered the message and
+not revert. Any value accrued that way can be recovered by the admin using the [`ERC7786OpenBridge.sweep`](#ERC7786OpenBridge-sweep-address-payable-) function.
+
+
+
+
+Recovery method in case value is ever received through [`ERC7786OpenBridge.receiveMessage`](#ERC7786OpenBridge-receiveMessage-bytes32-bytes-bytes-)
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayAdapter.sol";
+```
+
+Implementation of an ERC-7786 gateway destination adapter for the Axelar Network in dual mode.
+
+The contract implements AxelarExecutable's [`ERC7579DelayedExecutor._execute`](./account#ERC7579DelayedExecutor-_execute-address-bytes32-bytes32-bytes-) function to execute the message, converting Axelar's native
+workflow into the standard ERC-7786.
+
+
+While both ERC-7786 and Axelar do support non-evm chains, this adaptor does not. This limitation comes from
+the translation of the ERC-7930 interoperable address (binary objects -- bytes) to strings. This is necessary
+because Axelar uses string to represent addresses. For EVM network, this adapter uses a checksum hex string
+representation. Other networks would require a different encoding. Ideally we would have a single encoding for all
+networks (could be base58, base64, ...) but Axelar doesn't support that.
+
+
+
+
+Endpoint for creating a new message. If the message requires further (gateway specific) processing before
+it can be sent to the destination chain, then a non-zero `outboxId` must be returned. Otherwise, the
+message MUST be sent and this function must return 0.
+
+* MUST emit a [`IERC7786GatewaySource.MessageSent`](./interfaces#IERC7786GatewaySource-MessageSent-bytes32-bytes-bytes-bytes-uint256-bytes---) event.
+
+If any of the `attributes` is not supported, this function SHOULD revert with an [`IERC7786GatewaySource.UnsupportedAttribute`](./interfaces#IERC7786GatewaySource-UnsupportedAttribute-bytes4-) error.
+Other errors SHOULD revert with errors not specified in ERC-7786.
+
+
+
+Execution of a cross-chain message.
+
+In this function:
+
+- `axelarSourceChain` is in the Axelar format. It should not be expected to be a proper ERC-7930 format
+- `axelarSourceAddress` is the sender of the Axelar message. That should be the remote gateway on the chain
+ which the message originates from. It is NOT the sender of the ERC-7786 crosschain message.
+
+Proper ERC-7930 encoding of the crosschain message sender can be found in the message
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/crosschain/utils/ERC7786Receiver.sol";
+```
+
+Base implementation of an ERC-7786 compliant cross-chain message receiver.
+
+This abstract contract exposes the `receiveMessage` function that is used for communication with (one or multiple)
+destination gateways. This contract leaves two functions unimplemented:
+
+[`ERC7786Receiver._isKnownGateway`](#ERC7786Receiver-_isKnownGateway-address-), an internal getter used to verify whether an address is recognised by the contract as a valid
+ERC-7786 destination gateway. One or multiple gateway can be supported. Note that any malicious address for which
+this function returns true would be able to impersonate any account on any other chain sending any message.
+
+[`ERC7786Receiver._processMessage`](#ERC7786Receiver-_processMessage-address-bytes32-bytes-bytes-), the internal function that will be called with any message that has been validated.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/crosschain/wormhole/WormholeGatewayAdapter.sol";
+```
+
+An ERC-7786 compliant adapter to send and receive messages via Wormhole.
+
+Note: only EVM chains are currently supported
+
+
+
+Endpoint for creating a new message. If the message requires further (gateway specific) processing before
+it can be sent to the destination chain, then a non-zero `outboxId` must be returned. Otherwise, the
+message MUST be sent and this function must return 0.
+
+* MUST emit a [`IERC7786GatewaySource.MessageSent`](./interfaces#IERC7786GatewaySource-MessageSent-bytes32-bytes-bytes-bytes-uint256-bytes---) event.
+
+If any of the `attributes` is not supported, this function SHOULD revert with an [`IERC7786GatewaySource.UnsupportedAttribute`](./interfaces#IERC7786GatewaySource-UnsupportedAttribute-bytes4-) error.
+Other errors SHOULD revert with errors not specified in ERC-7786.
+
+
+
+Returns a quote for the value that must be passed to [`WormholeGatewayAdapter.requestRelay`](#WormholeGatewayAdapter-requestRelay-bytes32-uint256-address-)
+
+
+
+A message was relayed to Wormhole (part of the post processing of the outbox ids created by [`ERC7786OpenBridge.sendMessage`](#ERC7786OpenBridge-sendMessage-bytes-bytes-bytes---))
+
+
+
+Endpoint for creating a new message. If the message requires further (gateway specific) processing before
+it can be sent to the destination chain, then a non-zero `outboxId` must be returned. Otherwise, the
+message MUST be sent and this function must return 0.
+
+* MUST emit a [`IERC7786GatewaySource.MessageSent`](#IERC7786GatewaySource-MessageSent-bytes32-bytes-bytes-bytes-uint256-bytes---) event.
+
+If any of the `attributes` is not supported, this function SHOULD revert with an [`IERC7786GatewaySource.UnsupportedAttribute`](#IERC7786GatewaySource-UnsupportedAttribute-bytes4-) error.
+Other errors SHOULD revert with errors not specified in ERC-7786.
+
+
+
+Event emitted when a message is created. If `outboxId` is zero, no further processing is necessary. If
+`outboxId` is not zero, then further (gateway specific, and non-standardized) action is required.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/interfaces/IERC7786Attributes.sol";
+```
+
+Standard attributes for ERC-7786. These attributes may be standardized in different ERCs.
+
+
+
+Executes the calls in `executionData`.
+Reverts and bubbles up error if any call fails.
+
+`executionData` encoding:
+
+* If `opData` is empty, `executionData` is simply `abi.encode(calls)`.
+* Else, `executionData` is `abi.encode(calls, opData)`.
+ See: https://eips.ethereum.org/EIPS/eip-7579
+
+Supported modes:
+
+* `bytes32(0x01000000000000000000...)`: does not support optional `opData`.
+* `bytes32(0x01000000000078210001...)`: supports optional `opData`.
+
+Authorization checks:
+
+* If `opData` is empty, the implementation SHOULD require that
+ `msg.sender == address(this)`.
+* If `opData` is not empty, the implementation SHOULD use the signature
+ encoded in `opData` to determine if the caller can perform the execution.
+
+`opData` may be used to store additional data for authentication,
+paymaster data, gas limits, etc.
+
+
+
+This function is provided for frontends to detect support.
+Only returns true for:
+
+* `bytes32(0x01000000000000000000...)`: does not support optional `opData`.
+* `bytes32(0x01000000000078210001...)`: supports optional `opData`.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/interfaces/IERC7969.sol";
+```
+
+This interface provides a standard way to register and validate DKIM public key hashes onchain
+Domain owners can register their DKIM public key hashes and third parties can verify their validity
+The interface enables email-based account abstraction and secure account recovery mechanisms.
+
+
+The ERC-165 identifier for this interface is `0xdee3d600`.
+
+
+
+
+Emitted when a DKIM public key hash is revoked for a domain
+
+
+
diff --git a/docs/content/community-contracts/api/proxy.mdx b/docs/content/community-contracts/api/proxy.mdx
new file mode 100644
index 00000000..9cc675f5
--- /dev/null
+++ b/docs/content/community-contracts/api/proxy.mdx
@@ -0,0 +1,94 @@
+---
+title: "Proxy"
+description: "Smart contract proxy utilities and implementations"
+---
+
+Variants of proxy patterns, which are contracts that allow to forward a call to an implementation contract by using `delegatecall`. This contracts include:
+
+* [`HybridProxy`](#HybridProxy): An ERC-1967 proxy that uses the implementation slot as a beacon in a way that a user can upgrade to an implementation of their choice.
+
+## General
+
+[`HybridProxy`](#HybridProxy)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/proxy/HybridProxy.sol";
+```
+
+A version of an ERC-1967 proxy that uses the address stored in the implementation slot as a beacon.
+
+The design allows to set an initial beacon that the contract may quit by upgrading to its own implementation
+afterwards. Transition between the "beacon mode" and the "direct mode" require implementation that expose an
+upgrade mechanism that writes to the ERC-1967 implementation slot. Note that UUPSUpgradable includes security
+checks that are not compatible with this proxy design.
+
+
+The fallback mechanism relies on the implementation not to define the `IBeacon-implementation` function.
+Consider that if your implementation has this function, it'll be assumed as the beacon address, meaning that
+the returned address will be used as this proxy's implementation.
+
+
+
+
+Initializes the proxy with an initial implementation. If data is present, it will be used to initialize the
+implementation using a delegate call.
+
+
+
+Returns the current implementation address according to ERC-1967's implementation slot.
+
+
+The way this function identifies whether the implementation is a beacon, is by checking
+if it implements the `IBeacon-implementation` function. Consider that an actual implementation could
+define this function, mistakenly identifying it as a beacon.
+
+
+
+
diff --git a/docs/content/community-contracts/api/token.mdx b/docs/content/community-contracts/api/token.mdx
new file mode 100644
index 00000000..aecf4bb2
--- /dev/null
+++ b/docs/content/community-contracts/api/token.mdx
@@ -0,0 +1,2078 @@
+---
+title: "Token"
+description: "Smart contract token utilities and implementations"
+---
+
+Set of extensions and utilities for tokens (e.g ERC-20, ERC-721, ERC-1155) and derivated ERCs (e.g. ERC-4626, ERC-1363).
+
+* [`OnTokenTransferAdapter`](#OnTokenTransferAdapter): Adapter of the ERC-1363 receiver interface to comply with Chainlink’s 667 interface.
+* [`ERC20Allowlist`](#ERC20Allowlist): Extension of ERC20 with transfers and approvals that require users to be registered into an allowlist.
+* [`ERC20Blocklist`](#ERC20Blocklist): Extension of ERC20 with transfers and approvals that can be disabled by adding users into a blocklist.
+* [`ERC20Collateral`](#ERC20Collateral): Oracle-agnostic extension of ERC20 that limits the total supply based on a collateral amount.
+* [`ERC20Custodian`](#ERC20Custodian): Extension of ERC20 that implements an access-control agnostic approach to define a custodian that can freeze user’s transfers and approvals.
+* [`ERC4626Fees`](#ERC4626Fees): ERC4626 vault with fees on entry (deposit/mint) or exit (withdraw/redeem).
+
+## General
+
+[`OnTokenTransferAdapter`](#OnTokenTransferAdapter)
+
+## ERC20
+
+[`ERC20Allowlist`](#ERC20Allowlist)
+
+[`ERC20Blocklist`](#ERC20Blocklist)
+
+[`ERC20Collateral`](#ERC20Collateral)
+
+[`ERC20Custodian`](#ERC20Custodian)
+
+[`ERC4626Fees`](#ERC4626Fees)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Allowlist.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that allows to implement an allowlist
+mechanism that can be managed by an authorized account with the
+[`ERC20Allowlist._disallowUser`](#ERC20Allowlist-_disallowUser-address-) and [`ERC20Allowlist._allowUser`](#ERC20Allowlist-_allowUser-address-) functions.
+
+The allowlist provides the guarantee to the contract owner
+(e.g. a DAO or a well-configured multisig) that any account won't be
+able to execute transfers or approvals to other entities to operate
+on its behalf if [`ERC20Allowlist._allowUser`](#ERC20Allowlist-_allowUser-address-) was not called with such account as an
+argument. Similarly, the account will be disallowed again if
+[`ERC20Allowlist._disallowUser`](#ERC20Allowlist-_disallowUser-address-) is called.
+
+
+Deprecated. Use [`ERC20Restricted`](#ERC20Restricted) instead.
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Blocklist.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that allows to implement a blocklist
+mechanism that can be managed by an authorized account with the
+[`ERC20Blocklist._blockUser`](#ERC20Blocklist-_blockUser-address-) and [`ERC20Blocklist._unblockUser`](#ERC20Blocklist-_unblockUser-address-) functions.
+
+The blocklist provides the guarantee to the contract owner
+(e.g. a DAO or a well-configured multisig) that any account won't be
+able to execute transfers or approvals to other entities to operate
+on its behalf if [`ERC20Blocklist._blockUser`](#ERC20Blocklist-_blockUser-address-) was not called with such account as an
+argument. Similarly, the account will be unblocked again if
+[`ERC20Blocklist._unblockUser`](#ERC20Blocklist-_unblockUser-address-) is called.
+
+
+Deprecated. Use [`ERC20Restricted`](#ERC20Restricted) instead.
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Collateral.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that limits the supply of tokens based
+on a collateral amount and time-based expiration.
+
+The [`ERC20Collateral.collateral`](#ERC20Collateral-collateral--) function must be implemented to return the collateral
+data. This function can call external oracles or use any local storage.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Custodian.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that allows to implement a custodian
+mechanism that can be managed by an authorized account with the
+[`ERC20Custodian.freeze`](#ERC20Custodian-freeze-address-uint256-) function.
+
+This mechanism allows a custodian (e.g. a DAO or a
+well-configured multisig) to freeze and unfreeze the balance
+of a user.
+
+The frozen balance is not available for transfers or approvals
+to other entities to operate on its behalf if. The frozen balance
+can be reduced by calling [`ERC20Custodian.freeze`](#ERC20Custodian-freeze-address-uint256-) again with a lower amount.
+
+
+Deprecated. Use [`ERC20Freezable`](#ERC20Freezable) instead.
+
+
+
+
+Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
+(or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
+this function.
+
+Emits a [`ERC7786OpenBridge.UnsupportedNativeTransfer`](./crosschain#ERC7786OpenBridge-UnsupportedNativeTransfer--) event.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Freezable.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that allows to implement a freezing
+mechanism that can be managed by an authorized account with the
+`_freezeTokens` and `_unfreezeTokens` functions.
+
+The freezing mechanism provides the guarantee to the contract owner
+(e.g. a DAO or a well-configured multisig) that a specific amount
+of tokens held by an account won't be transferable until those
+tokens are unfrozen using `_unfreezeTokens`.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Restricted.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) that allows to implement user account transfer restrictions
+through the [`IERC7943.isUserAllowed`](./interfaces#IERC7943-isUserAllowed-address-) function. Inspired by [EIP-7943](https://eips.ethereum.org/EIPS/eip-7943).
+
+By default, each account has no explicit restriction. The [`IERC7943.isUserAllowed`](./interfaces#IERC7943-isUserAllowed-address-) function acts as
+a blocklist. Developers can override [`IERC7943.isUserAllowed`](./interfaces#IERC7943-isUserAllowed-address-) to check that `restriction == ALLOWED`
+to implement an allowlist.
+
+
+
+Returns whether a user account is allowed to interact with the token.
+
+Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).
+
+To convert into an allowlist, override as:
+
+```solidity
+function isUserAllowed(address account) public view virtual override returns (bool) {
+ return getRestriction(./account) == Restriction.ALLOWED;
+}
+```
+
+
+
+See `ERC20-_update`. Enforces restriction transfers (excluding minting and burning).
+
+Requirements:
+
+* `from` must be allowed to transfer tokens (see [`IERC7943.isUserAllowed`](./interfaces#IERC7943-isUserAllowed-address-)).
+* `to` must be allowed to receive tokens (see [`IERC7943.isUserAllowed`](./interfaces#IERC7943-isUserAllowed-address-)).
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20uRWA.sol";
+```
+
+Extension of [`PaymasterERC20`](./account#PaymasterERC20) according to [EIP-7943](https://eips.ethereum.org/EIPS/eip-7943).
+
+Combines standard ERC-20 functionality with RWA-specific features like user restrictions,
+asset freezing, and forced asset transfers.
+
+
+
+Returns whether a user account is allowed to interact with the token.
+
+Default implementation only disallows explicitly BLOCKED accounts (i.e. a blocklist).
+
+To convert into an allowlist, override as:
+
+```solidity
+function isUserAllowed(address account) public view virtual override returns (bool) {
+ return getRestriction(./account) == Restriction.ALLOWED;
+}
+```
+
+
+
+Returns true if this contract implements the interface defined by
+`interfaceId`. See the corresponding
+[ERC section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
+to learn more about how these ids are created.
+
+This function call must use less than 30 000 gas.
+
+
+
+
+
+
+
+
+
isTransferAllowed(address from, address to, uint256, uint256 amount) → bool
+
+See [`IERC7943.isTransferAllowed`](./interfaces#IERC7943-isTransferAllowed-address-address-uint256-uint256-).
+
+CAUTION: This function is only meant for external use. Overriding it will not apply the new checks to
+the internal [`ERC20Allowlist._update`](#ERC20Allowlist-_update-address-address-uint256-) function. Consider overriding [`ERC20Allowlist._update`](#ERC20Allowlist-_update-address-address-uint256-) accordingly to keep both functions in sync.
+
+
+
+See [`IERC7943.setFrozen`](./interfaces#IERC7943-setFrozen-address-uint256-uint256-).
+
+
+The `amount` is capped to the balance of the `user` to ensure the [`IERC7943.Frozen`](./interfaces#IERC7943-Frozen-address-uint256-uint256-) event
+emits values that consistently reflect the actual amount of tokens that are frozen.
+
+
+
+
+
+
+
+
+
+
forceTransfer(address from, address to, uint256, uint256 amount)
+
+See [`IERC7943.forceTransfer`](./interfaces#IERC7943-forceTransfer-address-address-uint256-uint256-).
+
+Bypasses the [`ERC20Restricted`](#ERC20Restricted) restrictions for the `from` address and adjusts the frozen balance
+to the new balance after the transfer.
+
+
+This function uses [`ERC20Allowlist._update`](#ERC20Allowlist-_update-address-address-uint256-) to perform the transfer, ensuring all standard ERC20
+side effects (such as balance updates and events) are preserved. If you override [`ERC20Allowlist._update`](#ERC20Allowlist-_update-address-address-uint256-)
+to add additional restrictions or logic, those changes will also apply here.
+Consider overriding this function to bypass newer restrictions if needed.
+
+
+
+
+Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
+(or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
+this function.
+
+Emits a [`ERC7786OpenBridge.UnsupportedNativeTransfer`](./crosschain#ERC7786OpenBridge-UnsupportedNativeTransfer--) event.
+
+
+
+
+
+
+
+
+
_checkEnforcer(address from, address to, uint256 amount)
+
+Internal function to check if the `enforcer` is allowed to forcibly transfer the `amount` of `tokens`.
+
+Example usage with `AccessControl-onlyRole`:
+
+```solidity
+function _checkEnforcer(address from, address to, uint256 amount) internal view override onlyRole(ENFORCER_ROLE) {}
+```
+
+
+
+Internal function to check if the `freezer` is allowed to freeze the `amount` of `tokens`.
+
+Example usage with `AccessControl-onlyRole`:
+
+```solidity
+function _checkFreezer(address user, uint256 amount) internal view override onlyRole(FREEZER_ROLE) {}
+```
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/token/OnTokenTransferAdapter.sol";
+```
+
+This contract exposes the 667 `onTokenTransfer` hook on top of `IERC1363Receiver-onTransferReceived`.
+
+Inheriting from this adapter makes your `ERC1363Receiver` contract automatically compatible with tokens, such as
+Chainlink's Link, that implement the 667 interface for transferAndCall.
+
+
diff --git a/docs/content/community-contracts/api/utils.mdx b/docs/content/community-contracts/api/utils.mdx
new file mode 100644
index 00000000..166b04ea
--- /dev/null
+++ b/docs/content/community-contracts/api/utils.mdx
@@ -0,0 +1,975 @@
+---
+title: "Utils"
+description: "Smart contract utils utilities and implementations"
+---
+
+Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives.
+
+* [`EnumerableSetExtended`](#EnumerableSetExtended) and [`EnumerableMapExtended`](#EnumerableMapExtended): Extensions of the `EnumerableSet` and `EnumerableMap` libraries with more types, including non-value types.
+* [`Masks`](#Masks): Library to handle `bytes32` masks.
+
+## Structs
+
+[`EnumerableSetExtended`](#EnumerableSetExtended)
+
+[`EnumerableMapExtended`](#EnumerableMapExtended)
+
+## Libraries
+
+[`Masks`](#Masks)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/structs/EnumerableMapExtended.sol";
+```
+
+Library for managing an enumerable variant of Solidity's
+[`mapping`](https://solidity.readthedocs.io/en/latest/types.html#mapping-types)
+type for non-value types as keys.
+
+Maps have the following properties:
+
+- Entries are added, removed, and checked for existence in constant time
+(O(1)).
+- Entries are enumerated in O(n). No guarantees are made on the ordering.
+- Map can be cleared (all entries removed) in O(n).
+
+```solidity
+contract Example {
+ // Add the library methods
+ using EnumerableMapExtended for EnumerableMapExtended.BytesToUintMap;
+
+ // Declare a set state variable
+ EnumerableMapExtended.BytesToUintMap private myMap;
+}
+```
+
+The following map types are supported:
+
+- `bytes -> uint256` (`BytesToUintMap`)
+- `string -> string` (`StringToStringMap`)
+
+
+Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+unusable.
+See [ethereum/solidity#11843](https://github.com/ethereum/solidity/pull/11843) for more info.
+
+In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
+array of EnumerableMap.
+
+
+Extensions of openzeppelin/contracts/utils/struct/EnumerableMap.sol.
+
+
+
+
+Adds a key-value pair to a map, or updates the value for an existing
+key. O(1).
+
+Returns true if the key was added to the map, that is if it was not
+already present.
+
+
+
+Removes all the entries from a map. O(n).
+
+
+Developers should keep in mind that this function has an unbounded cost and using it may render the
+function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
+
+
+
+
+Returns the key-value pair stored at position `index` in the map. O(1).
+
+Note that there are no guarantees on the ordering of entries inside the
+array, and it may change when more entries are added or removed.
+
+Requirements:
+
+- `index` must be strictly less than [`EnumerableMapExtended.length`](#EnumerableMapExtended-length-struct-EnumerableMapExtended-StringToStringMap-).
+
+
+
+
+
+
+
+
+
tryGet(struct EnumerableMapExtended.BytesToUintMap map, bytes key) → bool exists, uint256 value
+
+Returns an array containing all the keys
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
+Returns an array containing a slice of the keys
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
+Adds a key-value pair to a map, or updates the value for an existing
+key. O(1).
+
+Returns true if the key was added to the map, that is if it was not
+already present.
+
+
+
+Removes all the entries from a map. O(n).
+
+
+Developers should keep in mind that this function has an unbounded cost and using it may render the
+function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
+
+
+
+
+Returns the key-value pair stored at position `index` in the map. O(1).
+
+Note that there are no guarantees on the ordering of entries inside the
+array, and it may change when more entries are added or removed.
+
+Requirements:
+
+- `index` must be strictly less than [`EnumerableMapExtended.length`](#EnumerableMapExtended-length-struct-EnumerableMapExtended-StringToStringMap-).
+
+
+
+
+
+
+
+
+
tryGet(struct EnumerableMapExtended.StringToStringMap map, string key) → bool exists, string value
+
+Returns an array containing all the keys
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
+Returns an array containing a slice of the keys
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/structs/EnumerableSetExtended.sol";
+```
+
+Library for managing
+[sets](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) of non-value
+types.
+
+Sets have the following properties:
+
+- Elements are added, removed, and checked for existence in constant time
+(O(1)).
+- Elements are enumerated in O(n). No guarantees are made on the ordering.
+- Set can be cleared (all elements removed) in O(n).
+
+```solidity
+contract Example {
+ // Add the library methods
+ using EnumerableSetExtended for EnumerableSetExtended.StringSet;
+
+ // Declare a set state variable
+ EnumerableSetExtended.StringSet private mySet;
+}
+```
+
+Sets of type `string` (`StringSet`), `bytes` (`BytesSet`) and
+`bytes32[2]` (`Bytes32x2Set`) are supported.
+
+
+Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+unusable.
+See [ethereum/solidity#11843](https://github.com/ethereum/solidity/pull/11843) for more info.
+
+In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
+array of EnumerableSet.
+
+
+This is an extension of openzeppelin/contracts/utils/struct/EnumerableSet.sol.
+
+
+
+
+Removes all the values from a set. O(n).
+
+
+Developers should keep in mind that this function has an unbounded cost and using it may render the
+function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
+
+
+
+
+Returns the value stored at position `index` in the set. O(1).
+
+Note that there are no guarantees on the ordering of values inside the
+array, and it may change when more values are added or removed.
+
+Requirements:
+
+- `index` must be strictly less than [`EnumerableMapExtended.length`](#EnumerableMapExtended-length-struct-EnumerableMapExtended-StringToStringMap-).
+
+
+
+Return the entire set in an array
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
+Return a slice of the set in an array
+
+
+This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+this function has an unbounded cost, and using it as part of a state-changing function may render the function
+uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
+
+
+
+
diff --git a/docs/content/community-contracts/api/utils/cryptography.mdx b/docs/content/community-contracts/api/utils/cryptography.mdx
new file mode 100644
index 00000000..b2365ff0
--- /dev/null
+++ b/docs/content/community-contracts/api/utils/cryptography.mdx
@@ -0,0 +1,936 @@
+---
+title: "Cryptography"
+description: "Smart contract cryptography utilities and implementations"
+---
+
+A collection of contracts and libraries that implement various signature validation schemes and cryptographic primitives. These utilities enable secure authentication, multisignature operations, and advanced cryptographic operations in smart contracts.
+
+* [`ZKEmailUtils`](#ZKEmailUtils): Library for ZKEmail signature validation utilities, enabling email-based authentication through zero-knowledge proofs.
+* [`WebAuthn`](#WebAuthn): Library for verifying WebAuthn Authentication Assertions.
+* [`DKIMRegistry`](#DKIMRegistry): Implementation of [ERC-7969](https://eips.ethereum.org/EIPS/eip-7969) to enable onchain verification of DomainKeys Identified Mail (DKIM) signatures.
+* [`SignerZKEmail`](#SignerZKEmail): Implementation of an [AbstractSigner](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#AbstractSigner) that enables email-based authentication through zero-knowledge proofs.
+* [`SignerWebAuthn`](#SignerWebAuthn): Implementation of [SignerP256](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#SignerP256) that supports WebAuthn authentication assertions.
+* [`ERC7913ZKEmailVerifier`](#ERC7913ZKEmailVerifier), [`ERC7913WebAuthnVerifier`](#ERC7913WebAuthnVerifier): Ready to use ERC-7913 signature verifiers for ZKEmail and WebAuthn.
+
+## Utils
+
+[`ZKEmailUtils`](#ZKEmailUtils)
+
+[`WebAuthn`](#WebAuthn)
+
+[`DKIMRegistry`](#DKIMRegistry)
+
+## Abstract Signers
+
+[`SignerZKEmail`](#SignerZKEmail)
+
+[`SignerWebAuthn`](#SignerWebAuthn)
+
+## Verifiers
+
+[`ERC7913ZKEmailVerifier`](#ERC7913ZKEmailVerifier)
+
+[`ERC7913WebAuthnVerifier`](#ERC7913WebAuthnVerifier)
+
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/DKIMRegistry.sol";
+```
+
+Implementation of the [ERC-7969](https://eips.ethereum.org/EIPS/eip-7969) interface for registering
+and validating DomainKeys Identified Mail (DKIM) public key hashes onchain.
+
+This contract provides a standard way to register and validate DKIM public key hashes, enabling
+email-based account abstraction and secure account recovery mechanisms. Domain owners can register
+their DKIM public key hashes and third parties can verify their validity.
+
+The contract stores mappings of domain hashes to DKIM public key hashes, where:
+
+* Domain hash: keccak256 hash of the lowercase domain name
+* Key hash: keccak256 hash of the DKIM public key
+
+Example of usage:
+
+```solidity
+contract MyDKIMRegistry is DKIMRegistry, Ownable {
+ function setKeyHash(bytes32 domainHash, bytes32 keyHash) public onlyOwner {
+ _setKeyHash(domainHash, keyHash);
+ }
+
+ function setKeyHashes(bytes32 domainHash, bytes32[] memory keyHashes) public onlyOwner {
+ _setKeyHashes(domainHash, keyHashes);
+ }
+
+ function revokeKeyHash(bytes32 domainHash, bytes32 keyHash) public onlyOwner {
+ _revokeKeyHash(domainHash, keyHash);
+ }
+}
+```
+
+
+
+Sets a DKIM key hash as valid for a domain. Internal version without access control.
+
+Emits a [`IDKIMRegistry.KeyHashRegistered`](../interfaces#IDKIMRegistry-KeyHashRegistered-bytes32-bytes32-) event.
+
+
+This function does not validate that keyHash is non-zero. Consider adding
+validation in derived contracts if needed.
+
+
+
+
+Sets multiple DKIM key hashes as valid for a domain in a single transaction.
+Internal version without access control.
+
+Emits a [`IDKIMRegistry.KeyHashRegistered`](../interfaces#IDKIMRegistry-KeyHashRegistered-bytes32-bytes32-) event for each key hash.
+
+
+This function does not validate that the keyHashes array is non-empty.
+Consider adding validation in derived contracts if needed.
+
+
+
+
+Revokes a DKIM key hash for a domain, making it invalid.
+Internal version without access control.
+
+Emits a [`IDKIMRegistry.KeyHashRevoked`](../interfaces#IDKIMRegistry-KeyHashRevoked-bytes32-) event.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/WebAuthn.sol";
+```
+
+Library for verifying WebAuthn Authentication Assertions.
+
+WebAuthn enables strong authentication for smart contracts using
+[P256](https://docs.openzeppelin.com/contracts/5.x/api/utils#P256)
+as an alternative to traditional secp256k1 ECDSA signatures. This library verifies
+signatures generated during WebAuthn authentication ceremonies as specified in the
+[WebAuthn Level 2 standard](https://www.w3.org/TR/webauthn-2/).
+
+For blockchain use cases, the following WebAuthn validations are intentionally omitted:
+
+* Origin validation: Origin verification in `clientDataJSON` is omitted as blockchain
+ contexts rely on authenticator and dapp frontend enforcement. Standard authenticators
+ implement proper origin validation.
+* RP ID hash validation: Verification of `rpIdHash` in authenticatorData against expected
+ RP ID hash is omitted. This is typically handled by platform-level security measures.
+ Including an expiry timestamp in signed data is recommended for enhanced security.
+* Signature counter: Verification of signature counter increments is omitted. While
+ useful for detecting credential cloning, on-chain operations typically include nonce
+ protection, making this check redundant.
+* Extension outputs: Extension output value verification is omitted as these are not
+ essential for core authentication security in blockchain applications.
+* Attestation: Attestation object verification is omitted as this implementation
+ focuses on authentication (`webauthn.get`) rather than registration ceremonies.
+
+Inspired by:
+
+* [daimo-eth implementation](https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol)
+* [base implementation](https://github.com/base/webauthn-sol/blob/main/src/WebAuthn.sol)
+
+
+
+Performs verification of a WebAuthn Authentication Assertion. This variants allow the caller to select
+whether of not to require the UV flag (step 17).
+
+Verifies:
+
+1. Type is "webauthn.get" (see [`WebAuthn._validateExpectedTypeHash`](#WebAuthn-_validateExpectedTypeHash-string-uint256-))
+2. Challenge matches the expected value (see [`WebAuthn._validateChallenge`](#WebAuthn-_validateChallenge-string-uint256-bytes-))
+3. Cryptographic signature is valid for the given public key
+4. confirming physical user presence during authentication
+5. (if `requireUV` is true) confirming stronger user authentication (biometrics/PIN)
+6. Backup Eligibility (`BE`) and Backup State (BS) bits relationship is valid
+
+
+
+Verifies that calldata bytes (`input`) represents a valid `WebAuthnAuth` object. If encoding is valid,
+returns true and the calldata view at the object. Otherwise, returns false and an invalid calldata object.
+
+
+The returned `auth` object should not be accessed if `success` is false. Trying to access the data may
+cause revert/panic.
+
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/ZKEmailUtils.sol";
+```
+
+Library for [ZKEmail](https://docs.zk.email) Groth16 proof validation utilities.
+
+ZKEmail is a protocol that enables email-based authentication and authorization for smart contracts
+using zero-knowledge proofs. It allows users to prove ownership of an email address without revealing
+the email content or private keys.
+
+The validation process involves several key components:
+
+* A [DKIMRegistry](https://docs.zk.email/architecture/dkim-verification) (DomainKeys Identified Mail) verification
+mechanism to ensure the email was sent from a valid domain. Defined by an `IDKIMRegistry` interface.
+* A [command template](https://docs.zk.email/email-tx-builder/architecture/command-templates) validation
+mechanism to ensure the email command matches the expected format and parameters.
+* A [zero-knowledge proof](https://docs.zk.email/architecture/zk-proofs#how-zk-email-uses-zero-knowledge-proofs) verification
+mechanism to ensure the email was actually sent and received without revealing its contents. Defined by an `IGroth16Verifier` interface.
+
+
+
+Variant of [`ZKEmailUtils.isValidZKEmail`](#ZKEmailUtils-isValidZKEmail-struct-EmailProof-contract-IDKIMRegistry-contract-IGroth16Verifier-string---bytes---enum-ZKEmailUtils-Case-) that validates the `["signHash", "../access#AccessManagerLight-ADMIN_ROLE-uint8"]` command template.
+
+
+
+Validates a ZKEmail proof against a command template.
+
+This function takes an email proof, a DKIM registry contract, and a verifier contract
+as inputs. It performs several validation checks and returns an [`ZKEmailUtils.EmailProofError`](#ZKEmailUtils-EmailProofError) indicating the result.
+Returns `EmailProofError.NoError` if all validations pass, or a specific [`ZKEmailUtils.EmailProofError`](#ZKEmailUtils-EmailProofError) indicating
+which validation check failed.
+
+
+Attempts to validate the command for all possible string [`ZKEmailUtils.Case`](#ZKEmailUtils-Case) values.
+
+
+
+
+Variant of [`ZKEmailUtils.isValidZKEmail`](#ZKEmailUtils-isValidZKEmail-struct-EmailProof-contract-IDKIMRegistry-contract-IGroth16Verifier-string---bytes---enum-ZKEmailUtils-Case-) that validates a template with a specific string [`ZKEmailUtils.Case`](#ZKEmailUtils-Case).
+
+Useful for templates with Ethereum address matchers (i.e. ``ethAddr``), which are case-sensitive (e.g., `["someCommand", "../access#AccessManagerLight-_groups-mapping-address----Masks-Mask-"]`).
+
+
+
+Verifies that calldata bytes (`input`) represents a valid `EmailProof` object. If encoding is valid,
+returns true and the calldata view at the object. Otherwise, returns false and an invalid calldata object.
+
+
+The returned `emailProof` object should not be accessed if `success` is false. Trying to access the data may
+cause revert/panic.
+
+
+
+
+Builds the expected public signals array for the Groth16 verifier from the given EmailProof.
+
+Packs the domain, public key hash, email nullifier, timestamp, masked command, account salt, and isCodeExist fields
+into a uint256 array in the order expected by the verifier circuit.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/signers/SignerWebAuthn.sol";
+```
+
+Implementation of `SignerP256` that supports WebAuthn authentication assertions.
+
+This contract enables signature validation using WebAuthn authentication assertions,
+leveraging the P256 public key stored in the contract. It allows for both WebAuthn
+and raw P256 signature validation, providing compatibility with both signature types.
+
+The signature is expected to be an abi-encoded [`WebAuthn.WebAuthnAuth`](#WebAuthn-WebAuthnAuth) struct.
+
+Example usage:
+
+```solidity
+contract MyAccountWebAuthn is Account, SignerWebAuthn, Initializable {
+ function initialize(bytes32 qx, bytes32 qy) public initializer {
+ _setSigner(qx, qy);
+ }
+}
+```
+
+
+Failing to call [`ERC7579Signature._setSigner`](../account#ERC7579Signature-_setSigner-address-bytes-) either during construction (if used standalone)
+or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
+
+
+
+
+Validates a raw signature using the WebAuthn authentication assertion.
+
+In case the signature can't be validated, it falls back to the
+`SignerP256-_rawSignatureValidation` method for raw P256 signature validation by passing
+the raw `r` and `s` values from the signature.
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/signers/SignerZKEmail.sol";
+```
+
+Implementation of `AbstractSigner` using [ZKEmail](https://docs.zk.email) signatures.
+
+ZKEmail enables secure authentication and authorization through email messages, leveraging
+DKIM signatures from a [`DKIMRegistry`](#DKIMRegistry) and zero-knowledge proofs enabled by a [`SignerZKEmail.verifier`](#SignerZKEmail-verifier--)
+contract that ensures email authenticity without revealing sensitive information. The DKIM
+registry is trusted to correctly update DKIM keys, but users can override this behaviour and
+set their own keys. This contract implements the core functionality for validating email-based
+signatures in smart contracts.
+
+Developers must set the following components during contract initialization:
+
+* [`SignerZKEmail.accountSalt`](#SignerZKEmail-accountSalt--) - A unique identifier derived from the user's email address and account code.
+* [`DKIMRegistry`](#DKIMRegistry) - An instance of the DKIM registry contract for domain verification.
+* [`SignerZKEmail.verifier`](#SignerZKEmail-verifier--) - An instance of the Groth16Verifier contract for zero-knowledge proof validation.
+
+Example of usage:
+
+```solidity
+contract MyAccountZKEmail is Account, SignerZKEmail, Initializable {
+ function initialize(
+ bytes32 accountSalt,
+ IDKIMRegistry registry,
+ IGroth16Verifier groth16Verifier
+ ) public initializer {
+ // Will revert if the signer is already initialized
+ _setAccountSalt(accountSalt);
+ _setDKIMRegistry(registry);
+ _setVerifier(groth16Verifier);
+ }
+}
+```
+
+
+Failing to call [`SignerZKEmail._setAccountSalt`](#SignerZKEmail-_setAccountSalt-bytes32-), [`SignerZKEmail._setDKIMRegistry`](#SignerZKEmail-_setDKIMRegistry-contract-IDKIMRegistry-), and [`SignerZKEmail._setVerifier`](#SignerZKEmail-_setVerifier-contract-IGroth16Verifier-)
+either during construction (if used standalone) or during initialization (if used as a clone) may
+leave the signer either front-runnable or unusable.
+
+
+
+
+Unique identifier for owner of this contract defined as a hash of an email address and an account code.
+
+An account code is a random integer in a finite scalar field of [BN254](https://neuromancer.sk/std/bn/bn254) curve.
+It is a private randomness to derive a CREATE2 salt of the user's Ethereum address
+from the email address, i.e., userEtherAddr := CREATE2(hash(userEmailAddr, accountCode)).
+
+The account salt is used for:
+
+* Privacy: Enables email address privacy on-chain so long as the randomly generated account code is not revealed
+ to an adversary.
+* Security: Provides a unique identifier that cannot be easily guessed or brute-forced, as it's derived
+ from both the email address and a random account code.
+* Deterministic Address Generation: Enables the creation of deterministic addresses based on email addresses,
+ allowing users to recover their accounts using only their email.
+
+
+
+See `AbstractSigner-_rawSignatureValidation`. Validates a raw signature by:
+
+1. Decoding the email proof from the signature
+2. Validating the account salt matches
+3. Verifying the email proof using ZKEmail utilities
+
+
+
+```solidity
+import "@openzeppelin/community-contracts/utils/cryptography/verifiers/ERC7913WebAuthnVerifier.sol";
+```
+
+ERC-7913 signature verifier that supports WebAuthn authentication assertions.
+
+This verifier enables the validation of WebAuthn signatures using P256 public keys.
+The key is expected to be a 64-byte concatenation of the P256 public key coordinates (qx || qy).
+The signature is expected to be an abi-encoded [`WebAuthn.WebAuthnAuth`](#WebAuthn-WebAuthnAuth) struct.
+
+Uses `WebAuthn-verifyMinimal` for signature verification, which performs the essential
+WebAuthn checks: type validation, challenge matching, and cryptographic signature verification.
+
+
+Wallets that may require default P256 validation may install a P256 verifier separately.
+
+
+
+
+Verifies `signature` as a valid signature of `hash` by `key`.
+
+MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid.
+SHOULD return 0xffffffff or revert if the signature is not valid.
+SHOULD return 0xffffffff or revert if the key is empty
+
+
+
+Verifies a zero-knowledge proof of an email signature validated by a [`DKIMRegistry`](#DKIMRegistry) contract.
+
+The key format is ABI-encoded (IDKIMRegistry, bytes32, IGroth16Verifier) where:
+
+* IDKIMRegistry: The registry contract that validates DKIM public key hashes
+* bytes32: The account salt that uniquely identifies the user's email address
+* IGroth16Verifier: The verifier contract instance for ZK proof verification.
+
+See [`ERC7913ZKEmailVerifier._decodeKey`](#ERC7913ZKEmailVerifier-_decodeKey-bytes-) for the key encoding format.
+
+The signature is an ABI-encoded [`ZKEmailUtils.EmailProofError`](#ZKEmailUtils-EmailProofError) struct containing
+the proof details.
+
+Signature encoding:
+
+```solidity
+bytes memory signature = abi.encode(EmailProof({
+ domainName: "example.com", // The domain name of the email sender
+ publicKeyHash: bytes32(0x...), // Hash of the DKIM public key used to sign the email
+ timestamp: block.timestamp, // When the email was sent
+ maskedCommand: "signHash 12345...", // The command being executed, with sensitive data masked
+ emailNullifier: bytes32(0x...), // Unique identifier for the email to prevent replay attacks
+ accountSalt: bytes32(0x...), // Unique identifier derived from email and account code
+ isCodeExist: true, // Whether the account code exists in the proof
+ proof: bytes(0x...) // The zero-knowledge proof verifying the email's authenticity
+}));
+```
+
+
+
+Decodes the key into its components.
+
+```solidity
+bytes memory key = abi.encode(registry, accountSalt, verifier);
+```
+
+
+
diff --git a/docs/content/community-contracts/crosschain.mdx b/docs/content/community-contracts/crosschain.mdx
new file mode 100644
index 00000000..804aa1d0
--- /dev/null
+++ b/docs/content/community-contracts/crosschain.mdx
@@ -0,0 +1,167 @@
+---
+title: Cross-chain messaging
+---
+
+Developers building contracts may require cross-chain functionality. To accomplish this, multiple protocols have implemented their own ways to process operations across chains.
+
+The variety of these bridges is outlined in [@norswap](https://x.com/norswap)'s [Cross-Chain Interoperability Report](https://github.com/0xFableOrg/xchain/blob/master/README.md) that proposes [a taxonomy of 7 bridge categories](https://github.com/0xFableOrg/xchain/blob/master/README.md#bridge-taxonomy). This diversity makes it difficult for developers to design cross-chain applications given the lack of portability.
+
+This guide will teach you how to follow [ERC-7786](https://eips.ethereum.org/EIPS/eip-7786) to establish messaging gateways across chains regardless of the underlying bridge. Developers can implement gateway contracts that process cross-chain messages and connect any crosschain protocol they want (or implement themselves).
+
+## ERC-7786 Gateway
+
+To address the lack of composability in a simple and unopinionated way, ERC-7786 proposes a standard for implementing gateways that relay messages to other chains. This generalized approach is expressive enough to enable new types of applications and can be adapted to any bridge taxonomy or specific bridge interface with standardized attributes.
+
+### Message passing overview
+
+The ERC defines a source and a destination gateway. Both are contracts that implement a protocol to send a message and process its reception respectively. These two processes are identified explicitly by the ERC-7786 specification since they define the minimal requirements for both gateways.
+
+* On the ***source chain***, the contract implements a standard [`sendMessage`](/community-contracts/api/crosschain#AxelarGatewaySource-sendMessage-bytes-bytes-bytes---) function and emits a [`MessageSent`](/community-contracts/api/crosschain#AxelarGatewaySource-MessageSent-bytes32-string-string-bytes-bytes---) event to signal that the message should be relayed by the underlying protocol.
+* On the ***destination chain***, the gateway receives the message and passes it to the receiver contract by calling the [`receiveMessage`](/community-contracts/api/crosschain#ERC7786Receiver-receiveMessage-bytes32-bytes-bytes-) function.
+
+Smart contract developers only need to worry about implementing the [IERC7786GatewaySource](/community-contracts/api/crosschain#IERC7786GatewaySource) interface to send a message on the source chain and the [IERC7786GatewaySource](/community-contracts/api/crosschain#IERC7786GatewaySource) and [IERC7786Receiver](/community-contracts/api/crosschain#IERC7786Receiver) interface to receive such message on the destination chain.
+
+### Getting started with Axelar Network
+
+To start sending cross-chain messages, developers can get started with a duplex gateway powered by Axelar Network. This will allow a contract to send or receive cross-chain messages leveraging automated execution by Axelar relayers on the destination chain.
+
+./examples/crosschain/MyCustomAxelarGatewayDuplex.sol
+
+For more details of how the duplex gateway works, see [how to send and receive messages with the Axelar Network](#axelar-network) below
+
+
+Developers can register supported chains and destination gateways using the [`registerChainEquivalence`](/community-contracts/api/crosschain#AxelarGatewayBase-registerChainEquivalence-string-string-) and [`registerRemoteGateway`](/community-contracts/api/crosschain#AxelarGatewayBase-registerRemoteGateway-string-string-) functions
+
+
+## Cross-chain communication
+
+### Sending a message
+
+The interface for a source gateway is general enough that it allows wrapping a custom protocol to authenticate messages. Depending on the use case, developers can implement any offchain mechanism to read the standard [`MessageSent`](/community-contracts/api/crosschain#IERC7786GatewaySource-MessageSent-bytes32-string-string-bytes-bytes---) event and deliver it to the receiver on the destination chain.
+
+./examples/crosschain/MyERC7786GatewaySource.sol
+
+
+The standard represents chains using [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) identifiers and accounts using [CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) identifiers for increased interoperability with non-EVM chains. Consider using the Strings library in the contracts library to process these identifiers.
+
+
+### Receiving a message
+
+To successfully process a message on the destination chain, a destination gateway is required. Although ERC-7786 doesn’t define a standard interface for the destination gateway, it requires that it calls the `receiveMessage` upon message reception.
+
+Every cross-chain message protocol already offers a way to receive the message either through a canonical bridge or an intermediate contract. Developers can easily wrap the receiving contract into a gateway that calls the `receiveMessage` function as mandated by the ERC.
+
+To receive a message on a custom smart contract, OpenZeppelin Community Contracts provide an [ERC7786Receiver](/community-contracts/api/crosschain#ERC7786Receiver) implementation for developers to inherit. This way your contracts can receive a cross-chain message relayed through a known destination gateway gateway.
+
+./examples/crosschain/MyERC7786ReceiverContract.sol
+
+The standard receiving interface abstracts away the underlying protocol. This way, it is possible for a contract to send a message through an ERC-7786 compliant gateway (or through an adapter) and get it received on the destination chain without worrying about the protocol implementation details.
+
+### Axelar Network
+
+Aside from the [AxelarGatewayDuplex](/community-contracts/api/crosschain#AxelarGatewayDuplex), the library offers an implementation of the [IERC7786GatewaySource](/community-contracts/api/crosschain#IERC7786GatewaySource) interface called [AxelarGatewaySource](/community-contracts/api/crosschain#AxelarGatewaySource) that works as an adapter for sending messages in compliance with ERC-7786
+
+The implementation takes a local gateway address that MUST correspond to [Axelar’s native gateways](https://axelarscan.io/resources/chains?type=evm) and has mechanisms to:
+
+* Keep track of equivalences between Axelar chain names and CAIP-2 identifiers
+* Record a destination gateway per network using their CAIP-2 identifier
+
+The [AxelarGatewaySource](/community-contracts/api/crosschain#AxelarGatewaySource) implementation can be used out of the box
+
+./examples/crosschain/MyCustomAxelarGatewaySource.sol
+
+For a destination gateway, the library provides an adapter of the `AxelarExecutable` interface to receive messages and relay them to an [IERC7786Receiver](/community-contracts/api/crosschain#IERC7786Receiver).
+
+./examples/crosschain/MyCustomAxelarGatewayDestination.sol
+
+### Open Bridge
+
+The [ERC7786OpenBridge](/community-contracts/api/crosschain#ERC7786OpenBridge) is a special gateway that implements both [IERC7786GatewaySource](/community-contracts/api/crosschain#IERC7786GatewaySource) and [IERC7786Receiver](/community-contracts/api/crosschain#IERC7786Receiver) interfaces. It provides a way to send messages across multiple bridges simultaneously and ensures message delivery through a threshold-based confirmation system.
+
+The bridge maintains a list of known gateways and a confirmation threshold. When sending a message, it broadcasts to all registered gateways, and when receiving, it requires a minimum number of confirmations before executing the message. This approach increases reliability by ensuring messages are properly delivered and validated across multiple bridges.
+
+When sending a message, the bridge tracks the message IDs from each gateway to maintain a record of the message’s journey across different bridges:
+
+```solidity
+function sendMessage(
+ string calldata destinationChain,
+ string memory receiver,
+ bytes memory payload,
+ bytes[] memory attributes
+) public payable virtual whenNotPaused returns (bytes32 outboxId) {
+
+ // ... Initialize variables and prepare payload ...
+
+ // Post on all gateways
+ Outbox[] memory outbox = new Outbox[](_gateways.length());
+ bool needsId = false;
+ for (uint256 i = 0; i < outbox.length; ++i) {
+ address gateway = _gateways.at(i);
+ // send message
+ bytes32 id = IERC7786GatewaySource(gateway).sendMessage(
+ destinationChain,
+ bridge,
+ wrappedPayload,
+ attributes
+ );
+ // if ID, track it
+ if (id != bytes32(0)) {
+ outbox[i] = Outbox(gateway, id);
+ needsId = true;
+ }
+ }
+
+ // ... Handle message tracking and return value ...
+}
+```
+
+On the receiving end, the bridge implements a threshold-based confirmation system. Messages are only executed after receiving enough confirmations from the gateways, ensuring message validity and preventing double execution. The [`receiveMessage`](/community-contracts/api/crosschain#ERC7786OpenBridge-receiveMessage-string-string-string-bytes-bytes---) function handles this process:
+
+```solidity
+function receiveMessage(
+ string calldata /**messageId**/, // gateway specific, empty or unique
+ string calldata sourceChain, // CAIP-2 chain identifier
+ string calldata sender, // CAIP-10 account address (does not include the chain identifier)
+ bytes calldata payload,
+ bytes[] calldata attributes
+) public payable virtual whenNotPaused returns (bytes4) {
+
+ // ... Validate message format and extract message ID ...
+
+ // If call is first from a trusted gateway
+ if (_gateways.contains(msg.sender) && !tracker.receivedBy[msg.sender]) {
+ // Count number of time received
+ tracker.receivedBy[msg.sender] = true;
+ tracker.countReceived++;
+ emit Received(id, msg.sender);
+ }
+
+ // if already executed, leave gracefully
+ if (tracker.executed) return IERC7786Receiver.receiveMessage.selector;
+ else if (tracker.executed) {
+ revert ERC7786OpenBridgeAlreadyExecuted();
+ }
+
+ // .. Validate sender and prepare payload for execution ...
+
+ // If ready to execute, and not yet executed
+ if (tracker.countReceived >= getThreshold()) {
+ // prevent re-entry
+ tracker.executed = true;
+
+ // ... Prepare execution context and validate state ...
+ bytes memory call = abi.encodeCall(
+ IERC7786Receiver.receiveMessage,
+ (uint256(id).toHexString(32), sourceChain, originalSender, unwrappedPayload, attributes)
+ );
+
+ (bool success, bytes memory returndata) = receiver.parseAddress().call(call);
+
+ // ... Handle the result ...
+ }
+
+ return IERC7786Receiver.receiveMessage.selector;
+}
+```
+
+The bridge is designed to be configurable. As an `Ownable` contract, it allows the owner to manage the list of trusted gateways and adjust the confirmation threshold. The `_gateways` list and threshold are initially set during contract deployment using the [`_addGateway`](/community-contracts/api/crosschain#ERC7786OpenBridge-_addGateway-address-) and [`_setThreshold`](/community-contracts/api/crosschain#ERC7786OpenBridge-_setThreshold-uint8-) functions. The owner can update these settings as needed to adapt to changing requirements or add new gateways.
diff --git a/docs/content/community-contracts/index.mdx b/docs/content/community-contracts/index.mdx
new file mode 100644
index 00000000..6cc6cac0
--- /dev/null
+++ b/docs/content/community-contracts/index.mdx
@@ -0,0 +1,45 @@
+---
+title: Community Contracts
+---
+
+**A community-driven extension of our [Solidity library](https://docs.openzeppelin.com/contracts)**: the gold-standard of smart contract development. This library includes:
+
+* Extensions and modules compatible with contracts in the original package
+* Alternative implementation of interfaces defined in the original package
+* Contracts with third-party integrations
+* Contracts built by community members, that align with OpenZeppelin offerings
+* General prototypes and experiments
+
+Code is provided by the OpenZeppelin Contracts team, as well as by community contributors, for other developers to review, discuss, iterate on, and potentially use.
+
+## Overview
+
+### Installation
+
+Given this extension is intended for more experimental use cases and therefore the development process is more flexible. For such reason, the library can only be installed with Foundry using gitmodules.
+
+#### Foundry (git)
+
+```console
+$ forge install OpenZeppelin/openzeppelin-community-contracts
+```
+
+
+Make sure to add `@openzeppelin/community-contracts/=lib/openzeppelin-community-contracts/contracts/` in `remappings.txt.`
+
+
+### Usage
+
+Once installed, you can use the contracts in the library by importing them:
+
+./examples/MyStablecoinAllowlist.sol
+
+To keep your system secure, you should ***always*** use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don’t need to worry about it needlessly increasing gas costs.
+
+## Security
+
+Contracts in the community library are provided as is, with no particular guarantees. Given changes in this repository are more frequent, the code is not formally audited and not covered by the [bug bounty program on Immunefi](https://www.immunefi.com/bounty/openzeppelin).
+
+Similarly, the code has no backward compatibility guarantees.
+
+We kindly ask to report any issue directly to our security [contact](mailto:security@openzeppelin.org). The team will do its best to assist and mitigate any potential misuses of the library. However, keep in mind the flexibility assumed for this repository may relax our assessment.
diff --git a/docs/content/community-contracts/paymasters.mdx b/docs/content/community-contracts/paymasters.mdx
new file mode 100644
index 00000000..f1e1c73a
--- /dev/null
+++ b/docs/content/community-contracts/paymasters.mdx
@@ -0,0 +1,508 @@
+---
+title: Paymasters
+---
+
+In case you want to sponsor user operations for your users, ERC-4337 defines a special type of contract called _paymaster_, whose purpose is to pay the gas fees consumed by the user operation.
+
+In the context of account abstraction, sponsoring user operations allows a third party to pay for transaction gas fees on behalf of users. This can improve user experience by eliminating the need for users to hold native cryptocurrency (like ETH) to pay for transactions.
+
+To enable sponsorship, users sign their user operations including a special field called `paymasterAndData`, resulting from the concatenation of the paymaster address they’re intending to use and the associated calldata that’s going to be passed into [`validatePaymasterUserOp`](/community-contracts/api/utils/cryptography#PaymasterCore-validatePaymasterUserOp). The EntryPoint will use this field to determine whether it is willing to pay for the user operation or not.
+
+## Signed Sponsorship
+
+The [`PaymasterSigner`](/community-contracts/api/account#PaymasterSigner) implements signature-based sponsorship via authorization signatures, allowing designated paymaster signers to authorize and sponsor specific user operations without requiring users to hold native ETH.
+
+
+Learn more about [signers](/contracts/5.x/accounts#selecting-a-signer) to explore different approaches to user operation sponsorship via signatures.
+
+
+./examples/account/paymaster/PaymasterECDSASigner.sol
+
+
+Use [`ERC4337Utils`](/contracts/5.x/api/account#ERC4337Utils) to facilitate the access to paymaster-related fields of the userOp (e.g. `paymasterData`, `paymasterVerificationGasLimit`)
+
+
+To implement signature-based sponsorship, you’ll first need to deploy the paymaster contract. This contract will hold the ETH used to pay for user operations and verify signatures from your authorized signer. After deployment, you must fund the paymaster with ETH to cover gas costs for the operations it will sponsor:
+
+```typescript
+// Fund the paymaster with ETH
+await eoaClient.sendTransaction(
+ to: paymasterECDSASigner.address,
+ value: parseEther("0.01"),
+ data: encodeFunctionData(
+ abi: paymasterECDSASigner.abi,
+ functionName: "deposit",
+ args: [],
+ ),
+);
+```
+
+
+Paymasters require sufficient ETH balance to pay for gas costs. If the paymaster runs out of funds, all operations it’s meant to sponsor will fail. Consider implementing monitoring and automatic refilling of the paymaster’s balance in production environments.
+
+
+When a user initiates an operation that requires sponsorship, your backend service (or other authorized entity) needs to sign the operation using EIP-712. This signature proves to the paymaster that it should cover the gas costs for this specific user operation:
+
+```typescript
+// Set validation window
+const now = Math.floor(Date.now() / 1000);
+const validAfter = now - 60; // Valid from 1 minute ago
+const validUntil = now + 3600; // Valid for 1 hour
+const paymasterVerificationGasLimit = 100_000n;
+const paymasterPostOpGasLimit = 300_000n;
+
+// Sign using EIP-712 typed data
+const paymasterSignature = await signer.signTypedData(
+ domain:
+ chainId: await signerClient.getChainId(),
+ name: "MyPaymasterECDSASigner",
+ verifyingContract: paymasterECDSASigner.address,
+ version: "1",
+ ,
+ types:
+ UserOperationRequest: [
+ name: "sender", type: "address" ,
+ name: "nonce", type: "uint256" ,
+ name: "initCode", type: "bytes" ,
+ name: "callData", type: "bytes" ,
+ name: "accountGasLimits", type: "bytes32" ,
+ name: "preVerificationGas", type: "uint256" ,
+ name: "gasFees", type: "bytes32" ,
+ name: "paymasterVerificationGasLimit", type: "uint256" ,
+ name: "paymasterPostOpGasLimit", type: "uint256" ,
+ name: "validAfter", type: "uint48" ,
+ name: "validUntil", type: "uint48" ,
+ ],
+ ,
+ primaryType: "UserOperationRequest",
+ message:
+ sender: userOp.sender,
+ nonce: userOp.nonce,
+ initCode: userOp.initCode,
+ callData: userOp.callData,
+ accountGasLimits: userOp.accountGasLimits,
+ preVerificationGas: userOp.preVerificationGas,
+ gasFees: userOp.gasFees,
+ paymasterVerificationGasLimit,
+ paymasterPostOpGasLimit,
+ validAfter,
+ validUntil,
+ ,
+);
+```
+
+The time window (`validAfter` and `validUntil`) prevents replay attacks and allows you to limit how long the signature remains valid. Once signed, the paymaster data needs to be formatted and attached to the user operation:
+
+```typescript
+userOp.paymasterAndData = encodePacked(
+ ["address", "uint128", "uint128", "bytes"],
+ [
+ paymasterECDSASigner.address,
+ paymasterVerificationGasLimit,
+ paymasterPostOpGasLimit,
+ encodePacked(
+ ["uint48", "uint48", "bytes"],
+ [validAfter, validUntil, paymasterSignature]
+ ),
+ ]
+);
+```
+
+
+The `paymasterVerificationGasLimit` and `paymasterPostOpGasLimit` values should be adjusted based on your paymaster’s complexity. Higher values increase the gas cost but provide more execution headroom, reducing the risk of out-of-gas errors during validation or post-operation processing.
+
+
+With the paymaster data attached, the user operation can now be signed by the account signer and submitted to the EntryPoint contract:
+
+```typescript
+// Sign the user operation with the account owner
+const signedUserOp = await signUserOp(entrypoint, userOp);
+
+// Submit to the EntryPoint contract
+const userOpReceipt = await eoaClient.writeContract(
+ abi: EntrypointV08Abi,
+ address: entrypoint.address,
+ functionName: "handleOps",
+ args: [[signedUserOp], beneficiary.address],
+);
+```
+
+Behind the scenes, the EntryPoint will call the paymaster’s `validatePaymasterUserOp` function, which verifies the signature and time window. If valid, the paymaster commits to paying for the operation’s gas costs, and the EntryPoint executes the operation.
+
+## ERC20-based Sponsorship
+
+While signature-based sponsorship is useful for many applications, sometimes you want users to pay for their own transactions but using tokens instead of ETH. The [`PaymasterERC20`](/community-contracts/api/account#PaymasterERC20) allows users to pay for gas fees using ERC-20 tokens. Developers must implement an [`_fetchDetails`](/community-contracts/api/account#PaymasterERC20-_fetchDetails-struct-PackedUserOperation-bytes32-) to get the token price information from an oracle of their preference.
+
+```solidity
+function _fetchDetails(
+ PackedUserOperation calldata userOp,
+ bytes32 userOpHash
+) internal view override returns (uint256 validationData, IERC20 token, uint256 tokenPrice)
+ // Implement logic to fetch the token and token price from the userOp
+
+```
+
+### Using Oracles
+
+#### Chainlink Price Feeds
+
+A popular approach to implement price oracles is to use [Chainlink’s price feeds](https://docs.chain.link/data-feeds/using-data-feeds). By using their [`AggregatorV3Interface`](https://docs.chain.link/data-feeds/api-reference#aggregatorv3interface) developers determine the token-to-ETH exchange rate dynamically for their paymasters. This ensures fair pricing even as market rates fluctuate.
+
+Consider the following contract:
+
+```solidity
+// WARNING: Unaudited code.
+// Consider performing a security review before going to production.
+contract PaymasterUSDCChainlink is PaymasterERC20, Ownable {
+ // Values for sepolia
+ // See https://docs.chain.link/data-feeds/price-feeds/addresses
+ AggregatorV3Interface public constant USDC_USD_ORACLE =
+ AggregatorV3Interface(0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E);
+ AggregatorV3Interface public constant ETH_USD_ORACLE =
+ AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
+
+ // See https://sepolia.etherscan.io/token/0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238
+ IERC20 private constant USDC =
+ IERC20(0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238);
+
+ constructor(address initialOwner) Ownable(initialOwner) {}
+
+ function _authorizeWithdraw() internal virtual override onlyOwner {}
+
+ function liveness() public view virtual returns (uint256) {
+ return 15 minutes; // Tolerate stale data
+ }
+
+ function _fetchDetails(
+ PackedUserOperation calldata userOp,
+ bytes32 /* userOpHash */
+ ) internal view virtual override returns (uint256 validationData, IERC20 token, uint256 tokenPrice) {
+ (uint256 validationData_, uint256 price) = _fetchOracleDetails(userOp);
+ return (
+ validationData_,
+ USDC,
+ price
+ );
+ }
+
+ function _fetchOracleDetails(
+ PackedUserOperation calldata /* userOp */
+ )
+ internal
+ view
+ virtual
+ returns (uint256 validationData, uint256 tokenPrice)
+ {
+ // ...
+ }
+}
+```
+
+
+The `PaymasterUSDCChainlink` contract uses specific Chainlink price feeds (ETH/USD and USDC/USD) on Sepolia. For production use or other networks, you’ll need to modify the contract to use the appropriate price feed addresses.
+
+
+As you can see, a `_fetchOracleDetails` function is specified to fetch the token price that will be used as a reference for calculating the final ERC-20 payment. One can fetch and process price data from Chainlink oracles to determine the exchange rate between the price of a concrete ERC-20 and ETH. An example with USDC would be:
+
+1. Fetch the current `ETH/USD` and `USDC/USD` prices from their respective oracles.
+2. Calculate the `USDC/ETH` exchange rate using the formula: `USDC/ETH = (USDC/USD) / (ETH/USD)`. This gives us how many USDC tokens are needed to buy 1 ETH
+
+
+The price of the ERC-20 must be scaled by [`_tokenPriceDenominator`](/community-contracts/api/account#PaymasterERC20-_tokenPriceDenominator--).
+
+
+Here’s how an implementation of `_fetchOracleDetails` would look like using this approach:
+
+
+Use [`ERC4337Utils.combineValidationData`](/contracts/5.x/api/account#ERC4337Utils-combineValidationData-uint256-uint256-) to merge two `validationData` values.
+
+
+```solidity
+// WARNING: Unaudited code.
+// Consider performing a security review before going to production.
+
+using SafeCast for *;
+using ERC4337Utils for *;
+
+function _fetchOracleDetails(
+ PackedUserOperation calldata /* userOp */
+)
+ internal
+ view
+ virtual
+ returns (uint256 validationData, uint256 tokenPrice)
+{
+ (uint256 ETHUSDValidationData, int256 ETHUSD) = _fetchPrice(
+ ETH_USD_ORACLE
+ );
+ (uint256 USDCUSDValidationData, int256 USDCUSD) = _fetchPrice(
+ USDC_USD_ORACLE
+ );
+
+ if (ETHUSD <= 0 || USDCUSD <= 0) {
+ // No negative prices
+ return (ERC4337Utils.SIG_VALIDATION_FAILED, 0);
+ }
+
+ // eth / usdc = (usdc / usd) / (eth / usd) = usdc * usd / eth * usd = usdc / eth
+ int256 scale = _tokenPriceDenominator().toInt256();
+ int256 scaledUSDCUSD = USDCUSD * scale * (10 ** ETH_USD_ORACLE.decimals()).toInt256();
+ int256 scaledUSDCETH = scaledUSDCUSD / (ETHUSD * (10 ** USDC_USD_ORACLE.decimals()).toInt256());
+
+ return (
+ ETHUSDValidationData.combineValidationData(USDCUSDValidationData),
+ uint256(scaledUSDCETH) // Safe upcast
+ );
+}
+
+function _fetchPrice(
+ AggregatorV3Interface oracle
+) internal view virtual returns (uint256 validationData, int256 price) {
+ (
+ uint80 roundId,
+ int256 price_,
+ ,
+ uint256 timestamp,
+ uint80 answeredInRound
+ ) = oracle.latestRoundData();
+ if (
+ price_ == 0 || // No data
+ answeredInRound < roundId || // Not answered in round
+ timestamp == 0 || // Incomplete round
+ block.timestamp - timestamp > liveness() // Stale data
+ ) {
+ return (ERC4337Utils.SIG_VALIDATION_FAILED, 0);
+ }
+
+ return (ERC4337Utils.SIG_VALIDATION_SUCCESS, price_);
+}
+```
+
+
+An important difference with token-based sponsorship is that the user’s smart account must first approve the paymaster to spend their tokens. You might want to incorporate this approval as part of your account initialization process, or check if approval is needed before executing an operation.
+
+
+The PaymasterERC20 contract follows a pre-charge and refund model:
+
+1. During validation, it pre-charges the maximum possible gas cost
+2. After execution, it refunds any unused gas back to the user
+
+This model ensures the paymaster can always cover gas costs, while only charging users for the actual gas used.
+
+```typescript
+const paymasterVerificationGasLimit = 150_000n;
+const paymasterPostOpGasLimit = 300_000n;
+
+userOp.paymasterAndData = encodePacked(
+ ["address", "uint128", "uint128", "bytes"],
+ [
+ paymasterUSDCChainlink.address,
+ paymasterVerificationGasLimit,
+ paymasterPostOpGasLimit,
+ "0x" // No additional data needed
+ ]
+);
+```
+
+For the rest, you can sign the user operation as you would normally do once the `paymasterAndData` field has been set.
+
+```typescript
+// Sign the user operation with the account owner
+const signedUserOp = await signUserOp(entrypoint, userOp);
+
+// Submit to the EntryPoint contract
+const userOpReceipt = await eoaClient.writeContract(
+ abi: EntrypointV08Abi,
+ address: entrypoint.address,
+ functionName: "handleOps",
+ args: [[signedUserOp], beneficiary.address],
+);
+```
+
+
+Oracle-based pricing relies on the accuracy and freshness of price feeds. The `PaymasterUSDCChainlink` includes safety checks for stale data, but you should still monitor for extreme market volatility that could affect your users.
+
+
+### Using a Guarantor
+
+There are multiple valid cases where the user might not have enough tokens to pay for the transaction before it takes place. For example, if the user is claiming an airdrop, they might need their first transaction to be sponsored. For those cases, the [`PaymasterERC20Guarantor`](/community-contracts/api/account#PaymasterERC20Guarantor) contract extends the standard PaymasterERC20 to allow a third party (guarantor) to back user operations.
+
+The guarantor pre-funds the maximum possible gas cost upfront, and after execution:
+
+1. If the user repays the guarantor, the guarantor gets their funds back
+2. If the user fails to repay, the guarantor absorbs the cost
+
+
+
+A common use case is for guarantors to pay for operations of users claiming airdrops:
+
+* The guarantor pays gas fees upfront
+* The user claims their airdrop tokens
+* The user repays the guarantor from the claimed tokens
+* If the user fails to repay, the guarantor absorbs the cost
+
+
+To implement guarantor functionality, your paymaster needs to extend the PaymasterERC20Guarantor class and implement the `_fetchGuarantor` function:
+
+```solidity
+function _fetchGuarantor(
+ PackedUserOperation calldata userOp
+) internal view override returns (address guarantor){
+ // Implement logic to fetch and validate the guarantor from userOp
+}
+```
+
+Let’s create a guarantor-enabled paymaster by extending our previous example:
+
+```solidity
+contract PaymasterUSDCGuaranteed is EIP712, PaymasterERC20Guarantor, Ownable {
+
+ // Keep the same oracle code as before...
+
+ bytes32 private constant GUARANTEED_USER_OPERATION_TYPEHASH =
+ keccak256(
+ "GuaranteedUserOperation(address sender,uint256 nonce,bytes initCode,bytes callData,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterData)"
+ );
+
+ constructor(
+ address initialOwner
+ ) EIP712("PaymasterUSDCGuaranteed", "1") Ownable(initialOwner) {}
+
+ // Other functions from PaymasterUSDCChainlink...
+
+ function _fetchGuarantor(
+ PackedUserOperation calldata userOp
+ ) internal view override returns (address guarantor) {
+ bytes calldata paymasterData = userOp.paymasterData();
+
+ // Check guarantor data (should be at least 22 bytes: 20 for address + 2 for sig length)
+ // If no guarantor specified, return early
+ if (paymasterData.length < 22 || guarantor == address(0)) {
+ return address(0);
+ }
+
+ guarantor = address(bytes20(paymasterData[:20]));
+ uint16 guarantorSigLength = uint16(bytes2(paymasterData[20:22]));
+
+ // Ensure the signature fits in the data
+ if (paymasterData.length < 22 + guarantorSigLength) {
+ return address(0);
+ }
+
+ bytes calldata guarantorSignature = paymasterData[22:22 + guarantorSigLength];
+
+ // Validate the guarantor's signature
+ bytes32 structHash = _getGuaranteedOperationStructHash(userOp);
+ bytes32 hash = _hashTypedDataV4(structHash);
+
+ return SignatureChecker.isValidSignatureNow(
+ guarantor,
+ hash,
+ guarantorSignature
+ ) ? guarantor : address(0);
+ }
+
+ function _getGuaranteedOperationStructHash(
+ PackedUserOperation calldata userOp
+ ) internal pure returns (bytes32) {
+ return keccak256(
+ abi.encode(
+ GUARANTEED_USER_OPERATION_TYPEHASH,
+ userOp.sender,
+ userOp.nonce,
+ keccak256(userOp.initCode),
+ keccak256(userOp.callData),
+ userOp.accountGasLimits,
+ userOp.preVerificationGas,
+ userOp.gasFees,
+ keccak256(bytes(userOp.paymasterData()[:20])) // Just the guarantor address part
+ )
+ );
+ }
+}
+```
+
+With this implementation, a guarantor would sign a user operation to authorize backing it:
+
+```typescript
+// Sign the user operation with the guarantor
+const guarantorSignature = await guarantor.signTypedData(
+ domain:
+ chainId: await guarantorClient.getChainId(),
+ name: "PaymasterUSDCGuaranteed",
+ verifyingContract: paymasterUSDC.address,
+ version: "1",
+ ,
+ types:
+ GuaranteedUserOperation: [
+ name: "sender", type: "address" ,
+ name: "nonce", type: "uint256" ,
+ name: "initCode", type: "bytes" ,
+ name: "callData", type: "bytes" ,
+ name: "accountGasLimits", type: "bytes32" ,
+ name: "preVerificationGas", type: "uint256" ,
+ name: "gasFees", type: "bytes32" ,
+ name: "paymasterData", type: "bytes"
+ ]
+ ,
+ primaryType: "GuaranteedUserOperation",
+ message:
+ sender: userOp.sender,
+ nonce: userOp.nonce,
+ initCode: userOp.initCode,
+ callData: userOp.callData,
+ accountGasLimits: userOp.accountGasLimits,
+ preVerificationGas: userOp.preVerificationGas,
+ gasFees: userOp.gasFees,
+ paymasterData: guarantorAddress // Just the guarantor address
+ ,
+);
+```
+
+Then, we include the guarantor’s address and its signature in the paymaster data:
+
+```typescript
+const paymasterVerificationGasLimit = 150_000n;
+const paymasterPostOpGasLimit = 300_000n;
+
+userOp.paymasterAndData = encodePacked(
+ ["address", "uint128", "uint128", "bytes"],
+ [
+ paymasterUSDC.address,
+ paymasterVerificationGasLimit,
+ paymasterPostOpGasLimit,
+ encodePacked(
+ ["address", "bytes2", "bytes"],
+ [
+ guarantorAddress,
+ toHex(guarantorSignature.replace("0x", "").length / 2, size: 2 ),
+ guarantorSignature
+ ]
+ )
+ ]
+);
+```
+
+When the operation executes:
+
+1. During validation, the paymaster verifies the guarantor’s signature and pre-funds from the guarantor’s account
+2. The user operation executes, potentially giving the user tokens (like in an airdrop claim)
+3. During post-operation, the paymaster first tries to get repayment from the user
+4. If the user can’t pay, the guarantor’s pre-funded amount is used
+5. An event is emitted indicating who ultimately paid for the operation
+
+This approach enables novel use cases where users don’t need tokens to start using a web3 app, and can cover costs after receiving value through their transaction.
+
+## Practical Considerations
+
+When implementing paymasters in production environments, keep these considerations in mind:
+
+1. ***Balance management***: Regularly monitor and replenish your paymaster’s ETH balance to ensure uninterrupted service.
+2. ***Gas limits***: The verification and post-operation gas limits should be set carefully. Too low, and operations might fail; too high, and you waste resources.
+3. ***Security***: For signature-based paymasters, protect your signing key as it controls who gets subsidized operations.
+4. ***Price volatility***: For token-based paymasters, consider restricting which tokens are accepted, and implementing circuit breakers for extreme market conditions.
+5. ***Spending limits***: Consider implementing daily or per-user limits to prevent abuse of your paymaster.
+
+
+For production deployments, it’s often useful to implement a monitoring service that tracks paymaster usage, balances, and other metrics to ensure smooth operation.
+
diff --git a/docs/content/community-contracts/utilities.mdx b/docs/content/community-contracts/utilities.mdx
new file mode 100644
index 00000000..6e53b8ee
--- /dev/null
+++ b/docs/content/community-contracts/utilities.mdx
@@ -0,0 +1,56 @@
+---
+title: Utilities
+---
+
+Multiple libraries and general purpose utilities included in the community version of OpenZeppelin Contracts. These are only a set of utility contracts. For the full list, check out the [API Reference](/community-contracts/api/utils).
+
+## Cryptography
+
+### Validating Typed Data Signatures
+
+_For prior knowledge on how to validate signatures on-chain, check out the [OpenZeppelin Contracts documentation](/contracts/5.x/utilities#checking-signatures-on-chain)_
+
+As opposed to validating plain-text messages, it is possible to let your users sign structured data (i.e. typed values) in a way that is still readable on their wallets. This is possible by implementing [`EIP712`](/contracts/5.x/api/utils/cryptography#EIP712), a standard way to encode structured data into a typed data hash.
+
+To start validating signed typed structures, just validate the [typed data hash](/contracts/5.x/api/utils/cryptography#EIP712-_hashTypedDataV4-bytes32-):
+
+./examples/utils/cryptography/MyContractDomain.sol
+
+As part of the message, EIP-712 requires implementers to include a domain separator, which is a hash that includes the current smart contract address and the chain id where it’s deployed. This way, the smart contract can be sure that the structured message was signed for its specific domain, avoiding replayability of signatures in smart contracts.
+
+#### Validating Nested EIP-712 Signatures
+
+Accounts (i.e. Smart Contract Wallets or Smart Accounts) are particularly likely to be controlled by multiple signers. As such, it’s important to make sure that signatures are:
+
+1. Only valid for the intended domain and account.
+2. Validated in a way that’s readable for the end signer.
+
+On one hand, making sure that the Account signature is only valid for an specific smart contract (i.e. an application) is difficult since it requires to validate a signature whose domain is the application but also the Account itself. For these reason, the community developed [ERC-7739](https://eips.ethereum.org/EIPS/eip-7739); a defensive rehashing mechanism that binds a signature to a single domain using a nested EIP-712 approach (i.e. an EIP-712 typed structure wrapping another).
+
+In case your smart contract validates signatures, using [`ERC7739`](/contracts/5.x/api/utils/cryptography#ERC7739) signer will implement the [`IERC1271`](/contracts/5.x/api/interfaces#IERC1271) interface for validating smart contract signatures following the approach suggested by ERC-7739:
+
+./examples/utils/cryptography/ERC7739SignerECDSA.sol
+
+### ERC-7913 Signature Verifiers
+
+ERC-7913 extends the concept of signature verification to support keys that don’t have their own Ethereum address. This is particularly useful for integrating non-Ethereum cryptographic curves, hardware devices, or other identity systems into smart accounts.
+
+The standard defines a verifier interface that can be implemented to support different types of keys. A signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`.
+
+[`ERC7913Utils`](/community-contracts/api/utils/cryptography#ERC7913Utils) provides functions for verifying signatures using ERC-7913 compatible verifiers:
+
+```solidity
+using ERC7913Utils for bytes;
+
+function _verify(bytes memory signer, bytes32 hash, bytes memory signature) internal view returns (bool){
+ return signer.isValidSignatureNow(hash, signature);
+}
+```
+
+The verification process works as follows:
+
+* If `signer.length < 20`: verification fails
+* If `signer.length == 20`: verification is done using [SignatureChecker](/contracts/5.x/api/utils#SignatureChecker)
+* Otherwise: verification is done using an ERC-7913 verifier.
+
+This allows for backward compatibility with EOAs and ERC-1271 contracts while supporting new types of keys.
diff --git a/docs/content/confidential-contracts/api/finance.mdx b/docs/content/confidential-contracts/api/finance.mdx
new file mode 100644
index 00000000..faa9990d
--- /dev/null
+++ b/docs/content/confidential-contracts/api/finance.mdx
@@ -0,0 +1,838 @@
+---
+title: "Finance"
+description: "Smart contract finance utilities and implementations"
+---
+
+This directory includes primitives for on-chain confidential financial systems:
+
+* [`VestingWalletConfidential`](#VestingWalletConfidential): Handles the vesting of confidential tokens for a given beneficiary. Custody of multiple tokens can be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting schedule.
+* [`VestingWalletCliffConfidential`](#VestingWalletCliffConfidential): Variant of [`VestingWalletConfidential`](#VestingWalletConfidential) which adds a cliff period to the vesting schedule.
+
+For convenience, this directory also includes:
+
+* [`VestingWalletConfidentialFactory`](#VestingWalletConfidentialFactory): A factory which enables batch funding of vesting wallets.
+
+## Contracts
+[`VestingWalletConfidential`](#VestingWalletConfidential)
+[`VestingWalletCliffConfidential`](#VestingWalletCliffConfidential)
+[`VestingWalletConfidentialFactory`](#VestingWalletConfidentialFactory)
+
+
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/finance/ERC7821WithExecutor.sol";
+```
+
+Extension of `ERC7821` that adds an [`ERC7821WithExecutor.executor`](#ERC7821WithExecutor-executor--) address that is able to execute arbitrary calls via `ERC7821.execute`.
+
+
+
+Access control mechanism for the `execute` function.
+By default, only the contract itself is allowed to execute.
+
+Override this function to implement custom access control, for example to allow the
+ERC-4337 entrypoint to execute.
+
+```solidity
+function _erc7821AuthorizedExecutor(
+ address caller,
+ bytes32 mode,
+ bytes calldata executionData
+) internal view virtual override returns (bool) {
+ return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData);
+}
+```
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/finance/VestingWalletCliffConfidential.sol";
+```
+
+An extension of [`VestingWalletConfidential`](#VestingWalletConfidential) that adds a cliff to the vesting schedule. The cliff is `cliffSeconds` long and
+starts at the vesting start timestamp (see [`VestingWalletConfidential`](#VestingWalletConfidential)).
+
+
+
+Set the duration of the cliff, in seconds. The cliff starts at the vesting
+start timestamp (see [`VestingWalletConfidential.start`](#VestingWalletConfidential-start--)) and ends `cliffSeconds` later.
+
+
+
+This function returns the amount vested, as a function of time, for
+an asset given its total historical allocation. Returns 0 if the [`VestingWalletCliffConfidential.cliff`](#VestingWalletCliffConfidential-cliff--) timestamp is not met.
+
+
+The cliff not only makes the schedule return 0, but it also ignores every possible side
+effect from calling the inherited implementation (i.e. `super._vestingSchedule`). Carefully consider
+this caveat if the overridden implementation of this function has any (e.g. writing to memory or reverting).
+
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/finance/VestingWalletConfidential.sol";
+```
+
+A vesting wallet is an ownable contract that can receive ConfidentialFungibleTokens, and release these
+assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule.
+
+Any assets transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
+Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
+be immediately releasable.
+
+By setting the duration to 0, one can configure this contract to behave like an asset timelock that holds tokens for
+a beneficiary until a specified time.
+
+
+Since the wallet is `Ownable`, and ownership can be transferred, it is possible to sell unvested tokens.
+
+
+
+When using this contract with any token whose balance is adjusted automatically (i.e. a rebase token), make
+sure to account the supply/balance adjustment in the vesting schedule to ensure the vested amount is as intended.
+
+
+Confidential vesting wallet contracts can be deployed (as clones) using the [`VestingWalletConfidentialFactory`](#VestingWalletConfidentialFactory).
+
+
+
+Getter for the amount of releasable `token` tokens. `token` should be the address of an
+[`IConfidentialFungibleToken`](./interfaces#IConfidentialFungibleToken) contract.
+
+
+
+Release the tokens that have already vested.
+
+Emits a [`VestingWalletConfidential.VestingWalletConfidentialTokenReleased`](#VestingWalletConfidential-VestingWalletConfidentialTokenReleased-address-euint64-) event.
+
+
+
+Initializes the vesting wallet for a given `beneficiary` with a start time of `startTimestamp`
+and an end time of `startTimestamp + durationSeconds`.
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/finance/VestingWalletConfidentialFactory.sol";
+```
+
+A factory which enables batch funding of vesting wallets.
+
+The [`VestingWalletConfidentialFactory._deployVestingWalletImplementation`](#VestingWalletConfidentialFactory-_deployVestingWalletImplementation--), [`VestingWalletConfidentialFactory._initializeVestingWallet`](#VestingWalletConfidentialFactory-_initializeVestingWallet-address-bytes-), and [`VestingWalletConfidentialFactory._validateVestingWalletInitArgs`](#VestingWalletConfidentialFactory-_validateVestingWalletInitArgs-bytes-)
+functions remain unimplemented to allow for custom implementations of the vesting wallet to be used.
+
+
+
+Batches the funding of multiple confidential vesting wallets.
+
+Funds are sent to deterministic wallet addresses. Wallets can be created either
+before or after this operation.
+
+Emits a [`VestingWalletConfidentialFactory.VestingWalletConfidentialFunded`](#VestingWalletConfidentialFactory-VestingWalletConfidentialFunded-address-address-euint64-bytes-) event for each funded vesting plan.
+
+
+
+Internal function that is called once to deploy the vesting wallet implementation.
+
+Vesting wallet clones will be initialized by calls to the [`VestingWalletConfidentialFactory._initializeVestingWallet`](#VestingWalletConfidentialFactory-_initializeVestingWallet-address-bytes-) function.
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/governance/utils/VotesConfidential.sol";
+```
+
+A confidential votes contract tracking confidential voting power of accounts over time.
+It features vote delegation to delegators.
+
+This contract keeps a history (checkpoints) of each account's confidential vote power. Confidential
+voting power can be delegated either by calling the [`VotesConfidential.delegate`](#VotesConfidential-delegate-address-) function directly, or by providing
+a signature to be used with [`VotesConfidential.delegateBySig`](#VotesConfidential-delegateBySig-address-uint256-uint256-uint8-bytes32-bytes32-). Confidential voting power handles can be queried
+through the public accessors [`VotesConfidential.getVotes`](#VotesConfidential-getVotes-address-) and [`VotesConfidential.getPastVotes`](#VotesConfidential-getPastVotes-address-uint256-) but can only be decrypted by accounts
+allowed to access them. Ensure that [`HandleAccessManager._validateHandleAllowance`](./utils#HandleAccessManager-_validateHandleAllowance-bytes32-) is implemented properly, allowing all
+necessary addresses to access voting power handles.
+
+By default, voting units does not account for voting power. This makes transfers of underlying
+voting units cheaper. The downside is that it requires users to delegate to themselves in order
+to activate checkpoints and have their voting power tracked.
+
+
+
+Clock used for flagging checkpoints. Can be overridden to implement timestamp based
+checkpoints (and voting), in which case [`VotesConfidential.CLOCK_MODE`](#VotesConfidential-CLOCK_MODE--) should be overridden as well to match.
+
+
+
+Returns the amount of votes that `account` had at a specific moment in the past. If the [`VotesConfidential.clock`](#VotesConfidential-clock--) is
+configured to use block numbers, this will return the value at the end of the corresponding block.
+
+Requirements:
+
+- `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
+
+
+
+Returns the total supply of votes available at a specific moment in the past. If the [`VotesConfidential.clock`](#VotesConfidential-clock--) is
+configured to use block numbers, this will return the value at the end of the corresponding block.
+
+
+This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
+Votes that have not been delegated are still part of total supply, even though they would not participate in a
+vote.
+
+
+Requirements:
+
+- `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
+
+
+
+Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`
+should be zero. Total supply of voting units will be adjusted with mints and burns.
+
+
+Must be called after [`VotesConfidential.confidentialTotalSupply`](#VotesConfidential-confidentialTotalSupply--) is updated.
+
+
+
+
+
+
+
+
+
+
_moveDelegateVotes(address from, address to, euint64 amount)
+
+Sets `operator` as an operator for `holder` until the timestamp `until`.
+
+
+An operator may transfer any amount of tokens on behalf of a holder while approved.
+
+
+
+
+
+
+
+
+
+
confidentialTransfer(address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64
+
+Transfers the encrypted amount `encryptedAmount` to `to` with the given input proof `inputProof`.
+
+Returns the encrypted amount that was actually transferred.
+
+
+
+
+
+
+
+
+
confidentialTransfer(address to, euint64 amount) → euint64 transferred
+
+Similar to #IConfidentialFungibleToken-confidentialTransfer-address-externalEuint64-bytes- but without an input proof. The caller
+*must* already be allowed by ACL for the given `amount`.
+
+
+
+
+
+
+
+
+
confidentialTransferFrom(address from, address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64
+
+Transfers the encrypted amount `encryptedAmount` from `from` to `to` with the given input proof
+`inputProof`. `msg.sender` must be either `from` or an operator for `from`.
+
+Returns the encrypted amount that was actually transferred.
+
+
+
+
+
+
+
+
+
confidentialTransferFrom(address from, address to, euint64 amount) → euint64 transferred
+
+Similar to #IConfidentialFungibleToken-confidentialTransferFrom-address-address-externalEuint64-bytes- but without an input proof.
+The caller *must* be already allowed by ACL for the given `amount`.
+
+
+
+Similar to #IConfidentialFungibleToken-confidentialTransfer-address-externalEuint64-bytes- but with a callback to `to` after
+the transfer.
+
+The callback is made to the [`IConfidentialFungibleTokenReceiver.onConfidentialTransferReceived`](#IConfidentialFungibleTokenReceiver-onConfidentialTransferReceived-address-address-euint64-bytes-) function on the
+to address with the actual transferred amount (may differ from the given `encryptedAmount`) and the given
+data `data`.
+
+
+
+
+
+
+
+
+
confidentialTransferAndCall(address to, euint64 amount, bytes data) → euint64 transferred
+
+Similar to #IConfidentialFungibleToken-confidentialTransferFrom-address-address-externalEuint64-bytes- but with a callback to `to`
+after the transfer.
+
+
+
+Emitted when the expiration timestamp for an operator `operator` is updated for a given `holder`.
+The operator may move any amount of tokens on behalf of the holder until the timestamp `until`.
+
+
+
+
+
+
+
+
ConfidentialTransfer(address indexed from, address indexed to, euint64 indexed amount)
+
+Emitted when an encrypted amount is disclosed.
+
+Accounts with access to the encrypted amount `encryptedAmount` that is also accessible to this contract
+should be able to disclose the amount. This functionality is implementation specific.
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/interfaces/IConfidentialFungibleTokenReceiver.sol";
+```
+
+Interface for contracts that can receive confidential token transfers with a callback.
+
+
+
+Called upon receiving a confidential token transfer. Returns an encrypted boolean indicating success
+of the callback. If false is returned, the transfer must be reversed.
+
+
+
diff --git a/docs/content/confidential-contracts/api/token.mdx b/docs/content/confidential-contracts/api/token.mdx
new file mode 100644
index 00000000..d747f38f
--- /dev/null
+++ b/docs/content/confidential-contracts/api/token.mdx
@@ -0,0 +1,1200 @@
+---
+title: "Token"
+description: "Smart contract token utilities and implementations"
+---
+
+This set of interfaces, contracts, and utilities are all related to the evolving Confidential Token Standard. The standard utilizes the Zama fhEVM co-processor for manipulating FHE values. All amounts are stored on-chain as ciphertext handles (or pointers) to values stored on the co-processor.
+
+* [`ConfidentialFungibleToken`](#ConfidentialFungibleToken): Implementation of [`IConfidentialFungibleToken`](./interfaces#IConfidentialFungibleToken).
+* [`ConfidentialFungibleTokenERC20Wrapper`](#ConfidentialFungibleTokenERC20Wrapper): Extension of [`ConfidentialFungibleToken`](#ConfidentialFungibleToken) which wraps an `ERC20` into a confidential token. The wrapper allows for free conversion in both directions at a fixed rate.
+* [`ConfidentialFungibleTokenUtils`](#ConfidentialFungibleTokenUtils): A library that provides the on-transfer callback check used by [`ConfidentialFungibleToken`](#ConfidentialFungibleToken).
+
+## Core
+[`ConfidentialFungibleToken`](#ConfidentialFungibleToken)
+
+## Extensions
+[`ConfidentialFungibleTokenERC20Wrapper`](#ConfidentialFungibleTokenERC20Wrapper)
+
+## Utilities
+[`ConfidentialFungibleTokenUtils`](#ConfidentialFungibleTokenUtils)
+
+
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/token/ConfidentialFungibleToken.sol";
+```
+
+Reference implementation for [`IConfidentialFungibleToken`](./interfaces#IConfidentialFungibleToken).
+
+This contract implements a fungible token where balances and transfers are encrypted using the Zama fhEVM,
+providing confidentiality to users. Token amounts are stored as encrypted, unsigned integers (`euint64`)
+that can only be decrypted by authorized parties.
+
+Key features:
+
+- All balances are encrypted
+- Transfers happen without revealing amounts
+- Support for operators (delegated transfer capabilities with time bounds)
+- Transfer and call pattern
+- Safe overflow/underflow handling for FHE operations
+
+
+
+Sets `operator` as an operator for `holder` until the timestamp `until`.
+
+
+An operator may transfer any amount of tokens on behalf of a holder while approved.
+
+
+
+
+
+
+
+
+
+
confidentialTransfer(address to, externalEuint64 encryptedAmount, bytes inputProof) → euint64
+
+Transfers the encrypted amount `encryptedAmount` to `to` with the given input proof `inputProof`.
+
+Returns the encrypted amount that was actually transferred.
+
+
+
+
+
+
+
+
+
confidentialTransfer(address to, euint64 amount) → euint64
+
+Similar to interfaces#IConfidentialFungibleToken-confidentialTransfer-address-externalEuint64-bytes- but without an input proof. The caller
+*must* already be allowed by ACL for the given `amount`.
+
+
+
+Transfers the encrypted amount `encryptedAmount` from `from` to `to` with the given input proof
+`inputProof`. `msg.sender` must be either `from` or an operator for `from`.
+
+Returns the encrypted amount that was actually transferred.
+
+
+
+
+
+
+
+
+
confidentialTransferFrom(address from, address to, euint64 amount) → euint64 transferred
+
+Similar to interfaces#IConfidentialFungibleToken-confidentialTransferFrom-address-address-externalEuint64-bytes- but without an input proof.
+The caller *must* be already allowed by ACL for the given `amount`.
+
+
+
+Similar to interfaces#IConfidentialFungibleToken-confidentialTransfer-address-externalEuint64-bytes- but with a callback to `to` after
+the transfer.
+
+The callback is made to the [`IConfidentialFungibleTokenReceiver.onConfidentialTransferReceived`](./interfaces#IConfidentialFungibleTokenReceiver-onConfidentialTransferReceived-address-address-euint64-bytes-) function on the
+to address with the actual transferred amount (may differ from the given `encryptedAmount`) and the given
+data `data`.
+
+
+
+
+
+
+
+
+
confidentialTransferAndCall(address to, euint64 amount, bytes data) → euint64 transferred
+
+Similar to interfaces#IConfidentialFungibleToken-confidentialTransferFrom-address-address-externalEuint64-bytes- but with a callback to `to`
+after the transfer.
+
+
+
+Similar to interfaces#IConfidentialFungibleToken-confidentialTransferFrom-address-address-euint64- but with a callback to `to`
+after the transfer.
+
+
+
+Discloses an encrypted amount `encryptedAmount` publicly via an [`IConfidentialFungibleToken.AmountDisclosed`](./interfaces#IConfidentialFungibleToken-AmountDisclosed-euint64-uint64-)
+event. The caller and this contract must be authorized to use the encrypted amount on the ACL.
+
+
+This is an asynchronous operation where the actual decryption happens off-chain and
+[`ConfidentialFungibleToken.finalizeDiscloseEncryptedAmount`](#ConfidentialFungibleToken-finalizeDiscloseEncryptedAmount-uint256-uint64-bytes---) is called with the result.
+
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/token/extensions/ConfidentialFungibleTokenERC20Wrapper.sol";
+```
+
+A wrapper contract built on top of [`ConfidentialFungibleToken`](#ConfidentialFungibleToken) that allows wrapping an `ERC20` token
+into a confidential fungible token. The wrapper contract implements the `IERC1363Receiver` interface
+which allows users to transfer `ERC1363` tokens directly to the wrapper with a callback to wrap the tokens.
+
+
+Minting assumes the full amount of the underlying token transfer has been received, hence some non-standard
+tokens such as fee-on-transfer or other deflationary-type tokens are not supported by this wrapper.
+
+
+
+
+Returns the rate at which the underlying token is converted to the wrapped token.
+For example, if the `rate` is 1000, then 1000 units of the underlying token equal 1 unit of the wrapped token.
+
+
+
+`ERC1363` callback function which wraps tokens to the address specified in `data` or
+the address `from` (if no address is specified in `data`). This function refunds any excess tokens
+sent beyond the nearest multiple of [`ConfidentialFungibleTokenERC20Wrapper.rate`](#ConfidentialFungibleTokenERC20Wrapper-rate--). See [`ConfidentialFungibleTokenERC20Wrapper.wrap`](#ConfidentialFungibleTokenERC20Wrapper-wrap-address-uint256-) from more details on wrapping tokens.
+
+
+
+Wraps amount `amount` of the underlying token into a confidential token and sends it to
+`to`. Tokens are exchanged at a fixed rate specified by [`ConfidentialFungibleTokenERC20Wrapper.rate`](#ConfidentialFungibleTokenERC20Wrapper-rate--) such that `amount / rate()` confidential
+tokens are sent. Amount transferred in is rounded down to the nearest multiple of [`ConfidentialFungibleTokenERC20Wrapper.rate`](#ConfidentialFungibleTokenERC20Wrapper-rate--).
+
+
+
+Unwraps tokens from `from` and sends the underlying tokens to `to`. The caller must be `from`
+or be an approved operator for `from`. `amount * rate()` underlying tokens are sent to `to`.
+
+
+This is an asynchronous function and waits for decryption to be completed off-chain before disbursing
+tokens.
+
+
+The caller *must* already be approved by ACL for the given `amount`.
+
+
+
+
+
+
+
+
+
+
unwrap(address from, address to, externalEuint64 encryptedAmount, bytes inputProof)
+
+Variant of [`ConfidentialFungibleTokenERC20Wrapper.unwrap`](#ConfidentialFungibleTokenERC20Wrapper-unwrap-address-address-externalEuint64-bytes-) that passes an `inputProof` which approves the caller for the `encryptedAmount`
+in the ACL.
+
+
+
+Returns the default number of decimals of the underlying ERC-20 token that is being wrapped.
+Used as a default fallback when [`ConfidentialFungibleTokenERC20Wrapper._tryGetAssetDecimals`](#ConfidentialFungibleTokenERC20Wrapper-_tryGetAssetDecimals-contract-IERC20-) fails to fetch decimals of the underlying
+ERC-20 token.
+
+
+
+Returns the maximum number that will be used for [`IConfidentialFungibleToken.decimals`](./interfaces#IConfidentialFungibleToken-decimals--) by the wrapper.
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/token/extensions/ConfidentialFungibleTokenVotes.sol";
+```
+
+Extension of [`ConfidentialFungibleToken`](#ConfidentialFungibleToken) supporting confidential votes tracking and delegation.
+
+The amount of confidential voting units an account has is equal to the confidential token balance of
+that account. Voing power is taken into account when an account delegates votes to itself or to another
+account.
+
+
+
+Performs a transfer callback to the recipient of the transfer `to`. Should be invoked
+after all transfers "withCallback" on a [`ConfidentialFungibleToken`](#ConfidentialFungibleToken).
+
+The transfer callback is not invoked on the recipient if the recipient has no code (i.e. is an EOA). If the
+recipient has non-zero code, it must implement
+[`IConfidentialFungibleTokenReceiver.onConfidentialTransferReceived`](./interfaces#IConfidentialFungibleTokenReceiver-onConfidentialTransferReceived-address-address-euint64-bytes-) and return an `ebool` indicating
+whether the transfer was accepted or not. If the `ebool` is `false`, the transfer will be reversed.
+
+
+
diff --git a/docs/content/confidential-contracts/api/utils.mdx b/docs/content/confidential-contracts/api/utils.mdx
new file mode 100644
index 00000000..600364e3
--- /dev/null
+++ b/docs/content/confidential-contracts/api/utils.mdx
@@ -0,0 +1,1191 @@
+---
+title: "Utils"
+description: "Smart contract utils utilities and implementations"
+---
+
+Miscellaneous contracts and libraries containing utility functions you can use to improve security, and ease integrations when working with confidential contracts.
+
+* [`FHESafeMath`](#FHESafeMath): Implementation of safe math operations for encrypted values.
+* [`CheckpointsConfidential`](#CheckpointsConfidential): Implementation of checkpoints for encrypted values.
+* [`HandleAccessManager`](#HandleAccessManager): Minimal contract that adds a function to give allowance to callers for a given ciphertext handle.
+
+## Math
+
+[`FHESafeMath`](#FHESafeMath)
+
+## Structs
+
+[`CheckpointsConfidential`](#CheckpointsConfidential)
+
+## Other
+[`HandleAccessManager`](#HandleAccessManager)
+
+
+
+
+
+Try to increase the encrypted value `oldValue` by `delta`. If the operation is successful,
+`success` will be true and `updated` will be the new value. Otherwise, `success` will be false
+and `updated` will be the original value.
+
+
+
+Try to decrease the encrypted value `oldValue` by `delta`. If the operation is successful,
+`success` will be true and `updated` will be the new value. Otherwise, `success` will be false
+and `updated` will be the original value.
+
+
+
+Get handle access for the given handle `handle`. Access will be given to the
+account `account` with the given persistence flag.
+
+
+This function call is gated by `msg.sender` and validated by the
+[`HandleAccessManager._validateHandleAllowance`](#HandleAccessManager-_validateHandleAllowance-bytes32-) function.
+
+
+
+
+Unimplemented function that must revert if the message sender is not allowed to call
+[`HandleAccessManager.getHandleAllowance`](#HandleAccessManager-getHandleAllowance-bytes32-address-bool-) for the given handle.
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/utils/structs/CheckpointsConfidential.sol";
+```
+
+This library defines the `Trace*` struct, for checkpointing values as they change at different points in
+time, and later looking up past values by block number.
+
+To create a history of checkpoints, define a variable type `CheckpointsConfidential.Trace*` in your contract, and store a new
+checkpoint for the current transaction block using the [`CheckpointsConfidential.push`](#CheckpointsConfidential-push-struct-CheckpointsConfidential-TraceEuint64-uint256-euint64-) function.
+
+
+
+Pushes a (`key`, `value`) pair into a TraceEuint32 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint256).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+Pushes a (`key`, `value`) pair into a TraceEuint64 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint256).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+```solidity
+import "@openzeppelin/confidential-contracts/utils/structs/temporary-Checkpoints.sol";
+```
+
+This library defines the `Trace*` struct, for checkpointing values as they change at different points in
+time, and later looking up past values by block number. See [`VotesConfidential`](./governance#VotesConfidential) as an example.
+
+To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
+checkpoint for the current transaction block using the [`CheckpointsConfidential.push`](#CheckpointsConfidential-push-struct-CheckpointsConfidential-TraceEuint64-uint256-euint64-) function.
+
+
+
+Pushes a (`key`, `value`) pair into a Trace256 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint256).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
+
+Returns previous value and new value.
+
+
+Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
+library.
+
+
+
+
+Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
+if there is none.
+
+
+This is a variant of [`CheckpointsConfidential.upperLookup`](#CheckpointsConfidential-upperLookup-struct-CheckpointsConfidential-TraceEuint64-uint256-) that is optimized to find "recent" checkpoint (checkpoints with high
+keys).
+
+
+
+
+A value was attempted to be inserted on a past checkpoint.
+
+
+
diff --git a/docs/content/confidential-contracts/changelog.mdx b/docs/content/confidential-contracts/changelog.mdx
new file mode 100644
index 00000000..5a14e01f
--- /dev/null
+++ b/docs/content/confidential-contracts/changelog.mdx
@@ -0,0 +1,47 @@
+---
+title: Changelog
+---
+
+
+# [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/releases/tag/v0.2.0) - 2025-08-15
+
+- Upgrade all contracts to use `@fhevm/solidity` 0.7.0. ([#27](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/27))
+
+### Token
+- `IConfidentialFungibleToken`: Prefix `totalSupply` and `balanceOf` functions with confidential. ([#93](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/93))
+- `IConfidentialFungibleToken`: Rename `EncryptedAmountDisclosed` event to `AmountDisclosed`. ([#93](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/93))
+- `ConfidentialFungibleToken`: Change the default decimals from 9 to 6. ([#74](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/74))
+- `ConfidentialFungibleTokenERC20Wrapper`: Add an internal function to allow overriding the max decimals used for wrapped tokens. ([#89](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/89))
+- `ConfidentialFungibleTokenERC20Wrapper`: Add an internal function to allow overriding the underlying decimals fallback value. ([#133](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/133))
+
+### Governance
+- `VotesConfidential`: Add votes governance utility for keeping track of FHE vote delegations. ([#40](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/40))
+- `ConfidentialFungibleTokenVotes`: Add an extension of `ConfidentialFungibleToken` that implements `VotesConfidential`. ([#40](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/40))
+
+### Finance
+- `VestingWalletConfidential`: A vesting wallet that releases confidential tokens owned by it according to a defined vesting schedule. ([#91](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/91))
+- `VestingWalletCliffConfidential`: A variant of `VestingWalletConfidential` which adds a cliff period to the vesting schedule. ([#91](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/91))
+- `VestingWalletConfidentialFactory`: A generalized factory that allows for batch funding of confidential vesting wallets. ([#102](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/102))
+
+### Misc
+- `HandleAccessManager`: Minimal contract that adds a function to give allowance to callers for a given ciphertext handle. ([#143](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/143))
+- `ERC7821WithExecutor`: Add an abstract contract that inherits from `ERC7821` and adds an `executor` role. ([#102](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/102))
+- `CheckpointsConfidential`: Add a library for handling checkpoints with confidential value types. ([#60](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/60))
+- `TFHESafeMath`: Renamed to `FHESafeMath`. ([#137](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/pull/137))
+
+
+[Changes][v0.2.0]
+
+
+
+# [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/releases/tag/v0.1.0) - 2025-06-05
+
+Initial release of the OpenZeppelin Confidential Contracts.
+
+Note: Confidential contracts are currently in a phase of rapid development--future releases of the major version 0 may not be backwards compatible.
+
+[Changes][v0.1.0]
+
+
+[v0.2.0]: https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/compare/v0.1.0...v0.2.0
+[v0.1.0]: https://github.com/OpenZeppelin/openzeppelin-confidential-contracts/tree/v0.1.0
diff --git a/docs/content/confidential-contracts/index.mdx b/docs/content/confidential-contracts/index.mdx
new file mode 100644
index 00000000..c70adf4c
--- /dev/null
+++ b/docs/content/confidential-contracts/index.mdx
@@ -0,0 +1,17 @@
+---
+title: Confidential Contracts
+---
+
+A library of smart contracts that use ciphertext for amount, allowing for a wide variety of confidential use-cases, such as confidential tokens, auctions, vesting, voting etc. While the contracts are not written in an opinionated method (other than using the standard encrypted values published by Zama), for testing and examples in the documentation, the [Zama fhEVM](https://github.com/zama-ai/fhevm-solidity) will be used to operate on and decrypt [FHE](https://www.zama.ai/introduction-to-homomorphic-encryption) ciphertext.
+
+
+All contracts must set their respective co-processor configuration during construction (or initialization). This can be done automatically by inheriting contracts in [`ZamaConfig`](https://github.com/zama-ai/fhevm/blob/v0.7.12/library-solidity/config/ZamaConfig.sol#L47-L73).
+
+
+## Security
+
+Contracts in the confidential contracts library are provided as is, with no particular guarantees. Given changes in this repository are more frequent, the code is not formally audited and not covered by the [bug bounty program on Immunefi](https://www.immunefi.com/bounty/openzeppelin).
+
+Similarly, the code has no backward compatibility guarantees.
+
+We kindly ask to report any issue directly to our security [contact](mailto:security@openzeppelin.org). The team will do its best to assist and mitigate any potential misuses of the library. However, keep in mind the flexibility assumed for this repository may relax our assessment.
diff --git a/docs/content/confidential-contracts/token.mdx b/docs/content/confidential-contracts/token.mdx
new file mode 100644
index 00000000..188d1979
--- /dev/null
+++ b/docs/content/confidential-contracts/token.mdx
@@ -0,0 +1,109 @@
+---
+title: ERC7984
+---
+
+[`ERC7984`](/confidential-contracts/api/token#ERC7984) is a standard fungible token implementation that is similar to ERC-20, but built from the ground up with confidentiality in mind. All balance and transfer amounts are represented as ciphertext handles, ensuring that no data is leaked to the public.
+
+While the standard is built with inspiration from ERC-20, it is not ERC-20 compliant--the standard takes learning from all tokens built over the past 10 years (ERC-20, ERC-721, ERC-1155, ERC-6909 etc) and provides an interface for maximal functionality.
+
+## Usage
+
+### Transfer
+
+The token standard exposes eight different transfer functions. They are all permutations of the following options:
+
+* `transfer` and `transferFrom`: `transfer` moves tokens from the sender while `transferFrom` moves tokens from a specified `from` address. See [operator](#operator).
+* With and without `inputProof`: An `inputProof` can be provided to prove that the sender knows the value of the ciphertext `amount` provided.
+* With and without an `ERC1363` style callback: The standard implements callbacks, see the [callback](#callback) section for more details.
+
+Select the appropriate transfer function and generate a ciphertext using [fhevm-js](https://github.com/zama-ai/fhevm-js). If the ciphertext is a new value, or the sender does not have permission to access the ciphertext, an input-proof must be provided to show that the sender knows the value of the ciphertext.
+
+### Operator
+
+An operator is an address that has the ability to move tokens on behalf of another address by calling `transferFrom`. If Bob is an operator for Alice, Bob can move any amount of Alice’s tokens at any point in time. Operators are set using an expiration timestamp--this can be thought of as a limited duration infinite approval for an `ERC20`. Below is an example of setting Bob as an operator for Alice for 24 hours.
+
+```typescript
+const alice: Wallet;
+const expirationTimestamp = Math.round(Date.now()) + 60 * 60 * 24; // Now + 24 hours
+
+await tokenContract.connect(alice).setOperator(bob, expirationTimestamp);
+```
+
+
+Operators do not have allowance to reencrypt/decrypt balance handles for other addresses. This means that operators cannot transfer full balances and can only know success after a transaction (by decrypting the transferred amount).
+
+
+
+Setting an operator for any amount of time allows the operator to _***take all of your tokens***_. Carefully vet all potential operators before giving operator approval.
+
+
+### Callback
+
+The token standard exposes transfer functions with and without callbacks. It is up to the caller to decide if a callback is necessary for the transfer. For smart contracts that support it, callbacks allow the operator approval step to be skipped and directly invoke the receiver contract via a callback.
+
+Smart contracts that are the target of a callback must implement [`IERC7984Receiver`](/confidential-contracts/api/interfaces#IERC7984Receiver). After balances are updated for a transfer, the callback is triggered by calling the [`onConfidentialTransferReceived`](/confidential-contracts/api/interfaces#IERC7984Receiver-onConfidentialTransferReceived-address-address-euint64-bytes-) function. The function must either revert or return an `ebool` indicating success. If the callback returns false, the token transfer is reversed.
+
+## Examples
+
+### Privileged Minter/Burner
+
+Here is an example of a contract for a confidential fungible token with a privileged minter and burner.
+
+./examples/ERC7984MintableBurnable.sol
+
+### Swaps
+
+Swapping is one of the most primitive use-cases for fungible tokens. Below are examples for swapping between confidential and non-confidential tokens.
+
+#### Swap `ERC20` to `ERC7984`
+
+Swapping from a non-confidential `ERC20` to a confidential `ERC7984` is simple and actually done within the `ERC7984ERC20Wrapper`. See the excerpt from the `wrap` function below.
+
+```solidity
+function wrap(address to, uint256 amount) public virtual {
+ // take ownership of the tokens
+ SafeERC20.safeTransferFrom(underlying(), msg.sender, address(this), amount - (amount % rate()));
+
+ // mint confidential token
+ _mint(to, (amount / rate()).toUint64().asEuint64());
+}
+```
+
+The `ERC20` token is simply transferred in, which would revert on failure. We then transfer out the correct amount of the `ERC7984` using the internal `_mint` function, which is guaranteed to succeed.
+
+#### Swap `ERC7984` to `ERC7984`
+
+Swapping from a confidential `ERC7984` to another confidential `ERC7984` is a bit more complex although quite simple given the usage of the `FHE` library. For the sake of the example, we will swap from `fromToken` to `toToken` with a 1:1 exchange rate.
+
+```solidity
+ function swapConfidentialForConfidential(
+ IERC7984 fromToken,
+ IERC7984 toToken,
+ externalEuint64 amountInput,
+ bytes calldata inputProof
+ ) public virtual {
+ require(fromToken.isOperator(msg.sender, address(this)));
+
+ euint64 amount = FHE.fromExternal(amountInput, inputProof);
+
+ FHE.allowTransient(amount, address(fromToken));
+ euint64 amountTransferred = fromToken.confidentialTransferFrom(msg.sender, address(this), amount);
+
+ FHE.allowTransient(amountTransferred, address(toToken));
+ toToken.confidentialTransfer(msg.sender, amountTransferred);
+ }
+```
+
+The steps are as follows:
+
+1. Check operator approval
+2. Allow the `fromToken` to access `amount`
+3. Transfer from `from` to this contract for `amount`
+4. Allow the `toToken` to access `amountTransferred`
+5. Transfer `amountTransferred` to `msg.sender`
+
+#### Swap `ERC7984` to `ERC20`
+
+Swapping from a confidential token to a non-confidential token is the most complex since the decrypted data must be accessed to accurately complete the request. Decryption in our example will be done off-chain and relayed back using Zama’s Gateway. Below is an example of a contract doing a 1:1 swap from a confidential token to an ERC20 token.
+
+./examples/SwapERC7984ToERC20.sol
diff --git a/docs/content/contracts-cairo/2.x/access.mdx b/docs/content/contracts-cairo/2.x/access.mdx
new file mode 100644
index 00000000..0c982822
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/access.mdx
@@ -0,0 +1,513 @@
+---
+title: Access
+---
+
+Access control--that is, "who is allowed to do this thing"—is incredibly important in the world of smart contracts.
+The access control of your contract may govern who can mint tokens, vote on proposals, freeze transfers, and many other things.
+It is therefore critical to understand how you implement it, lest someone else
+[steals your whole system](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/).
+
+## Ownership and `Ownable`
+
+The most common and basic form of access control is the concept of ownership: there’s an account that is the `owner`
+of a contract and can do administrative tasks on it.
+This approach is perfectly reasonable for contracts that have a single administrative user.
+
+OpenZeppelin Contracts for Cairo provides [OwnableComponent](/contracts-cairo/2.x/api/access#OwnableComponent) for implementing ownership in your contracts.
+
+### Usage
+
+Integrating this component into a contract first requires assigning an owner.
+The implementing contract’s constructor should set the initial owner by passing the owner’s address to Ownable’s
+[`initializer`](/contracts-cairo/2.x/api/access#OwnableComponent-initializer) like this:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::ownable::OwnableComponent;
+ use starknet::ContractAddress;
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+
+ // Ownable Mixin
+ #[abi(embed_v0)]
+ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;
+ impl InternalImpl = OwnableComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, owner: ContractAddress) {
+ // Set the initial owner of the contract
+ self.ownable.initializer(owner);
+ }
+
+ (...)
+}
+```
+
+To restrict a function’s access to the owner only, add in the `assert_only_owner` method:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ (...)
+
+ #[external(v0)]
+ fn only_owner_allowed(ref self: ContractState) {
+ // This function can only be called by the owner
+ self.ownable.assert_only_owner();
+
+ (...)
+ }
+}
+```
+
+### Interface
+
+This is the full interface of the `OwnableMixinImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait OwnableABI {
+ // IOwnable
+ fn owner() -> ContractAddress;
+ fn transfer_ownership(new_owner: ContractAddress);
+ fn renounce_ownership();
+
+ // IOwnableCamelOnly
+ fn transferOwnership(newOwner: ContractAddress);
+ fn renounceOwnership();
+}
+```
+
+Ownable also lets you:
+
+* `transfer_ownership` from the owner account to a new one, and
+* `renounce_ownership` for the owner to relinquish this administrative privilege, a common pattern
+after an initial stage with centralized administration is over.
+
+
+Removing the owner altogether will mean that administrative tasks that are protected by `assert_only_owner`
+will no longer be callable!
+
+
+### Two step transfer
+
+The component also offers a more robust way of transferring ownership via the
+[OwnableTwoStepImpl](/contracts-cairo/2.x/api/access#OwnableComponent-Embeddable-Impls-OwnableTwoStepImpl) implementation. A two step transfer mechanism helps
+to prevent unintended and irreversible owner transfers. Simply replace the `OwnableMixinImpl`
+with its respective two step variant:
+
+```rust
+#[abi(embed_v0)]
+impl OwnableTwoStepMixinImpl = OwnableComponent::OwnableTwoStepMixinImpl;
+```
+
+#### Interface
+
+This is the full interface of the two step `OwnableTwoStepMixinImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait OwnableTwoStepABI {
+ // IOwnableTwoStep
+ fn owner() -> ContractAddress;
+ fn pending_owner() -> ContractAddress;
+ fn accept_ownership();
+ fn transfer_ownership(new_owner: ContractAddress);
+ fn renounce_ownership();
+
+ // IOwnableTwoStepCamelOnly
+ fn pendingOwner() -> ContractAddress;
+ fn acceptOwnership();
+ fn transferOwnership(newOwner: ContractAddress);
+ fn renounceOwnership();
+}
+```
+
+## Role-Based `AccessControl`
+
+While the simplicity of ownership can be useful for simple systems or quick prototyping, different levels of
+authorization are often needed. You may want for an account to have permission to ban users from a system, but not
+create new tokens. [Role-Based Access Control (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control) offers
+flexibility in this regard.
+
+In essence, we will be defining multiple roles, each allowed to perform different sets of actions.
+An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for
+instead of simply using [`assert_only_owner`](/contracts-cairo/2.x/api/access#OwnableComponent-assert_only_owner). This check can be enforced through [`assert_only_role`](/contracts-cairo/2.x/api/access#AccessControlComponent-assert_only_role).
+Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more.
+
+Most software uses access control systems that are role-based: some users are regular users, some may be supervisors
+or managers, and a few will often have administrative privileges.
+
+### Usage
+
+For each role that you want to define, you will create a new _role identifier_ that is used to grant, revoke, and
+check if an account has that role. See [Creating role identifiers](#creating-role-identifiers) for information
+on creating identifiers.
+
+Here’s a simple example of implementing [AccessControl](/contracts-cairo/2.x/api/access#AccessControlComponent) on a portion of an ERC20 token contract which defines
+and sets a 'minter' role:
+
+```rust
+const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");
+
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::accesscontrol::AccessControlComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ use starknet::ContractAddress;
+ use super::MINTER_ROLE;
+
+ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ // AccessControl
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ // ERC20
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ accesscontrol: AccessControlComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage,
+ #[substorage(v0)]
+ erc20: ERC20Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ #[flat]
+ ERC20Event: ERC20Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ name: ByteArray,
+ symbol: ByteArray,
+ initial_supply: u256,
+ recipient: ContractAddress,
+ minter: ContractAddress
+ ) {
+ // ERC20-related initialization
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+
+ // AccessControl-related initialization
+ self.accesscontrol.initializer();
+ self.accesscontrol._grant_role(MINTER_ROLE, minter);
+ }
+
+ /// This function can only be called by a minter.
+ #[external(v0)]
+ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
+ self.accesscontrol.assert_only_role(MINTER_ROLE);
+ self.erc20.mint(recipient, amount);
+ }
+}
+```
+
+
+Make sure you fully understand how [AccessControl](/contracts-cairo/2.x/api/access#AccessControlComponent) works before
+using it on your system, or copy-pasting the examples from this guide.
+
+
+While clear and explicit, this isn’t anything we wouldn’t have been able to achieve with
+[Ownable](/contracts-cairo/2.x/api/access#OwnableComponent). Where [AccessControl](/contracts-cairo/2.x/api/access#AccessControlComponent) shines the most is in scenarios where granular
+permissions are required, which can be implemented by defining _multiple_ roles.
+
+Let’s augment our ERC20 token example by also defining a 'burner' role, which lets accounts destroy tokens:
+
+```rust
+const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");
+const BURNER_ROLE: felt252 = selector!("BURNER_ROLE");
+
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::accesscontrol::AccessControlComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ use starknet::ContractAddress;
+ use super::{MINTER_ROLE, BURNER_ROLE};
+
+ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ // AccessControl
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ // ERC20
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ accesscontrol: AccessControlComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage,
+ #[substorage(v0)]
+ erc20: ERC20Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ #[flat]
+ ERC20Event: ERC20Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ name: ByteArray,
+ symbol: ByteArray,
+ initial_supply: u256,
+ recipient: ContractAddress,
+ minter: ContractAddress,
+ burner: ContractAddress
+ ) {
+ // ERC20-related initialization
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+
+ // AccessControl-related initialization
+ self.accesscontrol.initializer();
+ self.accesscontrol._grant_role(MINTER_ROLE, minter);
+ self.accesscontrol._grant_role(BURNER_ROLE, burner);
+ }
+
+ /// This function can only be called by a minter.
+ #[external(v0)]
+ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
+ self.accesscontrol.assert_only_role(MINTER_ROLE);
+ self.erc20.mint(recipient, amount);
+ }
+
+ /// This function can only be called by a burner.
+ #[external(v0)]
+ fn burn(ref self: ContractState, account: ContractAddress, amount: u256) {
+ self.accesscontrol.assert_only_role(BURNER_ROLE);
+ self.erc20.burn(account, amount);
+ }
+}
+```
+
+So clean!
+By splitting concerns this way, more granular levels of permission may be implemented than were possible with the
+simpler ownership approach to access control. Limiting what each component of a system is able to do is known
+as the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), and is a good
+security practice. Note that each account may still have more than one role, if so desired.
+
+### Granting and revoking roles
+
+The ERC20 token example above uses [`_grant_role`](/contracts-cairo/2.x/api/access#AccessControlComponent-_grant_role),
+an `internal` function that is useful when programmatically assigning
+roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts?
+
+By default, **accounts with a role cannot grant it or revoke it from other accounts**: all having a role does is making
+the [`assert_only_role`](/contracts-cairo/2.x/api/access#AccessControlComponent-assert_only_role) check pass. To grant and revoke roles dynamically, you will need help from the role’s _admin_.
+
+Every role has an associated admin role, which grants permission to call the
+[`grant_role`](/contracts-cairo/2.x/api/access#AccessControlComponent-grant_role) and
+[`revoke_role`](/contracts-cairo/2.x/api/access#AccessControlComponent-revoke_role) functions.
+A role can be granted or revoked by using these if the calling account has the corresponding admin role.
+Multiple roles may have the same admin role to make management easier.
+A role’s admin can even be the same role itself, which would cause accounts with that role to be able
+to also grant and revoke it.
+
+This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also
+provides an easy way to manage simpler applications. `AccessControl` includes a special role with the role identifier
+of `0`, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**.
+An account with this role will be able to manage any other role, unless
+[`set_role_admin`](/contracts-cairo/2.x/api/access#AccessControlComponent-set_role_admin) is used to select a new admin role.
+
+Let’s take a look at the ERC20 token example, this time taking advantage of the default admin role:
+
+```rust
+const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");
+const BURNER_ROLE: felt252 = selector!("BURNER_ROLE");
+
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::accesscontrol::AccessControlComponent;
+ use openzeppelin_access::accesscontrol::DEFAULT_ADMIN_ROLE;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ use starknet::ContractAddress;
+ use super::{MINTER_ROLE, BURNER_ROLE};
+
+ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ // AccessControl
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ // ERC20
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ (...)
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ name: ByteArray,
+ symbol: ByteArray,
+ initial_supply: u256,
+ recipient: ContractAddress,
+ admin: ContractAddress
+ ) {
+ // ERC20-related initialization
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+
+ // AccessControl-related initialization
+ self.accesscontrol.initializer();
+ self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin);
+ }
+
+ /// This function can only be called by a minter.
+ #[external(v0)]
+ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
+ self.accesscontrol.assert_only_role(MINTER_ROLE);
+ self.erc20.mint(recipient, amount);
+ }
+
+ /// This function can only be called by a burner.
+ #[external(v0)]
+ fn burn(ref self: ContractState, account: ContractAddress, amount: u256) {
+ self.accesscontrol.assert_only_role(BURNER_ROLE);
+ self.erc20.burn(account, amount);
+ }
+}
+```
+
+
+The `grant_role` and `revoke_role` functions are automatically exposed as `external` functions
+from the `AccessControlImpl` by leveraging the `#[abi(embed_v0)]` annotation.
+
+
+Note that, unlike the previous examples, no accounts are granted the 'minter' or 'burner' roles.
+However, because those roles' admin role is the default admin role, and that role was granted to the 'admin', that
+same account can call `grant_role` to give minting or burning permission, and `revoke_role` to remove it.
+
+Dynamic role allocation is often a desirable property, for example in systems where trust in a participant may vary
+over time. It can also be used to support use cases such as [KYC](https://en.wikipedia.org/wiki/Know_your_customer),
+where the list of role-bearers may not be known up-front, or may be prohibitively expensive to include in a single transaction.
+
+### Creating role identifiers
+
+In the Solidity implementation of AccessControl, contracts generally refer to the
+[keccak256 hash](https://docs.soliditylang.org/en/latest/units-and-global-variables.html?highlight=keccak256#mathematical-and-cryptographic-functions)
+of a role as the role identifier.
+
+For example:
+
+```rust
+bytes32 public constant SOME_ROLE = keccak256("SOME_ROLE")
+```
+
+These identifiers take up 32 bytes (256 bits).
+
+Cairo field elements (`felt252`) store a maximum of 252 bits.
+With this discrepancy, this library maintains an agnostic stance on how contracts should create identifiers.
+Some ideas to consider:
+
+* Use [sn_keccak](https://docs.starknet.io/architecture-and-concepts/cryptography/#starknet_keccak) instead.
+* Use Cairo friendly hashing algorithms like Poseidon, which are implemented in the
+[Cairo corelib](https://github.com/starkware-libs/cairo/blob/main/corelib/src/poseidon.cairo).
+
+
+The `selector!` macro can be used to compute [sn_keccak](https://docs.starknet.io/architecture-and-concepts/cryptography/#starknet_keccak) in Cairo.
+
+
+### Interface
+
+This is the full interface of the `AccessControlMixinImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait AccessControlABI {
+ // IAccessControl
+ fn has_role(role: felt252, account: ContractAddress) -> bool;
+ fn get_role_admin(role: felt252) -> felt252;
+ fn grant_role(role: felt252, account: ContractAddress);
+ fn revoke_role(role: felt252, account: ContractAddress);
+ fn renounce_role(role: felt252, account: ContractAddress);
+
+ // IAccessControlCamel
+ fn hasRole(role: felt252, account: ContractAddress) -> bool;
+ fn getRoleAdmin(role: felt252) -> felt252;
+ fn grantRole(role: felt252, account: ContractAddress);
+ fn revokeRole(role: felt252, account: ContractAddress);
+ fn renounceRole(role: felt252, account: ContractAddress);
+
+ // ISRC5
+ fn supports_interface(interface_id: felt252) -> bool;
+}
+```
+
+`AccessControl` also lets you `renounce_role` from the calling account.
+The method expects an account as input as an extra security measure, to ensure you are
+not renouncing a role from an unintended account.
diff --git a/docs/content/contracts-cairo/2.x/accounts.mdx b/docs/content/contracts-cairo/2.x/accounts.mdx
new file mode 100644
index 00000000..fbc2ec48
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/accounts.mdx
@@ -0,0 +1,504 @@
+---
+title: Accounts
+---
+
+Unlike Ethereum where accounts are derived from a private key, all Starknet accounts are contracts. This means there’s no Externally Owned Account (EOA)
+concept on Starknet.
+
+Instead, the network features native account abstraction and signature validation happens at the contract level.
+
+For a general overview of account abstraction, see
+[Starknet’s documentation](https://docs.starknet.io/architecture-and-concepts/accounts/introduction/).
+A more detailed discussion on the topic can be found in
+[Starknet Shaman’s forum](https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781).
+
+
+For detailed information on the usage and implementation check the [API Reference](/contracts-cairo/2.x/api/account) section.
+
+
+## What is an account?
+
+Accounts in Starknet are smart contracts, and so they can be deployed and interacted
+with like any other contract, and can be extended to implement any custom logic. However, an account is a special type
+of contract that is used to validate and execute transactions. For this reason, it must implement a set of entrypoints
+that the protocol uses for this execution flow. The [SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md) proposal defines a standard interface for accounts,
+supporting this execution flow and interoperability with DApps in the ecosystem.
+
+### ISRC6 Interface
+
+```rust
+/// Represents a call to a target contract function.
+struct Call {
+ to: ContractAddress,
+ selector: felt252,
+ calldata: Span
+}
+
+/// Standard Account Interface
+#[starknet::interface]
+pub trait ISRC6 {
+ /// Executes a transaction through the account.
+ fn __execute__(calls: Array);
+
+ /// Asserts whether the transaction is valid to be executed.
+ fn __validate__(calls: Array) -> felt252;
+
+ /// Asserts whether a given signature for a given hash is valid.
+ fn is_valid_signature(hash: felt252, signature: Array) -> felt252;
+}
+```
+
+
+The `calldata` member of the `Call` struct in the accounts has been updated to `Span` for optimization
+purposes, but the interface ID remains the same for backwards compatibility. This inconsistency will be fixed in future releases.
+
+
+[SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md) adds the `is_valid_signature` method. This method is not used by the protocol, but it’s useful for
+DApps to verify the validity of signatures, supporting features like Sign In with Starknet.
+
+SNIP-6 also defines that compliant accounts must implement the SRC5 interface following [SNIP-5](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md), as
+a mechanism for detecting whether a contract is an account or not through introspection.
+
+### ISRC5 Interface
+
+```rust
+/// Standard Interface Detection
+#[starknet::interface]
+pub trait ISRC5 {
+ /// Queries if a contract implements a given interface.
+ fn supports_interface(interface_id: felt252) -> bool;
+}
+```
+
+[SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md) compliant accounts must return `true` when queried for the ISRC6 interface ID.
+
+Even though these interfaces are not enforced by the protocol, it’s recommended to implement them for enabling
+interoperability with the ecosystem.
+
+### Protocol-level methods
+
+The Starknet protocol uses a few entrypoints for abstracting the accounts. We already mentioned the first two
+as part of the ISRC6 interface, and both are required for enabling accounts to be used for executing transactions. The rest are optional:
+
+1. `__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures,
+but the entrypoint implementation can be customized to feature any validation mechanism [with some limitations](https://docs.starknet.io/architecture-and-concepts/accounts/account-functions/#limitations_of_validation).
+2. `__execute__` executes the transaction if the validation is successful.
+3. `__validate_declare__` optional entrypoint similar to `__validate__` but for transactions
+meant to declare other contracts.
+4. `__validate_deploy__` optional entrypoint similar to `__validate__` but meant for [counterfactual deployments](./guides/deployment).
+
+
+Although these entrypoints are available to the protocol for its regular transaction flow, they can also be called like any other method.
+
+
+## Starknet Account
+
+Starknet native account abstraction pattern allows for the creation of custom accounts with different validation schemes, but
+usually most account implementations validate transactions using the [Stark curve](https://docs.starknet.io/architecture-and-concepts/cryptography/#stark-curve) which is the most efficient way
+of validating signatures since it is a STARK-friendly curve.
+
+OpenZeppelin Contracts for Cairo provides [AccountComponent](/contracts-cairo/2.x/api/account#AccountComponent) for implementing this validation scheme.
+
+### Usage
+
+Constructing an account contract requires integrating both [AccountComponent](/contracts-cairo/2.x/api/account#AccountComponent) and [SRC5Component](/contracts-cairo/2.x/api/introspection#SRC5Component). The contract should also set up the constructor to initialize the public key that will be used as the account’s signer. Here’s an example of a basic contract:
+
+```rust
+#[starknet::contract(account)]
+mod MyAccount {
+ use openzeppelin_account::AccountComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+
+ component!(path: AccountComponent, storage: account, event: AccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Account Mixin
+ #[abi(embed_v0)]
+ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;
+ impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ account: AccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccountEvent: AccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: felt252) {
+ self.account.initializer(public_key);
+ }
+}
+```
+
+### Interface
+
+This is the full interface of the `AccountMixinImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait AccountABI {
+ // ISRC6
+ fn __execute__(calls: Array);
+ fn __validate__(calls: Array) -> felt252;
+ fn is_valid_signature(hash: felt252, signature: Array) -> felt252;
+
+ // ISRC5
+ fn supports_interface(interface_id: felt252) -> bool;
+
+ // IDeclarer
+ fn __validate_declare__(class_hash: felt252) -> felt252;
+
+ // IDeployable
+ fn __validate_deploy__(
+ class_hash: felt252, contract_address_salt: felt252, public_key: felt252
+ ) -> felt252;
+
+ // IPublicKey
+ fn get_public_key() -> felt252;
+ fn set_public_key(new_public_key: felt252, signature: Span);
+
+ // ISRC6CamelOnly
+ fn isValidSignature(hash: felt252, signature: Array) -> felt252;
+
+ // IPublicKeyCamel
+ fn getPublicKey() -> felt252;
+ fn setPublicKey(newPublicKey: felt252, signature: Span);
+}
+```
+
+## Ethereum Account
+
+Besides the Stark-curve account, OpenZeppelin Contracts for Cairo also offers Ethereum-flavored accounts that use the [secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve for signature validation.
+For this the [EthAccountComponent](/contracts-cairo/2.x/api/account#EthAccountComponent) must be used.
+
+### Usage
+
+Constructing a secp256k1 account contract also requires integrating both [EthAccountComponent](/contracts-cairo/2.x/api/account#EthAccountComponent) and [SRC5Component](/contracts-cairo/2.x/api/introspection#SRC5Component).
+The contract should also set up the constructor to initialize the public key that will be used as the account’s signer.
+Here’s an example of a basic contract:
+
+```rust
+#[starknet::contract(account)]
+mod MyEthAccount {
+ use openzeppelin_account::EthAccountComponent;
+ use openzeppelin_account::interface::EthPublicKey;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use starknet::ClassHash;
+
+ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // EthAccount Mixin
+ #[abi(embed_v0)]
+ impl EthAccountMixinImpl =
+ EthAccountComponent::EthAccountMixinImpl;
+ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ eth_account: EthAccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ EthAccountEvent: EthAccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: EthPublicKey) {
+ self.eth_account.initializer(public_key);
+ }
+}
+```
+
+### Interface
+
+This is the full interface of the `EthAccountMixinImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait EthAccountABI {
+ // ISRC6
+ fn __execute__(calls: Array);
+ fn __validate__(calls: Array) -> felt252;
+ fn is_valid_signature(hash: felt252, signature: Array) -> felt252;
+
+ // ISRC5
+ fn supports_interface(interface_id: felt252) -> bool;
+
+ // IDeclarer
+ fn __validate_declare__(class_hash: felt252) -> felt252;
+
+ // IEthDeployable
+ fn __validate_deploy__(
+ class_hash: felt252, contract_address_salt: felt252, public_key: EthPublicKey
+ ) -> felt252;
+
+ // IEthPublicKey
+ fn get_public_key() -> EthPublicKey;
+ fn set_public_key(new_public_key: EthPublicKey, signature: Span);
+
+ // ISRC6CamelOnly
+ fn isValidSignature(hash: felt252, signature: Array) -> felt252;
+
+ // IEthPublicKeyCamel
+ fn getPublicKey() -> EthPublicKey;
+ fn setPublicKey(newPublicKey: EthPublicKey, signature: Span);
+}
+
+```
+
+## Deploying an account
+
+In Starknet there are two ways of deploying smart contracts: using the `deploy_syscall` and doing
+counterfactual deployments.
+The former can be easily done with the [Universal Deployer Contract (UDC)](./udc), a contract that
+wraps and exposes the `deploy_syscall` to provide arbitrary deployments through regular contract calls.
+But if you don’t have an account to invoke it, you will probably want to use the latter.
+
+To do counterfactual deployments, you need to implement another protocol-level entrypoint named
+`__validate_deploy__`. Check the [counterfactual deployments](./guides/deployment) guide to learn how.
+
+## Sending transactions
+
+Let’s now explore how to send transactions through these accounts.
+
+### Starknet Account
+
+First, let’s take the example account we created before and deploy it:
+
+```rust
+#[starknet::contract(account)]
+mod MyAccount {
+ use openzeppelin_account::AccountComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+
+ component!(path: AccountComponent, storage: account, event: AccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Account Mixin
+ #[abi(embed_v0)]
+ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;
+ impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ account: AccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccountEvent: AccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: felt252) {
+ self.account.initializer(public_key);
+ }
+}
+```
+
+To deploy the account variant, compile the contract and declare the class hash because custom accounts are likely not declared.
+This means that you’ll need an account already deployed.
+
+Next, create the account JSON with Starknet Foundry’s [custom account setup](https://foundry-rs.github.io/starknet-foundry/starknet/account.html#custom-account-contract) and include the `--class-hash` flag with the declared class hash.
+The flag enables custom account variants.
+
+
+The following examples use `sncast` [v0.23.0](https://github.com/foundry-rs/starknet-foundry/releases/tag/v0.23.0).
+
+
+```bash
+$ sncast \
+ --url http://127.0.0.1:5050 \
+ account create \
+ --name my-custom-account \
+ --class-hash 0x123456...
+```
+
+This command will output the precomputed contract address and the recommended `max-fee`.
+To counterfactually deploy the account, send funds to the address and then deploy the custom account.
+
+```bash
+$ sncast \
+ --url http://127.0.0.1:5050 \
+ account deploy \
+ --name my-custom-account
+```
+
+Once the account is deployed, set the `--account` flag with the custom account name to send transactions from that account.
+
+```bash
+$ sncast \
+ --account my-custom-account \
+ --url http://127.0.0.1:5050 \
+ invoke \
+ --contract-address 0x123... \
+ --function "some_function" \
+ --calldata 1 2 3
+```
+
+### Ethereum Account
+
+First, let’s take the example account we created before and deploy it:
+
+```rust
+#[starknet::contract(account)]
+mod MyEthAccount {
+ use openzeppelin_account::EthAccountComponent;
+ use openzeppelin_account::interface::EthPublicKey;
+ use openzeppelin_introspection::src5::SRC5Component;
+
+ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // EthAccount Mixin
+ #[abi(embed_v0)]
+ impl EthAccountMixinImpl =
+ EthAccountComponent::EthAccountMixinImpl;
+ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ eth_account: EthAccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ EthAccountEvent: EthAccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: EthPublicKey) {
+ self.eth_account.initializer(public_key);
+ }
+}
+```
+
+Special tooling is required in order to deploy and send transactions with an Ethereum-flavored account contract.
+The following examples utilize the [StarknetJS](https://www.starknetjs.com/) library.
+
+Compile and declare the contract on the target network.
+Next, precompute the EthAccount contract address using the declared class hash.
+
+
+The following examples use unreleased features from StarknetJS (`starknetjs@next`) at commit [d002baea0abc1de3ac6e87a671f3dec3757437b3](https://github.com/starknet-io/starknet.js/commit/d002baea0abc1de3ac6e87a671f3dec3757437b3).
+
+
+```javascript
+import * as dotenv from 'dotenv';
+import { CallData, EthSigner, hash } from 'starknet';
+import { ABI as ETH_ABI } from '../abis/eth_account.js';
+dotenv.config();
+
+const ethSigner = new EthSigner(process.env.ETH_PRIVATE_KEY);
+const ethPubKey = await ethSigner.getPubKey();
+const ethAccountClassHash = '';
+const ethCallData = new CallData(ETH_ABI);
+const ethAccountConstructorCalldata = ethCallData.compile('constructor', {
+ public_key: ethPubKey
+})
+const salt = '0x12345';
+const deployerAddress = '0x0';
+const ethContractAddress = hash.calculateContractAddressFromHash(
+ salt,
+ ethAccountClassHash,
+ ethAccountConstructorCalldata,
+ deployerAddress
+);
+console.log('Pre-calculated EthAccount address: ', ethContractAddress);
+```
+
+Send funds to the pre-calculated EthAccount address and deploy the contract.
+
+```javascript
+import * as dotenv from 'dotenv';
+import { Account, CallData, EthSigner, RpcProvider, stark } from 'starknet';
+import { ABI as ETH_ABI } from '../abis/eth_account.js';
+dotenv.config();
+
+const provider = new RpcProvider({ nodeUrl: process.env.API_URL });
+const ethSigner = new EthSigner(process.env.ETH_PRIVATE_KEY);
+const ethPubKey = await ethSigner.getPubKey();
+const ethAccountAddress = ''
+const ethAccount = new Account(provider, ethAccountAddress, ethSigner);
+
+const ethAccountClassHash = ''
+const ethCallData = new CallData(ETH_ABI);
+const ethAccountConstructorCalldata = ethCallData.compile('constructor', {
+ public_key: ethPubKey
+})
+const salt = '0x12345';
+const deployPayload = {
+ classHash: ethAccountClassHash,
+ constructorCalldata: ethAccountConstructorCalldata,
+ addressSalt: salt,
+};
+
+const { suggestedMaxFee: feeDeploy } = await ethAccount.estimateAccountDeployFee(deployPayload);
+const { transaction_hash, contract_address } = await ethAccount.deployAccount(
+ deployPayload,
+ { maxFee: stark.estimatedFeeToMaxFee(feeDeploy, 100) }
+);
+await provider.waitForTransaction(transaction_hash);
+console.log('EthAccount deployed at: ', contract_address);
+```
+
+Once deployed, connect the EthAccount instance to the target contract which enables calls to come from the EthAccount.
+Here’s what an ERC20 transfer from an EthAccount looks like.
+
+```javascript
+import * as dotenv from 'dotenv';
+import { Account, RpcProvider, Contract, EthSigner } from 'starknet';
+dotenv.config();
+
+const provider = new RpcProvider({ nodeUrl: process.env.API_URL });
+const ethSigner = new EthSigner(process.env.ETH_PRIVATE_KEY);
+const ethAccountAddress = ''
+const ethAccount = new Account(provider, ethAccountAddress, ethSigner);
+
+const erc20 = new Contract(compiledErc20.abi, erc20Address, provider);
+
+erc20.connect(ethAccount);
+
+const transferCall = erc20.populate('transfer', {
+ recipient: recipient.address,
+ amount: 50n
+});
+const tx = await erc20.transfer(
+ transferCall.calldata, { maxFee: 900_000_000_000_000 }
+);
+await provider.waitForTransaction(tx.transaction_hash);
+```
diff --git a/docs/content/contracts-cairo/2.x/api/access.mdx b/docs/content/contracts-cairo/2.x/api/access.mdx
new file mode 100644
index 00000000..71fd194c
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/access.mdx
@@ -0,0 +1,867 @@
+---
+title: Access Control
+---
+
+This crate provides ways to restrict who can access the functions of a contract or when they can do it.
+
+- [Ownable](#OwnableComponent) is a simple mechanism with a single "owner" role that can be assigned to a single account. This mechanism can be useful in simple scenarios, but fine grained access needs are likely to outgrow it.
+- [AccessControl](#AccessControlComponent) provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts.
+
+## Interfaces
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+### `IAccessControl` [toc] [#IAccessControl]
+
+
+```rust
+use openzeppelin_access::accesscontrol::interface::IAccessControl;
+```
+
+External interface of AccessControl.
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751
+```
+
+Functions
+
+- [`has_role(role, account)`](#IAccessControl-has_role)
+- [`get_role_admin(role)`](#IAccessControl-get_role_admin)
+- [`grant_role(role, account)`](#IAccessControl-grant_role)
+- [`revoke_role(role, account)`](#IAccessControl-revoke_role)
+- [`renounce_role(role, account)`](#IAccessControl-renounce_role)
+
+Events
+
+- [`RoleAdminChanged(role, previous_admin_role, new_admin_role)`](#IAccessControl-RoleAdminChanged)
+- [`RoleGranted(role, account, sender)`](#IAccessControl-RoleGranted)
+- [`RoleRevoked(role, account, sender)`](#IAccessControl-RoleRevoked)
+
+
+#### Functions [!toc] [#IAccessControl-Functions]
+
+
+Returns whether `account` can act as `role`.
+
+
+
+Returns the admin role that controls `role`. See [grant\_role](#IAccessControl-grant_role) and [revoke\_role](#IAccessControl-revoke_role).
+
+To change a role’s admin, use [set\_role\_admin](#AccessControlComponent-set_role_admin).
+
+
+
+Grants `role` to `account`.
+
+If `account` had not been already granted `role`, emits a [RoleGranted](#IAccessControl-RoleGranted) event.
+
+Requirements:
+
+- the caller must have `role`'s admin role.
+
+
+
+Revokes `role` from `account`.
+
+If `account` had been granted `role`, emits a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+Requirements:
+
+- the caller must have `role`'s admin role.
+
+
+
+Revokes `role` from the calling account.
+
+Roles are often managed via [grant\_role](#IAccessControl-grant_role) and [revoke\_role](#IAccessControl-revoke_role). This function’s purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).
+
+If the calling account had been granted `role`, emits a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+Requirements:
+
+- the caller must be `account`.
+
+
+#### Events [!toc] [#IAccessControl-Events]
+
+
+Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role`
+
+`DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite [RoleAdminChanged](#IAccessControl-RoleAdminChanged) not being emitted signaling this.
+
+
+
+Emitted when `account` is granted `role`.
+
+`sender` is the account that originated the contract call, an account with the admin role or the deployer address if `_grant_role` is called from the constructor.
+
+
+
+Emitted when `account` is revoked `role`.
+
+`sender` is the account that originated the contract call:
+
+- if using `revoke_role`, it is the admin role bearer.
+- if using `renounce_role`, it is the role bearer (i.e. `account`).
+
+
+### `IAccessControlWithDelay` [toc] [#IAccessControlWithDelay]
+
+
+```rust
+use openzeppelin_access::accesscontrol::interface::IAccessControlWithDelay;
+```
+
+External interface for the extended `AccessControlWithDelay` functionality.
+
+Functions
+
+- [`get_role_status(role, account)`](#IAccessControlWithDelay-get_role_status)
+- [`grant_role_with_delay(role, account, delay)`](#IAccessControlWithDelay-grant_role_with_delay)
+
+Events
+
+- [`RoleGrantedWithDelay(role, account, sender, delay)`](#IAccessControlWithDelay-RoleGrantedWithDelay)
+
+#### Functions [!toc] [#IAccessControlWithDelay-Functions]
+
+
+Returns the account’s status for the given role. The possible statuses are:
+
+- `NotGranted`: the role has not been granted to the account.
+- `Delayed`: The role has been granted to the account but is not yet active due to a time delay.
+- `Effective`: the role has been granted to the account and is currently active.
+
+
+
+Attempts to grant `role` to `account` with the specified activation delay.
+
+Requirements:
+
+- The caller must have `role`'s admin role.
+- delay must be greater than 0.
+- the `role` must not be already effective for `account`.
+
+May emit a [RoleGrantedWithDelay](#IAccessControlWithDelay-RoleGrantedWithDelay) event.
+
+
+#### Events [!toc] [#IAccessControlWithDelay-Events]
+
+
+Emitted when `account` is granted `role` with a delay.
+
+`sender` is the account that originated the contract call, an account with the admin role or the deployer address if [\_grant\_role\_with\_delay](#AccessControlComponent-_grant_role_with_delay) is called from the constructor.
+
+
+## Core
+
+### `OwnableComponent` [toc] [#OwnableComponent]
+
+
+```rust
+use openzeppelin_access::ownable::OwnableComponent;
+```
+
+`Ownable` provides a basic access control mechanism where an account (an owner) can be granted exclusive access to specific functions.
+
+This module includes the internal `assert_only_owner` to restrict a function to be used only by the owner.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### OwnableMixinImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableMixinImpl]
+
+- [`OwnableImpl`](#OwnableComponent-Embeddable-Impls-OwnableImpl)
+- [`OwnableCamelOnlyImpl`](#OwnableComponent-Embeddable-Impls-OwnableCamelOnlyImpl)
+
+#### OwnableTwoStepMixinImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableTwoStepMixinImpl]
+
+- [`OwnableTwoStepImpl`](#OwnableComponent-Embeddable-Impls-OwnableTwoStepImpl)
+- [`OwnableTwoStepCamelOnlyImpl`](#OwnableComponent-Embeddable-Impls-OwnableTwoStepCamelOnlyImpl)
+
+Embeddable Implementations
+
+#### OwnableImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableImpl]
+
+- [`owner(self)`](#OwnableComponent-owner)
+- [`transfer_ownership(self, new_owner)`](#OwnableComponent-transfer_ownership)
+- [`renounce_ownership(self)`](#OwnableComponent-renounce_ownership)
+
+#### OwnableTwoStepImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableTwoStepImpl]
+
+- [`owner(self)`](#OwnableComponent-two-step-owner)
+- [`pending_owner(self)`](#OwnableComponent-two-step-pending_owner)
+- [`accept_ownership(self)`](#OwnableComponent-two-step-accept_ownership)
+- [`transfer_ownership(self, new_owner)`](#OwnableComponent-two-step-transfer_ownership)
+- [`renounce_ownership(self)`](#OwnableComponent-two-step-renounce_ownership)
+
+#### OwnableCamelOnlyImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableCamelOnlyImpl]
+
+- [`transferOwnership(self, newOwner)`](#OwnableComponent-transferOwnership)
+- [`renounceOwnership(self)`](#OwnableComponent-renounceOwnership)
+
+#### OwnableTwoStepCamelOnlyImpl [!toc] [#OwnableComponent-Embeddable-Impls-OwnableTwoStepCamelOnlyImpl]
+
+- [`pendingOwner(self)`](#OwnableComponent-two-step-pendingOwner)
+- [`acceptOwnership(self)`](#OwnableComponent-two-step-acceptOwnership)
+- [`transferOwnership(self, new_owner)`](#OwnableComponent-two-step-transferOwnership)
+- [`renounceOwnership(self)`](#OwnableComponent-two-step-renounceOwnership)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#OwnableComponent-InternalImpl]
+
+- [`initializer(self, owner)`](#OwnableComponent-initializer)
+- [`assert_only_owner(self)`](#OwnableComponent-assert_only_owner)
+- [`_transfer_ownership(self, new_owner)`](#OwnableComponent-_transfer_ownership)
+- [`_propose_owner(self, new_owner)`](#OwnableComponent-_propose_owner)
+
+Events
+
+- [`OwnershipTransferStarted(previous_owner, new_owner)`](#OwnableComponent-OwnershipTransferStarted)
+- [`OwnershipTransferred(previous_owner, new_owner)`](#OwnableComponent-OwnershipTransferred)
+
+#### Embeddable functions [!toc] [#OwnableComponent-Embeddable-Functions]
+
+
+Returns the address of the current owner.
+
+
+
+Transfers ownership of the contract to a new account (`new_owner`). Can only be called by the current owner.
+
+Emits an [OwnershipTransferred](#OwnableComponent-OwnershipTransferred) event.
+
+
+
+Leaves the contract without owner. It will not be possible to call `assert_only_owner` functions anymore. Can only be called by the current owner.
+
+
+Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.
+
+
+
+#### Embeddable functions (two step transfer) [!toc] [#OwnableComponent-Embeddable-Functions-Two-Step]
+
+
+Returns the address of the current owner.
+
+
+
+Returns the address of the pending owner.
+
+
+
+Transfers ownership of the contract to the pending owner. Can only be called by the pending owner. Resets pending owner to zero address.
+
+Emits an [OwnershipTransferred](#OwnableComponent-OwnershipTransferred) event.
+
+
+
+Starts the two step ownership transfer process, by setting the pending owner. Setting `new_owner` to the zero address is allowed, this can be used to cancel an initiated ownership transfer.
+
+Can only be called by the current owner.
+
+Emits an [OwnershipTransferStarted](#OwnableComponent-OwnershipTransferStarted) event.
+
+
+
+Leaves the contract without owner. It will not be possible to call `assert_only_owner` functions anymore. Can only be called by the current owner.
+
+
+Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.
+
+
+
+
+See [transfer\_ownership](#OwnableComponent-transfer_ownership).
+
+
+
+See [renounce\_ownership](#OwnableComponent-renounce_ownership).
+
+
+
+See [pending\_owner](#OwnableComponent-two-step-pending_owner).
+
+
+
+See [accept\_ownership](#OwnableComponent-two-step-accept_ownership).
+
+
+
+See [transfer\_ownership](#OwnableComponent-two-step-transfer_ownership).
+
+
+
+See [renounce\_ownership](#OwnableComponent-two-step-renounce_ownership).
+
+
+#### Internal functions [!toc] [#OwnableComponent-Internal-Functions]
+
+
+Initializes the contract and sets `owner` as the initial owner.
+
+Requirements:
+
+- `owner` cannot be the zero address.
+
+Emits an [OwnershipTransferred](#OwnableComponent-OwnershipTransferred) event.
+
+
+
+Panics if called by any account other than the owner.
+
+
+
+Transfers ownership of the contract to a new account (`new_owner`). Internal function without access restriction.
+
+Emits an [OwnershipTransferred](#OwnableComponent-OwnershipTransferred) event.
+
+
+
+Sets a new pending owner in a two step transfer.
+
+Internal function without access restriction.
+
+Emits an [OwnershipTransferStarted](#OwnableComponent-OwnershipTransferStarted) event.
+
+
+#### Events [!toc] [#OwnableComponent-Events]
+
+
+Emitted when the pending owner is updated.
+
+
+
+Emitted when the ownership is transferred.
+
+
+### `AccessControlComponent` [toc] [#AccessControlComponent]
+
+
+```rust
+use openzeppelin_access::accesscontrol::AccessControlComponent;
+```
+
+Component that allows contracts to implement role-based access control mechanisms. Roles are referred to by their `felt252` identifier:
+
+```rust
+const MY_ROLE: felt252 = selector!("MY_ROLE");
+```
+
+Roles can be used to represent a set of permissions. To restrict access to a function call, use [`assert_only_role`](#AccessControlComponent-assert_only_role):
+
+```rust
+(...)
+
+#[external(v0)]
+fn foo(ref self: ContractState) {
+ self.accesscontrol.assert_only_role(MY_ROLE);
+
+ // Do something
+}
+```
+
+Roles can be granted and revoked dynamically via the [grant\_role](#AccessControlComponent-grant_role), [grant\_role\_with\_delay](#IAccessControlWithDelay-grant_role_with_delay) and [revoke\_role](#AccessControlComponent-revoke_role) functions. Each role has an associated admin role, and only accounts that have a role’s admin role can call [grant\_role](#AccessControlComponent-grant_role), [grant\_role\_with\_delay](#IAccessControlWithDelay-grant_role_with_delay) and [revoke\_role](#AccessControlComponent-revoke_role).
+
+By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using [set\_role\_admin](#AccessControlComponent-set_role_admin).
+
+
+The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it.
+
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### AccessControlMixinImpl [!toc] [#AccessControlComponent-Embeddable-Impls-AccessControlMixinImpl]
+
+- [`AccessControlImpl`](#AccessControlComponent-Embeddable-Impls-AccessControlImpl)
+- [`AccessControlCamelImpl`](#AccessControlComponent-Embeddable-Impls-AccessControlCamelImpl)
+- [`AccessControlWithDelayImpl`](#AccessControlComponent-Embeddable-Impls-AccessControlWithDelayImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### AccessControlImpl [!toc] [#AccessControlComponent-Embeddable-Impls-AccessControlImpl]
+
+- [`has_role(self, role, account)`](#AccessControlComponent-has_role)
+- [`get_role_admin(self, role)`](#AccessControlComponent-get_role_admin)
+- [`grant_role(self, role, account)`](#AccessControlComponent-grant_role)
+- [`revoke_role(self, role, account)`](#AccessControlComponent-revoke_role)
+- [`renounce_role(self, role, account)`](#AccessControlComponent-renounce_role)
+
+#### AccessControlCamelImpl [!toc] [#AccessControlComponent-Embeddable-Impls-AccessControlCamelImpl]
+
+- [`hasRole(self, role, account)`](#AccessControlComponent-hasRole)
+- [`getRoleAdmin(self, role)`](#AccessControlComponent-getRoleAdmin)
+- [`grantRole(self, role, account)`](#AccessControlComponent-grantRole)
+- [`revokeRole(self, role, account)`](#AccessControlComponent-revokeRole)
+- [`renounceRole(self, role, account)`](#AccessControlComponent-renounceRole)
+
+#### AccessControlWithDelayImpl [!toc] [#AccessControlComponent-Embeddable-Impls-AccessControlWithDelayImpl]
+
+- [`get_role_status(self, role, account)`](#AccessControlComponent-get_role_status)
+- [`grant_role_with_delay(self, role, account, delay)`](#AccessControlComponent-grant_role_with_delay)
+
+#### SRC5Impl [!toc] [#AccessControlComponent-Embeddable-Impls-SRC5Impl]
+
+- [`supports_interface(self, interface_id: felt252)`](./introspection#ISRC5-supports_interface)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#AccessControlComponent-InternalImpl]
+
+- [`initializer(self)`](#AccessControlComponent-initializer)
+- [`assert_only_role(self, role)`](#AccessControlComponent-assert_only_role)
+- [`is_role_effective(self, role, account)`](#AccessControlComponent-is_role_effective)
+- [`resolve_role_status(self, role, account)`](#AccessControlComponent-resolve_role_status)
+- [`is_role_granted(self, role, account)`](#AccessControlComponent-is_role_granted)
+- [`set_role_admin(self, role, admin_role)`](#AccessControlComponent-set_role_admin)
+- [`_grant_role(self, role, account)`](#AccessControlComponent-_grant_role)
+- [`_grant_role_with_delay(self, role, account, delay)`](#AccessControlComponent-_grant_role_with_delay)
+- [`_revoke_role(self, role, account)`](#AccessControlComponent-_revoke_role)
+
+Events
+
+#### IAccessControl [!toc] [#AccessControlComponent-Events-IAccessControl]
+
+- [`RoleAdminChanged(role, previous_admin_role, new_admin_role)`](#AccessControlComponent-RoleAdminChanged)
+- [`RoleGranted(role, account, sender)`](#AccessControlComponent-RoleGranted)
+- [`RoleRevoked(role, account, sender)`](#AccessControlComponent-RoleRevoked)
+
+#### IAccessControlWithDelay [!toc] [#AccessControlComponent-Events-IAccessControlWithDelay]
+
+- [`RoleGrantedWithDelay(role, account, sender, delay)`](#AccessControlComponent-RoleGrantedWithDelay)
+
+#### Embeddable functions [!toc] [#AccessControlComponent-Embeddable-Functions]
+
+
+Returns whether `account` can act as `role`.
+
+
+
+Returns the admin role that controls `role`. See [grant\_role](#AccessControlComponent-grant_role) and [revoke\_role](#AccessControlComponent-revoke_role).
+
+To change a role’s admin, use [set\_role\_admin](#AccessControlComponent-set_role_admin).
+
+
+
+Returns the account’s status for the given role.
+
+The possible statuses are:
+
+- `NotGranted`: the role has not been granted to the account.
+- `Delayed`: The role has been granted to the account but is not yet active due to a time delay.
+- `Effective`: the role has been granted to the account and is currently active.
+
+
+
+Grants `role` to `account`.
+
+If `account` had not been already granted `role`, emits a [RoleGranted](#IAccessControl-RoleGranted) event.
+
+Requirements:
+
+- the caller must have `role`'s admin role.
+
+May emit a [RoleGranted](#IAccessControl-RoleGranted) event.
+
+
+
+Attempts to grant `role` to `account` with the specified activation delay.
+
+Requirements:
+
+- The caller must have \`role’s admin role.
+- delay must be greater than 0.
+- the `role` must not be already effective for `account`.
+
+May emit a [RoleGrantedWithDelay](#IAccessControlWithDelay-RoleGrantedWithDelay) event.
+
+
+
+Revokes `role` from `account`.
+
+If `account` had been granted `role`, emits a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+Requirements:
+
+- the caller must have `role`'s admin role.
+
+May emit a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+
+
+Revokes `role` from the calling account.
+
+Roles are often managed via [grant\_role](#AccessControlComponent-grant_role) and [revoke\_role](#AccessControlComponent-revoke_role). This function’s purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).
+
+If the calling account had been revoked `role`, emits a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+Requirements:
+
+- the caller must be `account`.
+
+May emit a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+
+
+See [ISRC5::supports\_interface](./introspection#ISRC5-supports_interface).
+
+
+
+See [has\_role](#AccessControlComponent-has_role).
+
+
+
+See [get\_role\_admin](#AccessControlComponent-get_role_admin).
+
+
+
+See [grant\_role](#AccessControlComponent-grant_role).
+
+
+
+See [revoke\_role](#AccessControlComponent-revoke_role).
+
+
+
+See [renounce\_role](#AccessControlComponent-renounce_role).
+
+
+#### Internal functions [!toc] [#AccessControlComponent-Internal-Functions]
+
+
+Initializes the contract by registering the [IAccessControl](#IAccessControl) interface ID.
+
+
+
+Validates that the caller can act as the given role. Otherwise it panics.
+
+
+
+Returns whether the account can act as the given role.
+
+The account can act as the role if it is active and the `effective_from` time is before or equal to the current time.
+
+
+If the `effective_from` timepoint is 0, the role is effective immediately. This is backwards compatible with implementations that didn’t use delays but a single boolean flag.
+
+
+
+
+Returns the account’s status for the given role.
+
+The possible statuses are:
+
+- `NotGranted`: the role has not been granted to the account.
+- `Delayed`: The role has been granted to the account but is not yet active due to a time delay.
+- `Effective`: the role has been granted to the account and is currently active.
+
+
+
+Returns whether the account has the given role granted.
+
+
+The account may not be able to act as the role yet, if a delay was set and has not passed yet. Use `is_role_effective` to check if the account can act as the role.
+
+
+
+
+Sets `admin_role` as `role`'s admin role.
+
+Internal function without access restriction.
+
+Emits a [RoleAdminChanged](#IAccessControl-RoleAdminChanged) event.
+
+
+
+Attempts to grant `role` to `account`. The function does nothing if `role` is already effective for `account`. If `role` has been granted to `account`, but is not yet active due to a time delay, the delay is removed and `role` becomes effective immediately.
+
+Internal function without access restriction.
+
+May emit a [RoleGranted](#IAccessControl-RoleGranted) event.
+
+
+
+Attempts to grant `role` to `account` with the specified activation delay.
+
+The role will become effective after the given delay has passed. If the role is already active (`Effective`) for the account, the function will panic. If the role has been granted but is not yet active (being in the `Delayed` state), the existing delay will be overwritten with the new `delay`.
+
+Internal function without access restriction.
+
+Requirements:
+
+- delay must be greater than 0.
+- the `role` must not be already effective for `account`.
+
+May emit a [RoleGrantedWithDelay](#IAccessControlWithDelay-RoleGrantedWithDelay) event.
+
+
+
+Revokes `role` from `account`.
+
+Internal function without access restriction.
+
+May emit a [RoleRevoked](#IAccessControl-RoleRevoked) event.
+
+
+#### Events [!toc] [#AccessControlComponent-Events]
+
+
+See [IAccessControl::RoleAdminChanged](#IAccessControl-RoleAdminChanged).
+
+
+
+See [IAccessControl::RoleGranted](#IAccessControl-RoleGranted).
+
+
+
+See [IAccessControlWithDelay::RoleGrantedWithDelay](#IAccessControlWithDelay-RoleGrantedWithDelay).
+
+
+
+See [IAccessControl::RoleRevoked](#IAccessControl-RoleRevoked).
+
diff --git a/docs/content/contracts-cairo/2.x/api/account.mdx b/docs/content/contracts-cairo/2.x/api/account.mdx
new file mode 100644
index 00000000..a839a5ed
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/account.mdx
@@ -0,0 +1,842 @@
+---
+title: Account
+---
+
+This crate provides components to implement account contracts that can be used for interacting with the network.
+
+## Interfaces
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+### `ISRC6` [toc] [#ISRC6]
+
+
+```rust
+use openzeppelin_account::interface::ISRC6;
+```
+
+Interface of the SRC6 Standard Account as defined in the [SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd
+```
+
+Functions
+
+- [`__execute__(calls)`](#ISRC6-__execute__)
+- [`__validate__(calls)`](#ISRC6-__validate__)
+- [`is_valid_signature(hash, signature)`](#ISRC6-is_valid_signature)
+
+#### Functions [!toc] [#ISRC6-Functions]
+
+
+Executes the list of calls as a transaction after validation.
+
+The `Call` struct is defined in [corelib](https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/account.cairo#L3).
+
+
+
+Validates a transaction before execution.
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Validates whether a signature is valid or not for the given message hash.
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+### `ISRC9_V2` [toc] [#ISRC9_V2]
+
+
+```rust
+use openzeppelin_account::extensions::src9::ISRC9_V2;
+```
+
+Interface of the SRC9 Standard as defined in the [SNIP-9](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-9.md).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x1d1144bb2138366ff28d8e9ab57456b1d332ac42196230c3a602003c89872
+```
+
+Functions
+
+- [`execute_from_outside_v2(outside_execution, signature)`](#ISRC9_V2-execute_from_outside_v2)
+- [`is_valid_outside_execution_nonce(nonce)`](#ISRC9_V2-is_valid_outside_execution_nonce)
+
+#### Functions [!toc] [#ISRC9_V2-Functions]
+
+
+Allows anyone to submit a transaction on behalf of the account as long as they have the relevant signatures.
+
+This method allows reentrancy. A call to `__execute__` or `execute_from_outside_v2` can trigger another nested transaction to `execute_from_outside_v2` thus the implementation MUST verify that the provided `signature` matches the hash of `outside_execution` and that `nonce` was not already used.
+
+The implementation should expect version to be set to 2 in the domain separator.
+
+Arguments:
+
+- `outside_execution` - The parameters of the transaction to execute.
+- `signature` - A valid signature on the [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) message encoding of `outside_execution`.
+
+
+
+Get the status of a given nonce. `true` if the nonce is available to use.
+
+
+## Core
+
+### `AccountComponent` [toc] [#AccountComponent]
+
+
+```rust
+use openzeppelin_account::AccountComponent;
+```
+
+Account component implementing [`ISRC6`](#ISRC6) for signatures over the [Starknet curve](https://docs.starknet.io/architecture-and-concepts/cryptography/#stark-curve).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### AccountMixinImpl [!toc] [#AccountComponent-Embeddable-Impls-AccountMixinImpl]
+
+- [`SRC6Impl`](#AccountComponent-Embeddable-Impls-SRC6Impl)
+- [`DeclarerImpl`](#AccountComponent-Embeddable-Impls-DeclarerImpl)
+- [`DeployableImpl`](#AccountComponent-Embeddable-Impls-DeployableImpl)
+- [`PublicKeyImpl`](#AccountComponent-Embeddable-Impls-PublicKeyImpl)
+- [`SRC6CamelOnlyImpl`](#AccountComponent-Embeddable-Impls-SRC6CamelOnlyImpl)
+- [`PublicKeyCamelImpl`](#AccountComponent-Embeddable-Impls-PublicKeyCamelImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### SRC6Impl [!toc] [#AccountComponent-Embeddable-Impls-SRC6Impl]
+
+- [`__execute__(self, calls)`](#AccountComponent-__execute__)
+- [`__validate__(self, calls)`](#AccountComponent-__validate__)
+- [`is_valid_signature(self, hash, signature)`](#AccountComponent-is_valid_signature)
+
+#### DeclarerImpl [!toc] [#AccountComponent-Embeddable-Impls-DeclarerImpl]
+
+- [`__validate_declare__(self, class_hash)`](#AccountComponent-__validate_declare__)
+
+#### DeployableImpl [!toc] [#AccountComponent-Embeddable-Impls-DeployableImpl]
+
+- [`__validate_deploy__(self, hash, signature)`](#AccountComponent-__validate_deploy__)
+
+#### PublicKeyImpl [!toc] [#AccountComponent-Embeddable-Impls-PublicKeyImpl]
+
+- [`get_public_key(self)`](#AccountComponent-get_public_key)
+- [`set_public_key(self, new_public_key, signature)`](#AccountComponent-set_public_key)
+
+#### SRC6CamelOnlyImpl [!toc] [#AccountComponent-Embeddable-Impls-SRC6CamelOnlyImpl]
+
+- [`isValidSignature(self, hash, signature)`](#AccountComponent-isValidSignature)
+
+#### PublicKeyCamelImpl [!toc] [#AccountComponent-Embeddable-Impls-PublicKeyCamelImpl]
+
+- [`getPublicKey(self)`](#AccountComponent-getPublicKey)
+- [`setPublicKey(self, newPublicKey, signature)`](#AccountComponent-setPublicKey)
+
+#### SRC5Impl [!toc] [#AccountComponent-Embeddable-Impls-SRC5Impl]
+
+- [`supports_interface(self, interface_id: felt252)`](./introspection#ISRC5-supports_interface)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#AccountComponent-InternalImpl]
+
+- [`initializer(self, public_key)`](#AccountComponent-initializer)
+- [`assert_only_self(self)`](#AccountComponent-assert_only_self)
+- [`assert_valid_new_owner(self, current_owner, new_owner, signature)`](#AccountComponent-assert_valid_new_owner)
+- [`validate_transaction(self)`](#AccountComponent-validate_transaction)
+- [`_set_public_key(self, new_public_key)`](#AccountComponent-_set_public_key)
+- [`_is_valid_signature(self, hash, signature)`](#AccountComponent-_is_valid_signature)
+
+Events
+
+- [`OwnerAdded(new_owner_guid)`](#AccountComponent-OwnerAdded)
+- [`OwnerRemoved(removed_owner_guid)`](#AccountComponent-OwnerRemoved)
+
+#### Embeddable functions [!toc] [#AccountComponent-Embeddable-Functions]
+
+
+See [ISRC6::\_\_execute\_\_](#ISRC6-__execute__).
+
+
+
+See [ISRC6::\_\_validate\_\_](#ISRC6-__validate__).
+
+
+
+See [ISRC6::is\_valid\_signature](#ISRC6-is_valid_signature).
+
+
+
+Validates a [`Declare` transaction](https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#declare-transaction).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Validates a [`DeployAccount` transaction](https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#deploy_account_transaction). See [Counterfactual Deployments](../guides/deployment).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Returns the current public key of the account.
+
+
+
+Sets a new public key for the account. Only accessible by the account calling itself through `__execute__`.
+
+Requirements:
+
+- The caller must be the contract itself.
+- The signature must be valid for the new owner.
+
+Emits both an [OwnerRemoved](#AccountComponent-OwnerRemoved) and an [OwnerAdded](#AccountComponent-OwnerAdded) event.
+
+The message to be signed is computed in Cairo as follows:
+
+```javascript
+let message_hash = PoseidonTrait::new()
+ .update_with('StarkNet Message')
+ .update_with('accept_ownership')
+ .update_with(get_contract_address())
+ .update_with(current_owner)
+ .finalize();
+```
+
+
+
+See [ISRC6::is\_valid\_signature](#ISRC6-is_valid_signature).
+
+
+
+See [get\_public\_key](#AccountComponent-get_public_key).
+
+
+
+See [set\_public\_key](#AccountComponent-set_public_key).
+
+
+#### Internal functions [!toc] [#AccountComponent-Internal-Functions]
+
+
+Initializes the account with the given public key, and registers the `ISRC6` interface ID.
+
+Emits an [OwnerAdded](#AccountComponent-OwnerAdded) event.
+
+
+
+Validates that the caller is the account itself. Otherwise it reverts.
+
+
+
+Validates that `new_owner` accepted the ownership of the contract through a signature.
+
+Requirements:
+
+- `signature` must be valid for the new owner.
+
+This function assumes that `current_owner` is the current owner of the contract, and does not validate this assumption.
+
+
+
+Validates a transaction signature from the [global context](https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/info.cairo#L61).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Set the public key without validating the caller.
+
+Emits an [OwnerAdded](#AccountComponent-OwnerAdded) event.
+
+The usage of this method outside the `set_public_key` function is discouraged.
+
+
+
+Validates the provided `signature` for the `hash`, using the account's current public key.
+
+
+#### Events [!toc] [#AccountComponent-Events]
+
+
+Emitted when a `public_key` is added.
+
+
+
+Emitted when a `public_key` is removed.
+
+
+### `EthAccountComponent` [toc] [#EthAccountComponent]
+
+
+```rust
+use openzeppelin_account::eth_account::EthAccountComponent;
+```
+
+Account component implementing [`ISRC6`](#ISRC6) for signatures over the [Secp256k1 curve](https://en.bitcoin.it/wiki/Secp256k1).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+The `EthPublicKey` type is an alias for `starknet::secp256k1::Secp256k1Point`.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### EthAccountMixinImpl [!toc] [#EthAccountComponent-Embeddable-Impls-EthAccountMixinImpl]
+
+- [`SRC6Impl`](#EthAccountComponent-Embeddable-Impls-SRC6Impl)
+- [`DeclarerImpl`](#EthAccountComponent-Embeddable-Impls-DeclarerImpl)
+- [`DeployableImpl`](#EthAccountComponent-Embeddable-Impls-DeployableImpl)
+- [`PublicKeyImpl`](#EthAccountComponent-Embeddable-Impls-PublicKeyImpl)
+- [`SRC6CamelOnlyImpl`](#EthAccountComponent-Embeddable-Impls-SRC6CamelOnlyImpl)
+- [`PublicKeyCamelImpl`](#EthAccountComponent-Embeddable-Impls-PublicKeyCamelImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### SRC6Impl [!toc] [#EthAccountComponent-Embeddable-Impls-SRC6Impl]
+
+- [`__execute__(self, calls)`](#EthAccountComponent-__execute__)
+- [`__validate__(self, calls)`](#EthAccountComponent-__validate__)
+- [`is_valid_signature(self, hash, signature)`](#EthAccountComponent-is_valid_signature)
+
+#### DeclarerImpl [!toc] [#EthAccountComponent-Embeddable-Impls-DeclarerImpl]
+
+- [`__validate_declare__(self, class_hash)`](#EthAccountComponent-__validate_declare__)
+
+#### DeployableImpl [!toc] [#EthAccountComponent-Embeddable-Impls-DeployableImpl]
+
+- [`__validate_deploy__(self, hash, signature)`](#EthAccountComponent-__validate_deploy__)
+
+#### PublicKeyImpl [!toc] [#EthAccountComponent-Embeddable-Impls-PublicKeyImpl]
+
+- [`get_public_key(self)`](#EthAccountComponent-get_public_key)
+- [`set_public_key(self, new_public_key, signature)`](#EthAccountComponent-set_public_key)
+
+#### SRC6CamelOnlyImpl [!toc] [#EthAccountComponent-Embeddable-Impls-SRC6CamelOnlyImpl]
+
+- [`isValidSignature(self, hash, signature)`](#EthAccountComponent-isValidSignature)
+
+#### PublicKeyCamelImpl [!toc] [#EthAccountComponent-Embeddable-Impls-PublicKeyCamelImpl]
+
+- [`getPublicKey(self)`](#EthAccountComponent-getPublicKey)
+- [`setPublicKey(self, newPublicKey, signature)`](#EthAccountComponent-setPublicKey)
+
+#### SRC5Impl [!toc] [#EthAccountComponent-Embeddable-Impls-SRC5Impl]
+
+- [`supports_interface(self, interface_id: felt252)`](./introspection#ISRC5-supports_interface)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#EthAccountComponent-InternalImpl]
+
+- [`initializer(self, public_key)`](#EthAccountComponent-initializer)
+- [`assert_only_self(self)`](#EthAccountComponent-assert_only_self)
+- [`assert_valid_new_owner(self, current_owner, new_owner, signature)`](#EthAccountComponent-assert_valid_new_owner)
+- [`validate_transaction(self)`](#EthAccountComponent-validate_transaction)
+- [`_set_public_key(self, new_public_key)`](#EthAccountComponent-_set_public_key)
+- [`_is_valid_signature(self, hash, signature)`](#EthAccountComponent-_is_valid_signature)
+
+Events
+
+- [`OwnerAdded(new_owner_guid)`](#EthAccountComponent-OwnerAdded)
+- [`OwnerRemoved(removed_owner_guid)`](#EthAccountComponent-OwnerRemoved)
+
+#### Embeddable functions [!toc] [#EthAccountComponent-Embeddable-Functions]
+
+
+See [ISRC6::\_\_execute\_\_](#ISRC6-__execute__).
+
+
+
+See [ISRC6::\_\_validate\_\_](#ISRC6-__validate__).
+
+
+
+See [ISRC6::is\_valid\_signature](#ISRC6-is_valid_signature).
+
+
+
+Validates a [`Declare` transaction](https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#declare-transaction).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Validates a [`DeployAccount` transaction](https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#deploy_account_transaction). See [Counterfactual Deployments](../guides/deployment).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Returns the current public key of the account.
+
+
+
+Sets a new public key for the account. Only accessible by the account calling itself through `__execute__`.
+
+Requirements:
+
+- The caller must be the contract itself.
+- The signature must be valid for the new owner.
+
+Emits both an [OwnerRemoved](#EthAccountComponent-OwnerRemoved) and an [OwnerAdded](#EthAccountComponent-OwnerAdded) event.
+
+The message to be signed is computed in Cairo as follows:
+
+```javascript
+let message_hash = PoseidonTrait::new()
+ .update_with('StarkNet Message')
+ .update_with('accept_ownership')
+ .update_with(get_contract_address())
+ .update_with(current_owner.get_coordinates().unwrap_syscall())
+ .finalize();
+```
+
+
+
+See [ISRC6::is\_valid\_signature](#ISRC6-is_valid_signature).
+
+
+
+See [get\_public\_key](#EthAccountComponent-get_public_key).
+
+
+
+See [set\_public\_key](#EthAccountComponent-set_public_key).
+
+
+#### Internal functions [!toc] [#EthAccountComponent-Internal-Functions]
+
+
+Initializes the account with the given public key, and registers the `ISRC6` interface ID.
+
+Emits an [OwnerAdded](#EthAccountComponent-OwnerAdded) event.
+
+
+
+Validates that the caller is the account itself. Otherwise it reverts.
+
+
+
+Validates that `new_owner` accepted the ownership of the contract through a signature.
+
+Requirements:
+
+- The signature must be valid for the `new_owner`.
+
+This function assumes that `current_owner` is the current owner of the contract, and does not validate this assumption.
+
+
+
+Validates a transaction signature from the [global context](https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/info.cairo#L61).
+
+Returns the short string `'VALID'` if valid, otherwise it reverts.
+
+
+
+Set the public key without validating the caller.
+
+Emits an [OwnerAdded](#EthAccountComponent-OwnerAdded) event.
+
+The usage of this method outside the `set_public_key` function is discouraged.
+
+
+
+Validates the provided `signature` for the `hash`, using the account's current public key.
+
+
+#### Events [!toc] [#EthAccountComponent-Events]
+
+The `guid` is computed as the hash of the public key, using the poseidon hash function.
+
+
+Emitted when a `public_key` is added.
+
+
+
+Emitted when a `public_key` is removed.
+
+
+## Extensions
+
+### `SRC9Component` [toc] [#SRC9Component]
+
+
+```rust
+use openzeppelin_account::extensions::SRC9Component;
+```
+
+OutsideExecution component implementing [`ISRC9_V2`](#ISRC9_V2).
+
+This component is signature-agnostic, meaning it can be integrated into any account contract, as long as the account implements the ISRC6 interface.
+
+Embeddable Implementations
+
+#### OutsideExecutionV2Impl [!toc] [#SRC9Component-Embeddable-Impls-OutsideExecutionV2Impl]
+
+- [`execute_from_outside_v2(self, outside_execution, signature)`](#SRC9Component-execute_from_outside_v2)
+- [`is_valid_outside_execution_nonce(self, nonce)`](#SRC9Component-is_valid_outside_execution_nonce)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#SRC9Component-InternalImpl]
+
+- [`initializer(self)`](#SRC9Component-initializer)
+
+#### Embeddable functions [!toc] [#SRC9Component-Embeddable-Functions]
+
+
+Allows anyone to submit a transaction on behalf of the account as long as they have the relevant signatures.
+
+This method allows reentrancy. A call to `__execute__` or `execute_from_outside_v2` can trigger another nested transaction to `execute_from_outside_v2`. This implementation verifies that the provided `signature` matches the hash of `outside_execution` and that `nonce` was not already used.
+
+Arguments:
+
+- `outside_execution` - The parameters of the transaction to execute.
+- `signature` - A valid signature on the [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) message encoding of `outside_execution`.
+
+Requirements:
+
+- The caller must be the `outside_execution.caller` unless 'ANY\_CALLER' is used.
+- The current time must be within the `outside_execution.execute_after` and `outside_execution.execute_before` span.
+- The `outside_execution.nonce` must not be used before.
+- The `signature` must be valid.
+
+
+
+Returns the status of a given nonce. `true` if the nonce is available to use.
+
+
+#### Internal functions [!toc] [#SRC9Component-Internal-Functions]
+
+
+Initializes the account by registering the `ISRC9_V2` interface ID.
+
+
+## Presets
+
+### `AccountUpgradeable` [toc] [#AccountUpgradeable]
+
+
+```rust
+use openzeppelin_presets::AccountUpgradeable;
+```
+
+Upgradeable account which can change its public key and declare, deploy, or call contracts. Supports outside execution by implementing [SRC9](#SRC9Component).
+
+[Sierra class hash](../presets)
+
+```text
+{{AccountUpgradeableClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, public_key)`](#AccountUpgradeable-constructor)
+
+Embedded Implementations
+
+AccountComponent
+
+- [`AccountMixinImpl`](#AccountComponent-Embeddable-Mixin-Impl)
+
+SRC9Component
+
+- [`OutsideExecutionV2Impl`](#SRC9Component-Embeddable-Impls-OutsideExecutionV2Impl)
+
+External Functions
+
+- [`upgrade(self, new_class_hash)`](#AccountUpgradeable-upgrade)
+
+#### Constructor [!toc] [#AccountUpgradeable-Constructor]
+
+
+Sets the account `public_key` and registers the interfaces the contract supports.
+
+
+#### External functions [!toc] [#AccountUpgradeable-External-Functions]
+
+
+Upgrades the contract to a new implementation given by `new_class_hash`.
+
+Requirements:
+
+- The caller is the account contract itself.
+- `new_class_hash` cannot be zero.
+
+
+### `EthAccountUpgradeable` [toc] [#EthAccountUpgradeable]
+
+
+```rust
+use openzeppelin_presets::EthAccountUpgradeable;
+```
+
+Upgradeable account which can change its public key and declare, deploy, or call contracts, using Ethereum signing keys. Supports outside execution by implementing [SRC9](#SRC9Component).
+
+The `EthPublicKey` type is an alias for `starknet::secp256k1::Secp256k1Point`.
+
+[Sierra class hash](../presets)
+
+```text
+{{EthAccountUpgradeableClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, public_key)`](#EthAccountUpgradeable-constructor)
+
+Embedded Implementations
+
+EthAccountComponent
+
+- [`EthAccountMixinImpl`](#EthAccountComponent-Embeddable-Mixin-Impl)
+
+SRC9Component
+
+- [`OutsideExecutionV2Impl`](#SRC9Component-Embeddable-Impls-OutsideExecutionV2Impl)
+
+External Functions
+
+- [`upgrade(self, new_class_hash)`](#EthAccountUpgradeable-upgrade)
+
+#### Constructor [!toc] [#EthAccountUpgradeable-Constructor]
+
+
+Sets the account `public_key` and registers the interfaces the contract supports.
+
+
+#### External functions [!toc] [#EthAccountUpgradeable-External-Functions]
+
+
+Upgrades the contract to a new implementation given by `new_class_hash`.
+
+Requirements:
+
+- The caller is the account contract itself.
+- `new_class_hash` cannot be zero.
+
diff --git a/docs/content/contracts-cairo/2.x/api/erc1155.mdx b/docs/content/contracts-cairo/2.x/api/erc1155.mdx
new file mode 100644
index 00000000..8526aaea
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/erc1155.mdx
@@ -0,0 +1,783 @@
+---
+title: ERC1155
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This module provides interfaces, presets, and utilities related to ERC1155 contracts.
+
+For an overview of ERC1155, read our [ERC1155 guide](../erc1155).
+
+## Interfaces
+
+### `IERC1155` [toc] [#IERC1155]
+
+
+
+```rust
+use openzeppelin_token::erc1155::interface::IERC1155;
+```
+
+Interface of the IERC1155 standard as defined in [EIP1155](https://eips.ethereum.org/EIPS/eip-1155).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x6114a8f75559e1b39fcba08ce02961a1aa082d9256a158dd3e64964e4b1b52
+```
+
+Functions
+
+- [`balance_of(account, token_id)`](#IERC1155-balance_of)
+- [`balance_of_batch(accounts, token_ids)`](#IERC1155-balance_of_batch)
+- [`safe_transfer_from(from, to, token_id, value, data)`](#IERC1155-safe_transfer_from)
+- [`safe_batch_transfer_from(from, to, token_ids, values, data)`](#IERC1155-safe_batch_transfer_from)
+- [`set_approval_for_all(operator, approved)`](#IERC1155-set_approval_for_all)
+- [`is_approved_for_all(owner, operator)`](#IERC1155-is_approved_for_all)
+
+Events
+
+- [`TransferSingle(operator, from, to, id, value)`](#IERC1155-TransferSingle)
+- [`TransferBatch(operator, from, to, ids, values)`](#IERC1155-TransferBatch)
+- [`ApprovalForAll(owner, operator, approved)`](#IERC1155-ApprovalForAll)
+- [`URI(value, id)`](#IERC1155-URI)
+
+#### Functions [!toc] [#functions]
+
+
+Returns the amount of `token_id` tokens owned by `account`.
+
+
+
+Returns a list of balances derived from the `accounts` and `token_ids` pairs.
+
+
+
+Transfers ownership of `value` amount of `token_id` from `from` if `to` is either `IERC1155Receiver` or an account.
+
+`data` is additional data, it has no specified format and it is passed to `to`.
+
+Emits a [TransferSingle](#IERC1155-TransferSingle) event.
+
+
+
+Transfers ownership of `token_ids` and `values` pairs from `from` if `to` is either `IERC1155Receiver` or an account.
+
+`data` is additional data, it has no specified format and it is passed to `to`.
+
+Emits a [TransferBatch](#IERC1155-TransferBatch) event.
+
+
+
+Enables or disables approval for `operator` to manage all of the caller's assets.
+
+Emits an [ApprovalForAll](#IERC1155-ApprovalForAll) event.
+
+
+
+Queries if `operator` is an authorized operator for `owner`.
+
+
+#### Events [!toc] [#events]
+
+
+Emitted when `value` amount of `id` token is transferred from `from` to `to` through `operator`.
+
+
+
+Emitted when a batch of `values` amount of `ids` tokens are transferred from `from` to `to` through `operator`.
+
+
+
+Emitted when `owner` enables or disables `operator` to manage all of the owner's assets.
+
+
+
+Emitted when the token URI is updated to `value` for the `id` token.
+
+
+### `IERC1155MetadataURI` [toc] [#IERC1155MetadataURI]
+
+
+
+```rust
+use openzeppelin_token::erc1155::interface::IERC1155MetadataURI;
+```
+
+Interface for the optional metadata function in [EIP1155](https://eips.ethereum.org/EIPS/eip-1155#metadata).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0xcabe2400d5fe509e1735ba9bad205ba5f3ca6e062da406f72f113feb889ef7
+```
+
+Functions
+
+- [`uri(token_id)`](#IERC1155MetadataURI-uri)
+
+#### Functions [!toc] [#functions_2]
+
+
+Returns the Uniform Resource Identifier (URI) for the `token_id` token.
+
+
+### `IERC1155Receiver` [toc] [#IERC1155Receiver]
+
+
+
+```rust
+use openzeppelin_token::erc1155::interface::IERC1155Receiver;
+```
+
+Interface for contracts that support receiving token transfers from `ERC1155` contracts.
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x15e8665b5af20040c3af1670509df02eb916375cdf7d8cbaf7bd553a257515e
+```
+
+Functions
+
+- [`on_erc1155_received(operator, from, token_id, value, data)`](#IERC1155Receiver-on_erc1155_received)
+- [`on_erc1155_batch_received(operator, from, token_ids, values, data)`](#IERC1155Receiver-on_erc1155_batch_received)
+
+#### Functions [!toc] [#functions_3]
+
+
+This function is called whenever an ERC1155 `token_id` token is transferred to this `IERC1155Receiver` implementer via [IERC1155::safe\_transfer\_from](#IERC1155-safe_transfer_from) by `operator` from `from`.
+
+
+
+This function is called whenever multiple ERC1155 `token_ids` tokens are transferred to this `IERC1155Receiver` implementer via [IERC1155::safe\_batch\_transfer\_from](#IERC1155-safe_batch_transfer_from) by `operator` from `from`.
+
+
+## [](#core)Core
+
+### `ERC1155Component` [toc] [#ERC1155Component]
+
+
+
+```rust
+use openzeppelin_token::erc1155::ERC1155Component;
+```
+
+ERC1155 component implementing [IERC1155](#IERC1155) and [IERC1155MetadataURI](#IERC1155MetadataURI).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+See [Hooks](#ERC1155Component-Hooks) to understand how are hooks used.
+
+#### Hooks [!toc] [#ERC1155Component-Hooks]
+
+#### ERC1155HooksTrait [!toc] [#ERC1155Component-ERC1155HooksTrait]
+
+- [`before_update(self, from, to, token_ids, values)`](#ERC1155Component-before_update)
+- [`after_update(self, from, to, token_ids, values)`](#ERC1155Component-after_update)
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### ERC1155MixinImpl [!toc] [#ERC1155Component-Embeddable-Impls-ERC1155MixinImpl]
+
+- [`ERC1155Impl`](#ERC1155Component-Embeddable-Impls-ERC1155Impl)
+- [`ERC1155MetadataURIImpl`](#ERC1155Component-Embeddable-Impls-ERC1155MetadataURIImpl)
+- [`ERC1155CamelImpl`](#ERC1155Component-Embeddable-Impls-ERC1155CamelImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls-SRC5Impl)
+
+Embeddable Implementations
+
+#### ERC1155Impl [!toc] [#ERC1155Component-Embeddable-Impls-ERC1155Impl]
+
+- [`balance_of(self, account, token_id)`](#ERC1155Component-balance_of)
+- [`balance_of_batch(self, accounts, token_ids)`](#ERC1155Component-balance_of_batch)
+- [`safe_transfer_from(self, from, to, token_id, value, data)`](#ERC1155Component-safe_transfer_from)
+- [`safe_batch_transfer_from(self, from, to, token_ids, values, data)`](#ERC1155Component-safe_batch_transfer_from)
+- [`set_approval_for_all(self, operator, approved)`](#ERC1155Component-set_approval_for_all)
+- [`is_approved_for_all(self, owner, operator)`](#ERC1155Component-is_approved_for_all)
+
+#### ERC1155MetadataURIImpl [!toc] [#ERC1155Component-Embeddable-Impls-ERC1155MetadataURIImpl]
+
+- [`uri(self, token_id)`](#ERC1155Component-uri)
+
+#### ERC1155CamelImpl [!toc] [#ERC1155Component-Embeddable-Impls-ERC1155CamelImpl]
+
+- [`balanceOf(self, account, tokenId)`](#ERC1155Component-balanceOf)
+- [`balanceOfBatch(self, accounts, tokenIds)`](#ERC1155Component-balanceOfBatch)
+- [`safeTransferFrom(self, from, to, tokenId, value, data)`](#ERC1155Component-safeTransferFrom)
+- [`safeBatchTransferFrom(self, from, to, tokenIds, values, data)`](#ERC1155Component-safeBatchTransferFrom)
+- [`setApprovalForAll(self, operator, approved)`](#ERC1155Component-setApprovalForAll)
+- [`isApprovedForAll(self, owner, operator)`](#ERC1155Component-isApprovedForAll)
+
+Internal Functions
+
+#### InternalImpl [!toc] [#ERC1155Component-InternalImpl]
+
+- [`initializer(self, base_uri)`](#ERC1155Component-initializer)
+- [`initializer_no_metadata(self)`](#ERC1155Component-initializer_no_metadata)
+- [`mint_with_acceptance_check(self, to, token_id, value, data)`](#ERC1155Component-mint_with_acceptance_check)
+- [`batch_mint_with_acceptance_check(self, to, token_ids, values, data)`](#ERC1155Component-batch_mint_with_acceptance_check)
+- [`burn(self, from, token_id, value)`](#ERC1155Component-burn)
+- [`batch_burn(self, from, token_ids, values)`](#ERC1155Component-batch_burn)
+- [`update_with_acceptance_check(self, from, to, token_ids, values, data)`](#ERC1155Component-update_with_acceptance_check)
+- [`update(self, from, to, token_ids, values)`](#ERC1155Component-update)
+- [`_set_base_uri(self, base_uri)`](#ERC1155Component-_set_base_uri)
+
+Events
+
+IERC1155
+
+- [`TransferSingle(operator, from, to, id, value)`](#ERC1155Component-TransferSingle)
+- [`TransferBatch(operator, from, to, ids, values)`](#ERC1155Component-TransferBatch)
+- [`ApprovalForAll(owner, operator, approved)`](#ERC1155Component-ApprovalForAll)
+- [`URI(value, id)`](#ERC1155Component-URI)
+
+Hooks are functions which implementations can extend the functionality of the component source code. Every contract using ERC1155Component is expected to provide an implementation of the ERC1155HooksTrait. For basic token contracts, an empty implementation with no logic must be provided.
+
+You can use `openzeppelin_token::erc1155::ERC1155HooksEmptyImpl` which is already available as part of the library for this purpose.
+
+
+Function executed at the beginning of the [update](#ERC1155Component-update) function prior to any other logic.
+
+
+
+Function executed at the end of the [update](#ERC1155Component-update) function.
+
+
+#### Embeddable functions [!toc] [#embeddable_functions]
+
+
+Returns the amount of `token_id` tokens owned by `account`.
+
+
+
+Returns a list of balances derived from the `accounts` and `token_ids` pairs.
+
+Requirements:
+
+- `token_ids` and `accounts` must have the same length.
+
+
+
+Transfers ownership of `value` amount of `token_id` from `from` if `to` is either an account or `IERC1155Receiver`.
+
+`data` is additional data, it has no specified format and it is passed to `to`.
+
+This function can potentially allow a reentrancy attack when transferring tokens to an untrusted contract, when invoking `on_ERC1155_received` on the receiver. Ensure to follow the checks-effects-interactions pattern and consider employing reentrancy guards when interacting with untrusted contracts.
+
+Requirements:
+
+- Caller is either approved or the `token_id` owner.
+- `from` is not the zero address.
+- `to` is not the zero address.
+- If `to` refers to a non-account contract, it must implement `IERC1155Receiver::on_ERC1155_received` and return the required magic value.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event.
+
+
+
+Transfers ownership of `values` and `token_ids` pairs from `from` if `to` is either an account or `IERC1155Receiver`.
+
+`data` is additional data, it has no specified format and it is passed to `to`.
+
+This function can potentially allow a reentrancy attack when transferring tokens to an untrusted contract, when invoking `on_ERC1155_batch_received` on the receiver. Ensure to follow the checks-effects-interactions pattern and consider employing reentrancy guards when interacting with untrusted contracts.
+
+Requirements:
+
+- Caller is either approved or the `token_id` owner.
+- `from` is not the zero address.
+- `to` is not the zero address.
+- `token_ids` and `values` must have the same length.
+- If `to` refers to a non-account contract, it must implement `IERC1155Receiver::on_ERC1155_batch_received` and return the acceptance magic value.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event if the arrays contain one element, and [TransferBatch](#ERC1155Component-TransferBatch) otherwise.
+
+
+
+Enables or disables approval for `operator` to manage all of the callers assets.
+
+Requirements:
+
+- `operator` cannot be the caller.
+
+Emits an [ApprovalForAll](#ERC1155Component-ApprovalForAll) event.
+
+
+
+Queries if `operator` is an authorized operator for `owner`.
+
+
+
+
+This implementation returns the same URI for **all** token types. It relies on the token type ID substitution mechanism [specified in the EIP](https://eips.ethereum.org/EIPS/eip-1155#metadata).
+
+Clients calling this function must replace the `id` substring with the actual token type ID.
+
+
+
+See [ERC1155Component::balance\_of](#ERC1155Component-balance_of).
+
+
+
+See [ERC1155Component::balance\_of\_batch](#ERC1155Component-balance_of_batch).
+
+
+
+See [ERC1155Component::safe\_transfer\_from](#ERC1155Component-safe_transfer_from).
+
+
+
+See [ERC1155Component::safe\_batch\_transfer\_from](#ERC1155Component-safe_batch_transfer_from).
+
+
+
+See [ERC1155Component::set\_approval\_for\_all](#ERC1155Component-set_approval_for_all).
+
+
+
+See [ERC1155Component::is\_approved\_for\_all](#ERC1155Component-is_approved_for_all).
+
+
+#### Internal functions [!toc] [#internal_functions]
+
+
+Initializes the contract by setting the token's base URI as `base_uri`, and registering the supported interfaces. This should only be used inside the contract's constructor.
+
+Most ERC1155 contracts expose the [IERC1155MetadataURI](#IERC1155MetadataURI) interface which is what this initializer is meant to support. If the contract DOES NOT expose the [IERC1155MetadataURI](#IERC1155MetadataURI) interface, meaning tokens do not have a URI, the contract must instead use [initializer\_no\_metadata](#ERC1155Component-initializer_no_metadata) in the constructor. Failure to abide by these instructions can lead to unexpected issues especially with UIs.
+
+
+
+Initializes the contract with no metadata by registering only the IERC1155 interface.
+
+This initializer should ONLY be used during construction in the very specific instance when the contract does NOT expose the [IERC1155MetadataURI](#IERC1155MetadataURI) interface. Initializing a contract with this initializer means that tokens will not have a URI.
+
+
+
+Creates a `value` amount of tokens of type `token_id`, and assigns them to `to`.
+
+Requirements:
+
+- `to` cannot be the zero address.
+- If `to` refers to a smart contract, it must implement `IERC1155Receiver::on_ERC1155_received` and return the acceptance magic value.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event.
+
+
+
+Batched version of [mint\_with\_acceptance\_check](#ERC1155Component-mint_with_acceptance_check).
+
+Requirements:
+
+- `to` cannot be the zero address.
+- `token_ids` and `values` must have the same length.
+- If `to` refers to a smart contract, it must implement `IERC1155Receiver::on_ERC1155_batch_received` and return the acceptance magic value.
+
+Emits a [TransferBatch](#ERC1155Component-TransferBatch) event.
+
+
+
+Destroys a `value` amount of tokens of type `token_id` from `from`.
+
+Requirements:
+
+- `from` cannot be the zero address.
+- `from` must have at least `value` amount of tokens of type `token_id`.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event.
+
+
+
+Batched version of [burn](#ERC1155Component-burn).
+
+Requirements:
+
+- `from` cannot be the zero address.
+- `from` must have at least `value` amount of tokens of type `token_id`.
+- `token_ids` and `values` must have the same length.
+
+Emits a [TransferBatch](#ERC1155Component-TransferBatch) event.
+
+
+
+Version of `update` that performs the token acceptance check by calling `onERC1155Received` or `onERC1155BatchReceived` in the receiver if it implements `IERC1155Receiver`, otherwise by checking if it is an account.
+
+Requirements:
+
+- `to` is either an account contract or supports the `IERC1155Receiver` interface.
+- `token_ids` and `values` must have the same length.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event if the arrays contain one element, and [TransferBatch](#ERC1155Component-TransferBatch) otherwise.
+
+
+
+Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` (or `to`) is the zero address.
+
+Requirements:
+
+- `token_ids` and `values` must have the same length.
+
+Emits a [TransferSingle](#ERC1155Component-TransferSingle) event if the arrays contain one element, and [TransferBatch](#ERC1155Component-TransferBatch) otherwise.
+
+This function can be extended using the [ERC1155HooksTrait](#ERC1155Component-ERC1155HooksTrait), to add functionality before and/or after the transfer, mint, or burn.
+
+The ERC1155 acceptance check is not performed in this function. See [update\_with\_acceptance\_check](#ERC1155Component-update_with_acceptance_check) instead.
+
+
+
+Sets a new URI for all token types, by relying on the token type ID substitution mechanism [specified in the EIP](https://eips.ethereum.org/EIPS/eip-1155#metadata).
+
+By this mechanism, any occurrence of the `id` substring in either the URI or any of the values in the JSON file at said URI will be replaced by clients with the token type ID.
+
+For example, the `https://token-cdn-domain/\id\.json` URI would be interpreted by clients as `https://token-cdn-domain/000000000000...000000000000004cce0.json` for token type ID `0x4cce0`.
+
+Because these URIs cannot be meaningfully represented by the `URI` event, this function emits no events.
+
+
+#### Events [!toc] [#events_2]
+
+
+See [IERC1155::TransferSingle](#IERC1155-TransferSingle).
+
+
+
+See [IERC1155::TransferBatch](#IERC1155-TransferBatch).
+
+
+
+See [IERC1155::ApprovalForAll](#IERC1155-ApprovalForAll).
+
+
+
+
+See [IERC1155::URI](#IERC1155-URI).
+
+
+### `ERC1155ReceiverComponent` [toc] [#ERC1155ReceiverComponent]
+
+
+
+```rust
+use openzeppelin_token::erc1155::ERC1155ReceiverComponent;
+```
+
+ERC1155Receiver component implementing [IERC1155Receiver](#IERC1155Receiver).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### ERC1155MixinImpl [!toc] [#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155MixinImpl]
+
+- [`ERC1155ReceiverImpl`](#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverImpl)
+- [`ERC1155ReceiverCamelImpl`](#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverCamelImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls-SRC5Impl)
+
+Embeddable Implementations
+
+#### ERC1155ReceiverImpl [!toc] [#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverImpl]
+
+- [`on_erc1155_received(self, operator, from, token_id, value, data)`](#ERC1155ReceiverComponent-on_erc1155_received)
+- [`on_erc1155_batch_received(self, operator, from, token_ids, values, data)`](#ERC1155ReceiverComponent-on_erc1155_batch_received)
+
+#### ERC1155ReceiverCamelImpl [!toc] [#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverCamelImpl]
+
+- [`onERC1155Received(self, operator, from, tokenId, value, data)`](#ERC1155ReceiverComponent-onERC1155Received)
+- [`onERC1155BatchReceived(self, operator, from, tokenIds, values, data)`](#ERC1155ReceiverComponent-onERC1155BatchReceived)
+
+Internal Functions
+
+#### InternalImpl [!toc] [#ERC1155ReceiverComponent-InternalImpl]
+
+- [`initializer(self)`](#ERC1155ReceiverComponent-initializer)
+
+#### Embeddable functions [!toc] [#embeddable_functions_2]
+
+
+Returns the `IERC1155Receiver` interface ID.
+
+
+
+Returns the `IERC1155Receiver` interface ID.
+
+
+
+See [ERC1155ReceiverComponent::on\_erc1155\_received](#ERC1155ReceiverComponent-on_erc1155_received).
+
+
+
+See [ERC1155ReceiverComponent::on\_erc1155\_batch\_received](#ERC1155ReceiverComponent-on_erc1155_batch_received).
+
+
+#### Internal functions [!toc] [#internal_functions_2]
+
+
+Registers the `IERC1155Receiver` interface ID as supported through introspection.
+
+
+## [](#presets)Presets
+
+### `ERC1155Upgradeable` [toc] [#ERC1155Upgradeable]
+
+
+
+```rust
+use openzeppelin_presets::ERC1155;
+```
+
+Upgradeable ERC1155 contract leveraging [ERC1155Component](#ERC1155Component).
+
+[Sierra class hash](../presets)
+
+```text
+{{ERC1155UpgradeableClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, base_uri, recipient, token_ids, values, owner)`](#ERC1155Upgradeable-constructor)
+
+Embedded Implementations
+
+ERC1155Component
+
+- [`ERC1155MixinImpl`](#ERC1155Component-Embeddable-Mixin-Impl)
+
+OwnableMixinImpl
+
+- [`OwnableMixinImpl`](./access#OwnableComponent-Mixin-Impl)
+
+External Functions
+
+- [`upgrade(self, new_class_hash)`](#ERC1155Upgradeable-upgrade)
+
+#### Constructor [!toc] [#ERC1155Upgradeable-constructor-section]
+
+
+Sets the `base_uri` for all tokens and registers the supported interfaces. Mints the `values` for `token_ids` tokens to `recipient`. Assigns `owner` as the contract owner with permissions to upgrade.
+
+Requirements:
+
+- `to` is either an account contract (supporting ISRC6) or supports the `IERC1155Receiver` interface.
+- `token_ids` and `values` must have the same length.
+
+
+#### External Functions [!toc] [#ERC1155Upgradeable-external-functions]
+
+
+Upgrades the contract to a new implementation given by `new_class_hash`.
+
+Requirements:
+
+- The caller is the contract owner.
+- `new_class_hash` cannot be zero.
+
diff --git a/docs/content/contracts-cairo/2.x/api/erc20.mdx b/docs/content/contracts-cairo/2.x/api/erc20.mdx
new file mode 100644
index 00000000..08678751
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/erc20.mdx
@@ -0,0 +1,1580 @@
+---
+title: ERC20
+---
+
+This module provides interfaces, presets, and utilities related to ERC20 contracts.
+
+For an overview of ERC20, read our [ERC20 guide](../erc20).
+
+## Interfaces
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+### `IERC20` [toc] [#IERC20]
+
+
+```rust
+use openzeppelin_token::erc20::interface::IERC20;
+```
+
+Interface of the IERC20 standard as defined in [EIP-20](https://eips.ethereum.org/EIPS/eip-20).
+
+Functions
+
+- [`total_supply()`](#IERC20-total_supply)
+- [`balance_of(account)`](#IERC20-balance_of)
+- [`allowance(owner, spender)`](#IERC20-allowance)
+- [`transfer(recipient, amount)`](#IERC20-transfer)
+- [`transfer_from(sender, recipient, amount)`](#IERC20-transfer_from)
+- [`approve(spender, amount)`](#IERC20-approve)
+
+Events
+
+- [`Transfer(from, to, value)`](#IERC20-Transfer)
+- [`Approval(owner, spender, value)`](#IERC20-Approval)
+
+#### Functions [!toc] [#IERC20-Functions]
+
+
+Returns the amount of tokens in existence.
+
+
+
+Returns the amount of tokens owned by `account`.
+
+
+
+Returns the remaining number of tokens that `spender` is allowed to spend on behalf of `owner` through [transfer\_from](#transfer_from). This is zero by default.
+
+This value changes when [approve](#IERC20-approve) or [transfer\_from](#IERC20-transfer_from) are called.
+
+
+
+Moves `amount` tokens from the caller's token balance to `to`. Returns `true` on success, reverts otherwise.
+
+Emits a [Transfer](#IERC20-Transfer) event.
+
+
+
+Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism. `amount` is then deducted from the caller's allowance. Returns `true` on success, reverts otherwise.
+
+Emits a [Transfer](#IERC20-Transfer) event.
+
+
+
+Sets `amount` as the allowance of `spender` over the caller's tokens. Returns `true` on success, reverts otherwise.
+
+Emits an [Approval](#ERC20-Approval) event.
+
+
+#### Events [!toc] [#IERC20-Events]
+
+
+Emitted when `value` tokens are moved from one address (`from`) to another (`to`).
+
+Note that `value` may be zero.
+
+
+
+Emitted when the allowance of a `spender` for an `owner` is set. `value` is the new allowance.
+
+
+### `IERC20Metadata` [toc] [#IERC20Metadata]
+
+
+```rust
+use openzeppelin_token::erc20::interface::IERC20Metadata;
+```
+
+Interface for the optional metadata functions in [EIP-20](https://eips.ethereum.org/EIPS/eip-20).
+
+Functions
+
+- [`name()`](#IERC20Metadata-name)
+- [`symbol()`](#IERC20Metadata-symbol)
+- [`decimals()`](#IERC20Metadata-decimals)
+
+#### Functions [!toc] [#IERC20Metadata-Functions]
+
+
+Returns the name of the token.
+
+
+
+Returns the ticker symbol of the token.
+
+
+
+Returns the number of decimals the token uses - e.g. `8` means to divide the token amount by `100000000` to get its user-readable representation.
+
+For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`).
+
+Tokens usually opt for a value of `18`, imitating the relationship between Ether and Wei. This is the default value returned by this function. To create a custom decimals implementation, see [Customizing decimals](../erc20#customizing_decimals).
+
+This information is only used for *display* purposes: it in no way affects any of the arithmetic of the contract.
+
+
+### `IERC20Permit` [toc] [#IERC20Permit]
+
+
+```rust
+use openzeppelin_token::erc20::interface::IERC20Permit;
+```
+
+Interface of the ERC20Permit standard to support gasless token approvals as defined in [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612).
+
+Functions
+
+- [`permit(owner, spender, amount, deadline, signature)`](#IERC20Permit-permit)
+- [`nonces(owner)`](#IERC20Permit-nonces)
+- [`DOMAIN_SEPARATOR()`](#IERC20Permit-DOMAIN_SEPARATOR)
+
+#### Functions [!toc] [#IERC20Permit-Functions]
+
+
+Sets `amount` as the allowance of `spender` over `owner`'s tokens after validating the signature.
+
+
+
+Returns the current nonce of `owner`. A nonce value must be included whenever a signature for `permit` call is generated.
+
+
+
+Returns the domain separator used in generating a message hash for `permit` signature. The domain hashing logic follows the [SNIP12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) standard.
+
+
+### `IERC4626` [toc] [#IERC4626]
+
+
+```rust
+use openzeppelin_token::erc20::extensions::erc4626::interface::IERC4626;
+```
+
+Interface of the IERC4626 standard as defined in [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626).
+
+Functions
+
+- [`asset()`](#IERC4626-asset)
+- [`total_assets()`](#IERC4626-total_assets)
+- [`convert_to_shares(assets)`](#IERC4626-convert_to_shares)
+- [`convert_to_assets(shares)`](#IERC4626-convert_to_assets)
+- [`max_deposit(receiver)`](#IERC4626-max_deposit)
+- [`preview_deposit(assets)`](#IERC4626-preview_deposit)
+- [`deposit(assets, receiver)`](#IERC4626-deposit)
+- [`max_mint(receiver)`](#IERC4626-max_mint)
+- [`preview_mint(shares)`](#IERC4626-preview_mint)
+- [`mint(shares, receiver)`](#IERC4626-mint)
+- [`max_withdraw(owner)`](#IERC4626-max_withdraw)
+- [`preview_withdraw(assets)`](#IERC4626-preview_withdraw)
+- [`withdraw(assets, receiver, owner)`](#IERC4626-withdraw)
+- [`max_redeem(owner)`](#IERC4626-max_redeem)
+- [`preview_redeem(shares)`](#IERC4626-preview_redeem)
+- [`redeem(shares, receiver, owner)`](#IERC4626-redeem)
+
+Events
+
+- [`Deposit(sender, owner, assets, shares)`](#IERC4626-Deposit)
+- [`Withdraw(sender, receiver, owner, assets, shares)`](#IERC4626-Withdraw)
+
+#### Functions [!toc] [#IERC4626-Functions]
+
+
+Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
+
+Requirements:
+
+- MUST be an ERC20 token contract.
+- MUST NOT panic.
+
+
+
+Returns the total amount of the underlying asset that is "managed" by Vault.
+
+Requirements:
+
+- SHOULD include any compounding that occurs from yield.
+- MUST be inclusive of any fees that are charged against assets in the Vault.
+- MUST NOT panic.
+
+
+
+Returns the amount of shares that the Vault would exchange for the amount of `assets` provided irrespective of slippage or fees.
+
+Requirements:
+
+- MUST NOT be inclusive of any fees that are charged against assets in the Vault.
+- MUST NOT show any variations depending on the caller.
+- MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
+- MUST NOT panic unless due to integer overflow caused by an unreasonably large input.
+- MUST round down towards 0.
+
+This calculation MAY NOT reflect the "per-user" price-per-share, and instead should reflect the "average-user's" price-per-share, meaning what the average user should expect to see when exchanging to and from.
+
+
+
+Returns the amount of assets that the Vault would exchange for the amount of `shares` provided irrespective of slippage or fees.
+
+Requirements:
+
+- MUST NOT be inclusive of any fees that are charged against assets in the Vault.
+- MUST NOT show any variations depending on the caller.
+- MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
+- MUST NOT panic unless due to integer overflow caused by an unreasonably large input.
+- MUST round down towards 0.
+
+This calculation MAY NOT reflect the "per-user" price-per-share, and instead should reflect the "average-user's" price-per-share, meaning what the average user should expect to see when exchanging to and from.
+
+
+
+Returns the maximum amount of the underlying asset that can be deposited into the Vault for `receiver`, through a deposit call.
+
+Requirements:
+
+- MUST return a limited value if receiver is subject to some deposit limit.
+- MUST return 2 \** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
+- MUST NOT panic.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
+
+Requirements:
+
+- MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit call in the same transaction i.e. [IERC4626::deposit](#IERC4626-deposit) should return the same or more shares as `preview_deposit` if called in the same transaction.
+- MUST NOT account for deposit limits like those returned from [IERC4626::max\_deposit](#IERC4626-max_deposit) and should always act as though the deposit would be accepted, regardless if the user has enough tokens approved, etc.
+- MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
+- MUST NOT panic.
+
+Any unfavorable discrepancy between [IERC4626::convert\_to\_shares](#IERC4626-convert_to_shares) and `preview_deposit` SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing.
+
+
+
+Mints Vault shares to `receiver` by depositing exactly amount of `assets`.
+
+Requirements:
+
+- MUST emit the [IERC4626::Deposit](#IERC4626-Deposit) event.
+- MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the deposit execution, and are accounted for during deposit.
+- MUST panic if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not approving enough underlying tokens to the Vault contract, etc).
+
+Most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
+
+
+
+Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
+
+Requirements:
+
+- MUST return a limited value if receiver is subject to some mint limit.
+- MUST return 2 \** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
+- MUST NOT panic.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
+
+Requirements:
+
+- MUST return as close to and no fewer than the exact amount of assets that would be deposited in a `mint` call in the same transaction. I.e. [IERC4626::mint](#IERC4626-mint) should return the same or fewer assets as `preview_mint` if called in the same transaction.
+- MUST NOT account for mint limits like those returned from [IERC4626::max\_mint](#IERC4626-max_mint) and should always act as though the mint would be accepted, regardless if the user has enough tokens approved, etc.
+- MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
+- MUST NOT panic.
+
+Any unfavorable discrepancy between [IERC4626::convert\_to\_assets](#IERC4626-convert_to_assets) and `preview_mint` SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by minting.
+
+
+
+Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
+
+Requirements:
+
+- MUST emit the [IERC4626::Deposit](#IERC4626-Deposit) event.
+- MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint execution, and are accounted for during mint.
+- MUST panic if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not approving enough underlying tokens to the Vault contract, etc).
+
+Most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
+
+
+
+Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the Vault, through a withdraw call.
+
+Requirements:
+
+- MUST return a limited value if owner is subject to some withdrawal limit or timelock.
+- MUST NOT panic.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions.
+
+Requirements:
+
+- MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw call in the same transaction i.e. [IERC4626::withdraw](#IERC4626-withdraw) should return the same or fewer shares as `preview_withdraw` if called in the same transaction.
+- MUST NOT account for withdrawal limits like those returned from [IERC4626::max\_withdraw](#IERC4626-max_withdraw) and should always act as though the withdrawal would be accepted, regardless if the user has enough shares, etc.
+- MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
+- MUST NOT panic.
+
+Any unfavorable discrepancy between [IERC4626::convert\_to\_shares](#IERC4626-convert_to_shares) and `preview_withdraw` SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing.
+
+
+
+Burns shares from owner and sends exactly assets of underlying tokens to receiver.
+
+Requirements:
+
+- MUST emit the [IERC4626::Withdraw](#IERC4626-Withdraw) event.
+- MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the withdraw execution, and are accounted for during withdraw.
+- MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner not having enough shares, etc).
+
+Some implementations will require pre-requesting to the Vault before a withdrawal may be performed. Those methods should be performed separately.
+
+
+
+Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, through a redeem call.
+
+Requirements:
+
+- MUST return a limited value if owner is subject to some withdrawal limit or timelock.
+- MUST return `ERC20::balance_of(owner)` if `owner` is not subject to any withdrawal limit or timelock.
+- MUST NOT panic.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, given current on-chain conditions.
+
+Requirements:
+
+- MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call in the same transaction i.e. [IERC4626::redeem](#IERC4626-redeem) should return the same or more assets as preview\_redeem if called in the same transaction.
+- MUST NOT account for redemption limits like those returned from [IERC4626::max\_redeem](#IERC4626-max_redeem) and should always act as though the redemption would be accepted, regardless if the user has enough shares, etc.
+- MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
+- MUST NOT panic.
+
+Any unfavorable discrepancy between [IERC4626::convert\_to\_assets](#IERC4626-convert_to_assets) and `preview_redeem` SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by redeeming.
+
+
+
+Burns exactly shares from owner and sends assets of underlying tokens to receiver.
+
+Requirements:
+
+- MUST emit the [IERC4626::Withdraw](#IERC4626-Withdraw) event.
+- MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the redeem execution, and are accounted for during redeem.
+- MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner not having enough shares, etc).
+
+Some implementations will require pre-requesting to the Vault before a withdrawal may be performed. Those methods should be performed separately.
+
+
+#### Events [!toc] [#IERC4626-Events]
+
+
+Emitted when `sender` exchanges `assets` for `shares` and transfers those `shares` to `owner`.
+
+
+
+Emitted when `sender` exchanges `shares`, owned by `owner`, for `assets` and transfers those `assets` to `receiver`.
+
+
+## Core
+
+### `ERC20Component` [toc] [#ERC20Component]
+
+
+```rust
+use openzeppelin_token::erc20::ERC20Component;
+```
+
+ERC20 component extending [IERC20](#IERC20) and [IERC20Metadata](#IERC20Metadata).
+
+See [Hooks](#ERC20Component-Hooks) to understand how are hooks used.
+
+Hooks
+
+#### ERC20HooksTrait [!toc] [#ERC20Component-ERC20HooksTrait]
+
+- [`before_update(self, from, recipient, amount)`](#ERC20Component-before_update)
+- [`after_update(self, from, recipient, amount)`](#ERC20Component-after_update)
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### ERC20MixinImpl [!toc] [#ERC20Component-Embeddable-Impls-ERC20MixinImpl]
+
+- [`ERC20Impl`](#ERC20Component-Embeddable-Impls-ERC20Impl)
+- [`ERC20MetadataImpl`](#ERC20Component-Embeddable-Impls-ERC20MetadataImpl)
+- [`ERC20CamelOnlyImpl`](#ERC20Component-Embeddable-Impls-ERC20CamelOnlyImpl)
+
+Embeddable Implementations
+
+#### ERC20Impl [!toc] [#ERC20Component-Embeddable-Impls-ERC20Impl]
+
+- [`total_supply(self)`](#ERC20Component-total_supply)
+- [`balance_of(self, account)`](#ERC20Component-balance_of)
+- [`allowance(self, owner, spender)`](#ERC20Component-allowance)
+- [`transfer(self, recipient, amount)`](#ERC20Component-transfer)
+- [`transfer_from(self, sender, recipient, amount)`](#ERC20Component-transfer_from)
+- [`approve(self, spender, amount)`](#ERC20Component-approve)
+
+#### ERC20MetadataImpl [!toc] [#ERC20Component-Embeddable-Impls-ERC20MetadataImpl]
+
+- [`name(self)`](#ERC20Component-name)
+- [`symbol(self)`](#ERC20Component-symbol)
+- [`decimals(self)`](#ERC20Component-decimals)
+
+#### ERC20CamelOnlyImpl [!toc] [#ERC20Component-Embeddable-Impls-ERC20CamelOnlyImpl]
+
+- [`totalSupply(self)`](#ERC20Component-totalSupply)
+- [`balanceOf(self, account)`](#ERC20Component-balanceOf)
+- [`transferFrom(self, sender, recipient, amount)`](#ERC20Component-transferFrom)
+
+#### ERC20PermitImpl [!toc] [#ERC20Component-Embeddable-Impls-ERC20PermitImpl]
+
+- [`permit(self, owner, spender, amount, deadline, signature)`](#ERC20Component-permit)
+- [`nonces(self, owner)`](#ERC20Component-nonces)
+- [`DOMAIN_SEPARATOR(self)`](#ERC20Component-DOMAIN_SEPARATOR)
+
+#### SNIP12MetadataExternalImpl [!toc] [#ERC20Component-Embeddable-Impls-SNIP12MetadataExternalImpl]
+
+- [`snip12_metadata(self)`](#ERC20Component-snip12_metadata)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#ERC20Component-InternalImpl]
+
+- [`initializer(self, name, symbol)`](#ERC20Component-initializer)
+- [`mint(self, recipient, amount)`](#ERC20Component-mint)
+- [`burn(self, account, amount)`](#ERC20Component-burn)
+- [`update(self, from, to, amount)`](#ERC20Component-update)
+- [`_transfer(self, sender, recipient, amount)`](#ERC20Component-_transfer)
+- [`_approve(self, owner, spender, amount)`](#ERC20Component-_approve)
+- [`_spend_allowance(self, owner, spender, amount)`](#ERC20Component-_spend_allowance)
+
+Events
+
+- [`Transfer(from, to, value)`](#ERC20Component-Transfer)
+- [`Approval(owner, spender, value)`](#ERC20Component-Approval)
+
+#### Hooks [!toc] [#ERC20Component-Hooks]
+
+Hooks are functions which implementations can extend the functionality of the component source code. Every contract using ERC20Component is expected to provide an implementation of the ERC20HooksTrait. For basic token contracts, an empty implementation with no logic must be provided.
+
+You can use `openzeppelin_token::erc20::ERC20HooksEmptyImpl` which is already available as part of the library for this purpose.
+
+
+Function executed at the beginning of the [update](#ERC20Component-update) function prior to any other logic.
+
+
+
+Function executed at the end of the [update](#ERC20Component-update) function.
+
+
+#### Embeddable functions [!toc] [#ERC20Component-Embeddable-Functions]
+
+
+See [IERC20::total\_supply](#IERC20-total_supply).
+
+
+
+See [IERC20::balance\_of](#IERC20-balance_of).
+
+
+
+See [IERC20::allowance](#IERC20-allowance).
+
+
+
+See [IERC20::transfer](#IERC20-transfer).
+
+Requirements:
+
+- `recipient` cannot be the zero address.
+- The caller must have a balance of at least `amount`.
+
+
+
+See [IERC20::transfer\_from](#IERC20-transfer_from).
+
+Requirements:
+
+- `sender` cannot be the zero address.
+- `sender` must have a balance of at least `amount`.
+- `recipient` cannot be the zero address.
+- The caller must have allowance for `sender`'s tokens of at least `amount`.
+
+
+
+See [IERC20::approve](#IERC20-approve).
+
+Requirements:
+
+- `spender` cannot be the zero address.
+
+
+
+See [IERC20Metadata::name](#IERC20Metadata-name).
+
+
+
+See [IERC20Metadata::symbol](#IERC20Metadata-symbol).
+
+
+
+See [IERC20Metadata::decimals](#IERC20Metadata-decimals).
+
+
+
+See [IERC20::total\_supply](#IERC20-total_supply).
+
+Supports the Cairo v0 convention of writing external methods in camelCase as discussed [here](https://github.com/OpenZeppelin/cairo-contracts/discussions/34).
+
+
+
+See [IERC20::balance\_of](#IERC20-balance_of).
+
+Supports the Cairo v0 convention of writing external methods in camelCase as discussed [here](https://github.com/OpenZeppelin/cairo-contracts/discussions/34).
+
+
+
+See [IERC20::transfer\_from](#IERC20-transfer_from).
+
+Supports the Cairo v0 convention of writing external methods in camelCase as discussed [here](https://github.com/OpenZeppelin/cairo-contracts/discussions/34).
+
+
+
+Sets `amount` as the allowance of `spender` over `owner`'s tokens after validating the signature.
+
+Requirements:
+
+- `owner` is a deployed account contract.
+- `spender` is not the zero address.
+- `deadline` is not a timestamp in the past.
+- `signature` is a valid signature that can be validated with a call to `owner` account.
+- `signature` must use the current nonce of the `owner`.
+
+Emits an [Approval](#ERC20-Approval) event. Every successful call increases \`owner's nonce by one.
+
+
+
+Returns the current nonce of `owner`. A nonce value must be included whenever a signature for `permit` call is generated.
+
+
+
+Returns the domain separator used in generating a message hash for `permit` signature. The domain hashing logic follows the [SNIP12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) standard.
+
+
+
+Returns the domain name and version used to generate the message hash for permit signature.
+
+The returned tuple contains:
+
+- `t.0`: The name used in the [SNIP12Metadata](./utilities#snip12) implementation.
+- `t.1`: The version used in the [SNIP12Metadata](./utilities#snip12) implementation.
+
+
+#### Internal functions [!toc] [#ERC20Component-Internal-Functions]
+
+
+Initializes the contract by setting the token name and symbol. This should be used inside of the contract's constructor.
+
+
+
+Creates an `amount` number of tokens and assigns them to `recipient`.
+
+Emits a [Transfer](#ERC20Component-Transfer) event with `from` being the zero address.
+
+Requirements:
+
+- `recipient` cannot be the zero address.
+
+
+
+Destroys `amount` number of tokens from `account`.
+
+Emits a [Transfer](#ERC20Component-Transfer) event with `to` set to the zero address.
+
+Requirements:
+
+- `account` cannot be the zero address.
+
+
+
+Transfers an `amount` of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is the zero address.
+
+This function can be extended using the [ERC20HooksTrait](#ERC20Component-ERC20HooksTrait), to add functionality before and/or after the transfer, mint, or burn.
+
+Emits a [Transfer](#ERC20Component-Transfer) event.
+
+
+
+Moves `amount` of tokens from `from` to `to`.
+
+This internal function does not check for access permissions but can be useful as a building block, for example to implement automatic token fees, slashing mechanisms, etc.
+
+Emits a [Transfer](#ERC20Component-Transfer) event.
+
+Requirements:
+
+- `from` cannot be the zero address.
+- `to` cannot be the zero address.
+- `from` must have a balance of at least `amount`.
+
+
+
+Sets `amount` as the allowance of `spender` over `owner`'s tokens.
+
+This internal function does not check for access permissions but can be useful as a building block, for example to implement automatic allowances on behalf of other addresses.
+
+Emits an [Approval](#ERC20Component-Approval) event.
+
+Requirements:
+
+- `owner` cannot be the zero address.
+- `spender` cannot be the zero address.
+
+
+
+Updates `owner`'s allowance for `spender` based on spent `amount`.
+
+This internal function does not update the allowance value in the case of infinite allowance.
+
+Possibly emits an [Approval](#ERC20Component-Approval) event.
+
+
+#### Events [!toc] [#ERC20Component-Events]
+
+
+See [IERC20::Transfer](#IERC20-Transfer).
+
+
+
+See [IERC20::Approval](#IERC20-Approval).
+
+
+## Extensions
+
+### `ERC4626Component` [toc] [#ERC4626Component]
+
+
+```rust
+use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component;
+```
+
+Extension of ERC20 that implements the [IERC4626](#IERC4626) interface which allows the minting and burning of "shares" in exchange for an underlying "asset." The component leverages traits to configure fees, limits, and decimals.
+
+[Immutable Component Config](../components#immutable-config)
+
+#### constants [!toc] [#ERC4626Component-constants]
+
+- [`UNDERLYING_DECIMALS`](#ERC4626Component-IC-UNDERLYING_DECIMALS)
+- [`DECIMALS_OFFSET`](#ERC4626Component-IC-DECIMALS_OFFSET)
+
+#### functions [!toc] [#ERC4626Component-functions]
+
+- [`validate()`](#ERC4626Component-IC-validate)
+
+Hooks
+
+#### FeeConfigTrait [!toc] [#ERC4626Component-FeeConfigTrait]
+
+- [`calculate_deposit_fee(self, assets, shares)`](#ERC4626Component-calculate_deposit_fee)
+- [`calculate_mint_fee(self, assets, shares)`](#ERC4626Component-calculate_mint_fee)
+- [`calculate_withdraw_fee(self, assets, shares)`](#ERC4626Component-calculate_withdraw_fee)
+- [`calculate_redeem_fee(self, assets, shares)`](#ERC4626Component-calculate_redeem_fee)
+
+#### LimitConfigTrait [!toc] [#ERC4626Component-LimitConfigTrait]
+
+- [`deposit_limit(self, receiver)`](#ERC4626Component-deposit_limit)
+- [`mint_limit(self, receiver)`](#ERC4626Component-mint_limit)
+- [`withdraw_limit(self, owner)`](#ERC4626Component-withdraw_limit)
+- [`redeem_limit(self, owner)`](#ERC4626Component-redeem_limit)
+
+#### ERC4626HooksTrait [!toc] [#ERC4626Component-ERC4626HooksTrait]
+
+- [`before_deposit(self, caller, receiver, assets, shares, fee)`](#ERC4626Component-before_deposit)
+- [`after_deposit(self, caller, receiver, assets, shares, fee)`](#ERC4626Component-after_deposit)
+- [`before_withdraw(self, caller, receiver, owner, assets, shares, fee)`](#ERC4626Component-before_withdraw)
+- [`after_withdraw(self, caller, receiver, owner, assets, shares, fee)`](#ERC4626Component-after_withdraw)
+
+#### AssetsManagementTrait [!toc] [#ERC4626Component-AssetsManagementTrait]
+
+- [`get_total_assets(self)`](#ERC4626Component-get_total_assets)
+- [`transfer_assets_in(self, from, assets)`](#ERC4626Component-transfer_assets_in)
+- [`transfer_assets_out(self, to, assets)`](#ERC4626Component-transfer_assets_out)
+
+Embeddable Implementations
+
+#### ERC4626Impl [!toc] [#ERC4626Component-Embeddable-Impls-ERC4626Impl]
+
+- [`asset(self)`](#ERC4626Component-asset)
+- [`total_assets(self)`](#ERC4626Component-total_assets)
+- [`convert_to_shares(self, assets)`](#ERC4626Component-convert_to_shares)
+- [`convert_to_assets(self, shares)`](#ERC4626Component-convert_to_assets)
+- [`max_deposit(self, receiver)`](#ERC4626Component-max_deposit)
+- [`preview_deposit(self, assets)`](#ERC4626Component-preview_deposit)
+- [`deposit(self, assets, receiver)`](#ERC4626Component-deposit)
+- [`max_mint(self, receiver)`](#ERC4626Component-max_mint)
+- [`preview_mint(self, shares)`](#ERC4626Component-preview_mint)
+- [`mint(self, shares, receiver)`](#ERC4626Component-mint)
+- [`max_withdraw(self, owner)`](#ERC4626Component-max_withdraw)
+- [`preview_withdraw(self, assets)`](#ERC4626Component-preview_withdraw)
+- [`withdraw(self, assets, receiver, owner)`](#ERC4626Component-withdraw)
+- [`max_redeem(self, owner)`](#ERC4626Component-max_redeem)
+- [`preview_redeem(self, shares)`](#ERC4626Component-preview_redeem)
+- [`redeem(self, shares, receiver, owner)`](#ERC4626Component-redeem)
+
+#### ERC20Impl [!toc] [#ERC4626Component-Embeddable-Impls-ERC20Impl]
+
+- [`total_supply(self)`](#ERC20Component-total_supply)
+- [`balance_of(self, account)`](#ERC20Component-balance_of)
+- [`allowance(self, owner, spender)`](#ERC20Component-allowance)
+- [`transfer(self, recipient, amount)`](#ERC20Component-transfer)
+- [`transfer_from(self, sender, recipient, amount)`](#ERC20Component-transfer_from)
+- [`approve(self, spender, amount)`](#ERC20Component-approve)
+
+#### ERC4626MetadataImpl [!toc] [#ERC4626Component-Embeddable-Impls-ERC4626MetadataImpl]
+
+- [`name(self)`](#ERC4626Component-name)
+- [`symbol(self)`](#ERC4626Component-symbol)
+- [`decimals(self)`](#ERC4626Component-decimals)
+
+Internal functions
+
+#### InternalImpl [!toc] [#ERC4626Component-InternalImpl]
+
+- [`initializer(self, asset_address)`](#ERC4626Component-initializer)
+- [`_deposit(self, caller, receiver, assets, shares)`](#ERC4626Component-_deposit)
+- [`_withdraw(self, caller, receiver, owner, assets, shares)`](#ERC4626Component-_withdraw)
+- [`_convert_to_shares(self, assets, rounding)`](#ERC4626Component-_convert_to_shares)
+- [`_convert_to_assets(self, shares, rounding)`](#ERC4626Component-_convert_to_assets)
+
+#### Immutable Config [!toc] [#ERC4626Component-Immutable-Config]
+
+
+Should match the underlying asset's decimals. The default value is `18`.
+
+
+
+Corresponds to the representational offset between `UNDERLYING_DECIMALS` and the vault decimals. The greater the offset, the more expensive it is for attackers to execute an inflation attack.
+
+
+
+Validates the given implementation of the contract's configuration.
+
+Requirements:
+
+- `UNDERLYING_DECIMALS` + `DECIMALS_OFFSET` cannot exceed 255 (max u8).
+
+This function is called by the contract's initializer.
+
+
+#### Hooks [!toc] [#ERC4626Component-Hooks]
+
+Hooks are functions which implementations can extend the functionality of the component source code. Every contract using ERC4626Component is expected to provide an implementation of the ERC4626HooksTrait. For basic token contracts, an empty implementation with no logic must be provided.
+
+You can use `openzeppelin_token::erc20::extensions::erc4626::ERC4626EmptyHooks` which is already available as part of the library for this purpose.
+
+#### FeeConfigTrait [!toc] [#ERC4626Component-FeeConfigTrait]
+
+The logic for calculating entry and exit fees is expected to be defined at the contract level. Defaults to no entry or exit fees.
+
+The FeeConfigTrait hooks directly into the preview methods of the ERC4626 component. The preview methods must return as close to the exact amount of shares or assets as possible if the actual (previewed) operation occurred in the same transaction (according to [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec). All operations use their corresponding preview method as the value of assets or shares being moved to or from the user. The fees calculated in FeeConfigTrait are used to adjust the final asset and share amounts used in both the preview and the actual operations.
+
+To transfer fees, this trait needs to be coordinated with `ERC4626Component::ERC4626Hooks`.
+
+See implementation examples:
+
+- Contract charging fees in assets: [ERC4626AssetsFeesMock](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo#L253)
+- Contract charging fees in shares: [ERC4626SharesFeesMock](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo#L426)
+
+
+Calculates the entry fee for a deposit during [preview\_deposit](#ERC4626Component-preview_deposit). The returned fee affects the final asset and share amounts. Fees are not transferred automatically and must be handled in the [after\_deposit](#ERC4626Component-after_deposit) hook: asset fees should be transferred from the vault's management to the fee recipient, while share fees should be minted to the fee recipient.
+
+
+
+Calculates the entry fee for a mint during [preview\_mint](#ERC4626Component-preview_mint). The returned fee affects the final asset and share amounts. Fees are not transferred automatically and must be handled in the [after\_deposit](#ERC4626Component-after_deposit) hook: asset fees should be transferred from the vault's management to the fee recipient, while share fees should be minted to the fee recipient.
+
+
+
+Calculates the exit fee for a withdraw during [preview\_withdraw](#ERC4626Component-preview_withdraw). The returned fee affects the final asset and share amounts. Fees are not transferred automatically and must be handled in the [before\_withdraw](#ERC4626Component-before_withdraw) hook: asset fees should be transferred from the vault's management to the fee recipient, while share fees should be transferred from the owner to the fee recipient.
+
+
+
+Calculates the exit fee for a redeem during [preview\_redeem](#ERC4626Component-preview_redeem). The returned fee affects the final asset and share amounts. Fees are not transferred automatically and must be handled in the [before\_withdraw](#ERC4626Component-before_withdraw) hook: asset fees should be transferred from the vault's management to the fee recipient, while share fees should be transferred from the owner to the fee recipient.
+
+
+#### LimitConfigTrait [!toc] [#ERC4626Component-LimitConfigTrait]
+
+Sets limits to the target exchange type and is expected to be defined at the contract level. These limits correspond directly to the `max_` i.e. `deposit_limit` → `max_deposit`.
+
+The [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec states that the `max_` methods must take into account all global and user-specific limits. If an operation is disabled (even temporarily), the corresponding limit MUST be `0` and MUST NOT panic.
+
+
+The max deposit allowed.
+
+Defaults (`Option::None`) to 2 \** 256 - 1.
+
+
+
+The max mint allowed.
+
+Defaults (`Option::None`) to 2 \** 256 - 1.
+
+
+
+The max withdraw allowed.
+
+Defaults (`Option::None`) to the full asset balance of `owner` converted from shares.
+
+
+
+The max redeem allowed.
+
+Defaults (`Option::None`) to the full asset balance of `owner`.
+
+
+#### ERC4626HooksTrait [!toc] [#ERC4626Component-ERC4626HooksTrait]
+
+Allows contracts to hook logic into deposit and withdraw transactions. This is where contracts can transfer fees.
+
+ERC4626 preview methods must be inclusive of any entry or exit fees. Fees are calculated using [FeeConfigTrait](#ERC4626Component-FeeConfigTrait) methods and automatically adjust the final asset and share amounts. Fee transfers are handled in `ERC4626HooksTrait` methods.
+
+Special care must be taken when calling external contracts in these hooks. In that case, consider implementing reentrancy protections. For example, in the `withdraw` flow, the `withdraw_limit` is checked **before** the `before_withdraw` hook is invoked. If this hook performs a reentrant call that invokes `withdraw` again, the subsequent check on `withdraw_limit` will be done before the first withdrawal's core logic (e.g., burning shares and transferring assets) is executed. This could lead to bypassing withdrawal constraints or draining funds.
+
+See the [ERC4626AssetsFeesMock](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo#L253) and [ERC4626SharesFeesMock](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo#L426) examples.
+
+
+Hooks into [\_deposit](#ERC4626Component-_deposit).
+
+Executes logic before transferring assets and minting shares. The fee is calculated via [FeeConfigTrait](#ERC4626Component-FeeConfigTrait). Assets and shares represent the actual amounts the user will spend and receive, respectively. Asset fees are included in assets; share fees are excluded from shares.
+
+
+
+Hooks into [\_deposit](#ERC4626Component-_deposit).
+
+Executes logic after transferring assets and minting shares. The fee is calculated via [FeeConfigTrait](#ERC4626Component-FeeConfigTrait). Assets and shares represent the actual amounts the user will spend and receive, respectively. Asset fees are included in assets; share fees are excluded from shares.
+
+
+
+Hooks into [\_withdraw](#ERC4626Component-_withdraw).
+
+Executes logic before burning shares and transferring assets. The fee is calculated via [FeeConfigTrait](#ERC4626Component-FeeConfigTrait). Assets and shares represent the actual amounts the user will receive and spend, respectively. Asset fees are excluded from assets; share fees are included in shares.
+
+
+
+Hooks into [\_withdraw](#ERC4626Component-_withdraw).
+
+Executes logic after burning shares and transferring assets. The fee is calculated via [FeeConfigTrait](#ERC4626Component-FeeConfigTrait). Assets and shares represent the actual amounts the user will receive and spend, respectively. Asset fees are excluded from assets; share fees are included in shares.
+
+
+#### AssetsManagementTrait [!toc] [#ERC4626Component-AssetsManagementTrait]
+
+Defines how the ERC4626 vault manages its underlying assets. This trait provides the core asset management functionality for the vault, abstracting the actual storage and transfer mechanisms. It enables two primary implementation patterns:
+
+1. **Self-managed assets**: The vault contract holds assets directly on its own address. This is the default behavior provided by `ERC4626SelfAssetsManagement` implementation.
+2. **External vault**: Assets are managed by an external contract, allowing for more complex asset management strategies. The exact implementation is expected to be defined by the contract implementing the ERC4626 component.
+
+The trait methods are called during deposit, withdrawal, and total assets calculations, ensuring that the vault's share pricing remains accurate regardless of the underlying asset management strategy.
+
+Implementations must ensure that `get_total_assets` returns the actual amount of assets that can be withdrawn by users. Inaccurate reporting can lead to incorrect share valuations and potential economic attacks.
+
+See implementation examples:
+
+- Self-managed vault: [ERC4626SelfAssetsManagement](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/token/src/erc20/extensions/erc4626/erc4626.cairo#L760).
+- External vault: [ERC4626ExternalAssetsManagement](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo#L92).
+
+
+Returns the total amount of underlying assets under the vault's management. Used for share price calculations and determining the vault's total value.
+
+This method should return the actual amount of assets that the vault controls and that can be used to satisfy withdrawal requests. For self-managed vaults, this is typically the vault contract's token balance. For external vaults, this should include any assets deposited in external protocols, minus any that are locked or unredeemable.
+
+The accuracy of this method is critical for proper vault operation: - Overreporting can lead to share dilution and user losses. - Underreporting can lead to share inflation and potential economic attacks.
+
+
+
+Transfers assets from an external address into the vault's management. Called during `deposit` and `mint` operations.
+
+This method should handle the actual transfer of underlying assets from the `from` address into the vault's control. For self-managed vaults, this typically means transferring tokens to the vault contract's address. For external vaults, this might involve transferring into an external contract.
+
+Requirements:
+
+- MUST transfer exactly `assets` amount of the underlying token.
+- SHOULD revert if the transfer fails or insufficient allowance/balance.
+
+
+
+Transfers assets from the vault's management to an external address. Called during withdraw and redeem operations.
+
+This method should handle the actual transfer of underlying assets from the vault's control to the `to` address. For self-managed vaults, this typically means transferring tokens from the vault contract's address. For external vaults, this might involve withdrawing from an external contract first.
+
+Requirements:
+
+- MUST transfer exactly `assets` amount of the underlying token.
+- SHOULD revert if insufficient assets are available or transfer fails.
+
+
+#### Embeddable functions [!toc] [#ERC4626Component-Embeddable-Functions]
+
+
+Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
+
+
+
+Returns the total amount of the underlying asset that is "managed" by Vault.
+
+
+
+Returns the amount of shares that the Vault would exchange for the amount of assets provided irrespective of slippage or fees.
+
+As per the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec, this may panic *only* if there's an overflow from an unreasonably large input.
+
+
+
+Returns the amount of assets that the Vault would exchange for the amount of shares provided irrespective of slippage or fees.
+
+As per the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec, this may panic *only* if there's an overflow from an unreasonably large input.
+
+
+
+Returns the maximum amount of the underlying asset that can be deposited into the Vault for the `receiver`, through a [deposit](#ERC4626Component-deposit) call.
+
+The default max deposit value is 2 \** 256 - 1.
+
+This can be changed in the implementing contract by defining custom logic in [LimitConfigTrait::deposit\_limit](#ERC4626Component-deposit_limit).
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
+
+The default deposit preview value is the full amount of shares. This can be changed to account for fees, for example, in the implementing contract by defining custom logic in [FeeConfigTrait::calculate\_deposit\_fee](#ERC4626Component-calculate_deposit_fee).
+
+This method must be inclusive of entry fees to be compliant with the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec.
+
+
+
+Mints Vault shares to `receiver` by depositing exactly `assets` of underlying tokens. Returns the amount of newly-minted shares.
+
+Requirements:
+
+- `assets` is less than or equal to the max deposit amount for `receiver`.
+
+Emits a [Deposit](#IERC4626-Deposit) event.
+
+
+
+Returns the maximum amount of the Vault shares that can be minted for `receiver` through a [mint](#ERC4626Component-mint) call.
+
+The default max mint value is 2 \** 256 - 1.
+
+This can be changed in the implementing contract by defining custom logic in [LimitConfigTrait::mint\_limit](#ERC4626Component-mint_limit).
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
+
+The default mint preview value is the full amount of assets. This can be changed to account for fees, for example, in the implementing contract by defining custom logic in [FeeConfigTrait::calculate\_mint\_fee](#ERC4626Component-calculate_mint_fee).
+
+This method must be inclusive of entry fees to be compliant with the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec.
+
+
+
+Mints exactly Vault `shares` to `receiver` by depositing amount of underlying tokens. Returns the amount deposited assets.
+
+Requirements:
+
+- `shares` is less than or equal to the max shares amount for `receiver`.
+
+Emits a [Deposit](#IERC4626-Deposit) event.
+
+
+
+Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the Vault, through a [withdraw](#ERC4626Component-withdraw) call.
+
+The default max withdraw value is the full balance of assets for `owner` (converted from shares). This can be changed in the implementing contract by defining custom logic in [LimitConfigTrait::withdraw\_limit](#ERC4626Component-withdraw_limit).
+
+With customized limits, the maximum withdraw amount will either be the custom limit itself or `owner`'s total asset balance, whichever value is less.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions.
+
+The default withdraw preview value is the full amount of shares. This can be changed to account for fees, for example, in the implementing contract by defining custom logic in [FeeConfigTrait::calculate\_withdraw\_fee](#ERC4626Component-calculate_withdraw_fee).
+
+This method must be inclusive of exit fees to be compliant with the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec.
+
+
+
+Burns shares from `owner` and sends exactly `assets` of underlying tokens to `receiver`.
+
+Requirements:
+
+- `assets` is less than or equal to the max withdraw amount of `owner`.
+
+Emits a [Withdraw](#IERC4626-Withdraw) event.
+
+
+
+Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, through a [redeem](#ERC4626Component-redeem) call.
+
+The default max redeem value is the full balance of assets for `owner`. This can be changed in the implementing contract by defining custom logic in [LimitConfigTrait::redeem\_limit](#ERC4626Component-redeem_limit).
+
+With customized limits, the maximum redeem amount will either be the custom limit itself or `owner`'s total asset balance, whichever value is less.
+
+
+
+Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, given current on-chain conditions.
+
+The default redeem preview value is the full amount of assets. This can be changed to account for fees, for example, in the implementing contract by defining custom logic in [FeeConfigTrait::calculate\_redeem\_fee](#ERC4626Component-calculate_redeem_fee).
+
+This method must be inclusive of exit fees to be compliant with the [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) spec.
+
+
+
+Burns exactly `shares` from `owner` and sends assets of underlying tokens to `receiver`.
+
+Requirements:
+
+- `shares` is less than or equal to the max redeem amount of `owner`.
+
+Emits a [Withdraw](#IERC4626-Withdraw) event.
+
+
+
+Returns the name of the token.
+
+
+
+Returns the ticker symbol of the token, usually a shorter version of the name.
+
+
+
+Returns the cumulative number of decimals which includes both `UNDERLYING_DECIMALS` and `OFFSET_DECIMALS`. Both of which must be defined in the [ImmutableConfig](#ERC4626Component-Immutable-Config) inside the implementing contract.
+
+
+#### Internal functions [!toc] [#ERC4626Component-Internal-Functions]
+
+
+Validates the [ImmutableConfig](#ERC4626Component-Immutable-Config) constants and sets the `asset_address` to the vault. This should be set in the contract's constructor.
+
+Requirements:
+
+- `asset_address` cannot be the zero address.
+
+
+
+Internal logic for [deposit](#ERC4626Component-deposit) and [mint](#ERC4626Component-mint).
+
+Transfers `assets` from `caller` to the Vault contract then mints `shares` to `receiver`. Fees can be transferred in the `ERC4626Hooks::after_deposit` hook which is executed after assets are transferred and shares are minted.
+
+Requirements:
+
+- [ERC20::transfer\_from](#ERC20Component-transfer_from) must return true.
+
+Emits two [ERC20::Transfer](#ERC20Component-Transfer) events (`ERC20::mint` and `ERC20::transfer_from`).
+
+Emits a [Deposit](#IERC4626-Deposit) event.
+
+
+
+Internal logic for [withdraw](#ERC4626Component-withdraw) and [redeem](#ERC4626Component-redeem).
+
+Burns `shares` from `owner` and then transfers `assets` to `receiver`. Fees can be transferred in the `ERC4626Hooks::before_withdraw` hook which is executed before shares are burned and assets are transferred.
+
+Requirements:
+
+- [ERC20::transfer](#ERC20Component-transfer) must return true.
+
+Emits two [ERC20::Transfer](#ERC20Component-Transfer) events (`ERC20::burn` and `ERC20::transfer`).
+
+Emits a [Withdraw](#IERC4626-Withdraw) event.
+
+
+
+Internal conversion function (from assets to shares) with support for `rounding` direction.
+
+
+
+Internal conversion function (from shares to assets) with support for `rounding` direction.
+
+
+## Presets
+
+### `ERC20Upgradeable` [toc] [#ERC20Upgradeable]
+
+
+```rust
+use openzeppelin_presets::ERC20Upgradeable;
+```
+
+Upgradeable ERC20 contract leveraging [ERC20Component](#ERC20Component) with a fixed-supply mechanism for token distribution.
+
+[Sierra class hash](../presets)
+
+```text
+{{ERC20UpgradeableClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, name, symbol, fixed_supply, recipient, owner)`](#ERC20Upgradeable-constructor)
+
+Embedded Implementations
+
+#### ERC20MixinImpl [!toc] [#ERC20Upgradeable-Embedded-Impls-ERC20MixinImpl]
+
+- [`ERC20MixinImpl`](#ERC20Component-Embeddable-Mixin-Impl)
+
+#### OwnableMixinImpl [!toc] [#ERC20Upgradeable-Embedded-Impls-OwnableMixinImpl]
+
+- [`OwnableMixinImpl`](./access#OwnableComponent-Mixin-Impl)
+
+External Functions
+
+- [`upgrade(self, new_class_hash)`](#ERC20Upgradeable-upgrade)
+
+#### Constructor [!toc] [#ERC20Upgradeable-Constructor]
+
+
+Sets the `name` and `symbol` and mints `fixed_supply` tokens to `recipient`. Assigns `owner` as the contract owner with permissions to upgrade.
+
+
+#### External functions [!toc] [#ERC20Upgradeable-External-Functions]
+
+
+Upgrades the contract to a new implementation given by `new_class_hash`.
+
+Requirements:
+
+- The caller is the contract owner.
+- `new_class_hash` cannot be zero.
+
diff --git a/docs/content/contracts-cairo/2.x/api/erc721.mdx b/docs/content/contracts-cairo/2.x/api/erc721.mdx
new file mode 100644
index 00000000..9436efa2
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/erc721.mdx
@@ -0,0 +1,1154 @@
+---
+title: ERC721
+---
+
+This module provides interfaces, presets, and utilities related to ERC721 contracts.
+
+For an overview of ERC721, read our [ERC721 guide](../erc721).
+
+## Interfaces
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+### `IERC721` [toc] [#IERC721]
+
+
+```rust
+use openzeppelin_token::erc721::interface::IERC721;
+```
+
+Interface of the IERC721 standard as defined in [EIP721](https://eips.ethereum.org/EIPS/eip-721).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943
+```
+
+Functions
+
+- [`balance_of(account)`](#IERC721-balance_of)
+- [`owner_of(token_id)`](#IERC721-owner_of)
+- [`safe_transfer_from(from, to, token_id, data)`](#IERC721-safe_transfer_from)
+- [`transfer_from(from, to, token_id)`](#IERC721-transfer_from)
+- [`approve(to, token_id)`](#IERC721-approve)
+- [`set_approval_for_all(operator, approved)`](#IERC721-set_approval_for_all)
+- [`get_approved(token_id)`](#IERC721-get_approved)
+- [`is_approved_for_all(owner, operator)`](#IERC721-is_approved_for_all)
+
+Events
+
+- [`Approval(owner, approved, token_id)`](#IERC721-Approval)
+- [`ApprovalForAll(owner, operator, approved)`](#IERC721-ApprovalForAll)
+- [`Transfer(from, to, token_id)`](#IERC721-Transfer)
+
+#### Functions [!toc] [#IERC721-Functions]
+
+
+Returns the number of NFTs owned by `account`.
+
+
+
+Returns the owner address of `token_id`.
+
+
+
+Transfer ownership of `token_id` from `from` to `to`, checking first that `to` is aware of the ERC721 protocol to prevent tokens being locked forever. For information regarding how contracts communicate their awareness of the ERC721 protocol, see [Receiving Tokens](../erc721#receiving_tokens).
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Transfer ownership of `token_id` from `from` to `to`.
+
+Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 transfers or else they may be permanently lost. Usage of [IERC721::safe\_transfer\_from](#IERC721-safe_transfer_from) prevents loss, though the caller must understand this adds an external call which potentially creates a reentrancy vulnerability.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Change or reaffirm the approved address for an NFT.
+
+Emits an [Approval](#IERC721-Approval) event.
+
+
+
+Enable or disable approval for `operator` to manage all of the caller's assets.
+
+Emits an [ApprovalForAll](#IERC721-ApprovalForAll) event.
+
+
+
+Returns the address approved for `token_id`.
+
+
+
+Query if `operator` is an authorized operator for `owner`.
+
+
+#### Events [!toc] [#IERC721-Events]
+
+
+Emitted when `owner` enables `approved` to manage the `token_id` token.
+
+
+
+Emitted when `owner` enables or disables `operator` to manage the `token_id` token.
+
+
+
+Emitted when `token_id` token is transferred from `from` to `to`.
+
+
+### `IERC721Metadata` [toc] [#IERC721Metadata]
+
+
+```rust
+use openzeppelin_token::erc721::interface::IERC721Metadata;
+```
+
+Interface for the optional metadata functions in [EIP721](https://eips.ethereum.org/EIPS/eip-721).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0xabbcd595a567dce909050a1038e055daccb3c42af06f0add544fa90ee91f25
+```
+
+Functions
+
+- [`name()`](#IERC721Metadata-name)
+- [`symbol()`](#IERC721Metadata-symbol)
+- [`token_uri(token_id)`](#IERC721Metadata-token_uri)
+
+#### Functions [!toc] [#IERC721Metadata-Functions]
+
+
+Returns the NFT name.
+
+
+
+Returns the NFT ticker symbol.
+
+
+
+Returns the Uniform Resource Identifier (URI) for the `token_id` token. If the URI is not set for `token_id`, the return value will be an empty `ByteArray`.
+
+
+### `IERC721Receiver` [toc] [#IERC721Receiver]
+
+
+```rust
+use openzeppelin_token::erc721::interface::IERC721Receiver;
+```
+
+Interface for contracts that support receiving `safe_transfer_from` transfers.
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc
+```
+
+Functions
+
+- [`on_erc721_received(operator, from, token_id, data)`](#IERC721Receiver-on_erc721_received)
+
+#### Functions [!toc] [#IERC721Receiver-Functions]
+
+
+Whenever an IERC721 `token_id` token is transferred to this non-account contract via [IERC721::safe\_transfer\_from](#IERC721-safe_transfer_from) by `operator` from `from`, this function is called.
+
+
+### `IERC721Enumerable` [toc] [#IERC721Enumerable]
+
+
+Interface for the optional enumerable functions in [EIP721](https://eips.ethereum.org/EIPS/eip-721).
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x16bc0f502eeaf65ce0b3acb5eea656e2f26979ce6750e8502a82f377e538c87
+```
+
+Functions
+
+- [`total_supply()`](#IERC721Enumerable-total_supply)
+- [`token_by_index(index)`](#IERC721Enumerable-token_by_index)
+- [`token_of_owner_by_index(owner, index)`](#IERC721Enumerable-token_of_owner_by_index)
+
+#### Functions [!toc] [#IERC721Enumerable-Functions]
+
+
+Returns the total amount of tokens stored by the contract.
+
+
+
+Returns a token id at a given `index` of all the tokens stored by the contract. Use along with [IERC721Enumerable::total\_supply](#IERC721Enumerable-total_supply) to enumerate all tokens.
+
+
+
+Returns the token id owned by `owner` at a given `index` of its token list. Use along with [IERC721::balance\_of](#IERC721-balance_of) to enumerate all of `owner`'s tokens.
+
+
+## Core
+
+### `ERC721Component` [toc] [#ERC721Component]
+
+
+```rust
+use openzeppelin_token::erc721::ERC721Component;
+```
+
+ERC721 component implementing [IERC721](#IERC721) and [IERC721Metadata](#IERC721Metadata).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+See [Hooks](#ERC721Component-Hooks) to understand how are hooks used.
+
+Hooks
+
+#### ERC721HooksTrait [!toc] [#ERC721Component-ERC721HooksTrait]
+
+- [`before_update(self, to, token_id, auth)`](#ERC721Component-before_update)
+- [`after_update(self, to, token_id, auth)`](#ERC721Component-after_update)
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### ERC721MixinImpl [!toc] [#ERC721Component-Embeddable-Impls-ERC721MixinImpl]
+
+- [`ERC721Impl`](#ERC721Component-Embeddable-Impls-ERC721Impl)
+- [`ERC721MetadataImpl`](#ERC721Component-Embeddable-Impls-ERC721MetadataImpl)
+- [`ERC721CamelOnlyImpl`](#ERC721Component-Embeddable-Impls-ERC721CamelOnlyImpl)
+- [`ERC721MetadataCamelOnlyImpl`](#ERC721Component-Embeddable-Impls-ERC721MetadataCamelOnlyImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### ERC721Impl [!toc] [#ERC721Component-Embeddable-Impls-ERC721Impl]
+
+- [`balance_of(self, account)`](#ERC721Component-balance_of)
+- [`owner_of(self, token_id)`](#ERC721Component-owner_of)
+- [`safe_transfer_from(self, from, to, token_id, data)`](#ERC721Component-safe_transfer_from)
+- [`transfer_from(self, from, to, token_id)`](#ERC721Component-transfer_from)
+- [`approve(self, to, token_id)`](#ERC721Component-approve)
+- [`set_approval_for_all(self, operator, approved)`](#ERC721Component-set_approval_for_all)
+- [`get_approved(self, token_id)`](#ERC721Component-get_approved)
+- [`is_approved_for_all(self, owner, operator)`](#ERC721Component-is_approved_for_all)
+
+#### ERC721MetadataImpl [!toc] [#ERC721Component-Embeddable-Impls-ERC721MetadataImpl]
+
+- [`name(self)`](#ERC721Component-name)
+- [`symbol(self)`](#ERC721Component-symbol)
+- [`token_uri(self, token_id)`](#ERC721Component-token_uri)
+
+#### ERC721CamelOnlyImpl [!toc] [#ERC721Component-Embeddable-Impls-ERC721CamelOnlyImpl]
+
+- [`balanceOf(self, account)`](#ERC721Component-balanceOf)
+- [`ownerOf(self, tokenId)`](#ERC721Component-ownerOf)
+- [`safeTransferFrom(self, from, to, tokenId, data)`](#ERC721Component-safeTransferFrom)
+- [`transferFrom(self, from, to, tokenId)`](#ERC721Component-transferFrom)
+- [`setApprovalForAll(self, operator, approved)`](#ERC721Component-setApprovalForAll)
+- [`getApproved(self, tokenId)`](#ERC721Component-getApproved)
+- [`isApprovedForAll(self, owner, operator)`](#ERC721Component-isApprovedForAll)
+
+#### ERC721MetadataCamelOnlyImpl [!toc] [#ERC721Component-Embeddable-Impls-ERC721MetadataCamelOnlyImpl]
+
+- [`tokenURI(self, tokenId)`](#ERC721Component-tokenURI)
+
+#### SRC5Impl [!toc] [#ERC721Component-Embeddable-Impls-SRC5Impl]
+
+- [`supports_interface(self, interface_id: felt252)`](./introspection#ISRC5-supports_interface)
+
+Internal functions
+
+#### InternalImpl [!toc] [#ERC721Component-InternalImpl]
+
+- [`initializer(self, name, symbol, base_uri)`](#ERC721Component-initializer)
+- [`initializer_no_metadata(self)`](#ERC721Component-initializer_no_metadata)
+- [`exists(self, token_id)`](#ERC721Component-exists)
+- [`transfer(self, from, to, token_id)`](#ERC721Component-transfer)
+- [`mint(self, to, token_id)`](#ERC721Component-mint)
+- [`safe_transfer(self, from, to, token_id, data)`](#ERC721Component-safe_transfer)
+- [`safe_mint(self, to, token_id, data)`](#ERC721Component-safe_mint)
+- [`burn(self, token_id)`](#ERC721Component-burn)
+- [`update(self, to, token_id, auth)`](#ERC721Component-update)
+- [`_owner_of(self, token_id)`](#ERC721Component-_owner_of)
+- [`_require_owned(self, token_id)`](#ERC721Component-_require_owned)
+- [`_approve(self, to, token_id, auth)`](#ERC721Component-_approve)
+- [`_approve_with_optional_event(self, to, token_id, auth, emit_event)`](#ERC721Component-_approve_with_optional_event)
+- [`_set_approval_for_all(self, owner, operator, approved)`](#ERC721Component-_set_approval_for_all)
+- [`_set_base_uri(self, base_uri)`](#ERC721Component-_set_base_uri)
+- [`_base_uri(self)`](#ERC721Component-_base_uri)
+- [`_is_authorized(self, owner, spender, token_id)`](#ERC721Component-_is_authorized)
+- [`_check_authorized(self, owner, spender, token_id)`](#ERC721Component-_check_authorized)
+
+Events
+
+IERC721
+
+- [`Approval(owner, approved, token_id)`](#ERC721Component-Approval)
+- [`ApprovalForAll(owner, operator, approved)`](#ERC721Component-ApprovalForAll)
+- [`Transfer(from, to, token_id)`](#ERC721Component-Transfer)
+
+#### Hooks [!toc] [#ERC721Component-Hooks]
+
+Hooks are functions which implementations can extend the functionality of the component source code. Every contract using ERC721Component is expected to provide an implementation of the ERC721HooksTrait. For basic token contracts, an empty implementation with no logic must be provided.
+
+You can use `openzeppelin_token::erc721::ERC721HooksEmptyImpl` which is already available as part of the library for this purpose.
+
+
+Function executed at the beginning of the [update](#ERC721Component-update) function prior to any other logic.
+
+
+
+Function executed at the end of the [update](#ERC721Component-update) function.
+
+
+#### [](#embeddable_functions)Embeddable functions [!toc] [#embeddable_functions]
+
+
+See [IERC721::balance\_of](#IERC721-balance_of).
+
+
+
+See [IERC721::owner\_of](#IERC721-owner_of).
+
+Requirements:
+
+- `token_id` exists.
+
+
+
+See [IERC721::safe\_transfer\_from](#IERC721-safe_transfer_from).
+
+Requirements:
+
+- Caller is either approved or the `token_id` owner.
+- `to` is not the zero address.
+- `from` is not the zero address.
+- `token_id` exists.
+- `to` is either an account contract or supports the [IERC721Receiver](#IERC721Receiver) interface.
+
+
+
+See [IERC721::transfer\_from](#IERC721-transfer_from).
+
+Requirements:
+
+- Caller either approved or the `token_id` owner.
+- `to` is not the zero address.
+- `from` is not the zero address.
+- `token_id` exists.
+
+
+
+See [IERC721::approve](#IERC721-approve).
+
+Requirements:
+
+- The caller is either an approved operator or the `token_id` owner.
+- `to` cannot be the token owner or the zero address.
+- `token_id` exists.
+
+
+
+See [IERC721::set\_approval\_for\_all](#IERC721-set_approval_for_all).
+
+Requirements:
+
+- `operator` is not the zero address.
+
+
+
+See [IERC721::get\_approved](#IERC721-get_approved).
+
+Requirements:
+
+- `token_id` exists.
+
+
+
+See [IERC721::is\_approved\_for\_all](#IERC721-is_approved_for_all).
+
+
+
+See [IERC721Metadata::name](#IERC721Metadata-name).
+
+
+
+See [IERC721Metadata::symbol](#IERC721Metadata-symbol).
+
+
+
+Returns the Uniform Resource Identifier (URI) for the `token_id` token. If a base URI is set, the resulting URI for each token will be the concatenation of the base URI and the token ID. For example, the base URI `https://token-cdn-domain/` would be returned as `https://token-cdn-domain/123` for token ID `123`.
+
+If the URI is not set for `token_id`, the return value will be an empty `ByteArray`.
+
+
+
+See [ERC721Component::balance\_of](#ERC721Component-balance_of).
+
+
+
+See [ERC721Component::owner\_of](#ERC721Component-owner_of).
+
+
+
+See [ERC721Component::safe\_transfer\_from](#ERC721Component-safe_transfer_from).
+
+
+
+See [ERC721Component::transfer\_from](#ERC721Component-transfer_from).
+
+
+
+See [ERC721Component::set\_approval\_for\_all](#ERC721Component-set_approval_for_all).
+
+
+
+See [ERC721Component::get\_approved](#ERC721Component-get_approved).
+
+
+
+See [ERC721Component::is\_approved\_for\_all](#ERC721Component-is_approved_for_all).
+
+
+
+See [ERC721Component::token\_uri](#ERC721Component-token_uri).
+
+
+#### [](#internal_functions)Internal functions [!toc] [#internal_functions]
+
+
+Initializes the contract by setting the token name and symbol. This should be used inside the contract's constructor.
+
+Most ERC721 contracts expose the [IERC721Metadata](#IERC721Metadata) interface which is what this initializer is meant to support. If the contract DOES NOT expose the [IERC721Metadata](#IERC721Metadata) interface, meaning the token does not have a name, symbol, or URI, the contract must instead use [initializer\_no\_metadata](#ERC721Component-initializer_no_metadata) in the constructor. Failure to abide by these instructions can lead to unexpected issues especially with UIs.
+
+
+
+Initializes the contract with no metadata by registering only the IERC721 interface.
+
+This initializer should ONLY be used during construction in the very specific instance when the contract does NOT expose the [IERC721Metadata](#IERC721Metadata) interface. Initializing a contract with this initializer means that tokens will not have a name, symbol, or URI.
+
+
+
+Internal function that returns whether `token_id` exists.
+
+Tokens start existing when they are minted ([mint](#ERC721-mint)), and stop existing when they are burned ([burn](#ERC721-burn)).
+
+
+
+Transfers `token_id` from `from` to `to`.
+
+Internal function without access restriction.
+
+This method may lead to the loss of tokens if `to` is not aware of the ERC721 protocol.
+
+Requirements:
+
+- `to` is not the zero address.
+- `from` is the token owner.
+- `token_id` exists.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Mints `token_id` and transfers it to `to`. Internal function without access restriction.
+
+This method may lead to the loss of tokens if `to` is not aware of the ERC721 protocol.
+
+Requirements:
+
+- `to` is not the zero address.
+- `token_id` does not exist.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Transfers ownership of `token_id` from `from` if `to` is either an account or `IERC721Receiver`.
+
+`data` is additional data, it has no specified format and is forwarded in `IERC721Receiver::on_erc721_received` to `to`.
+
+This method makes an external call to the recipient contract, which can lead to reentrancy vulnerabilities.
+
+Requirements:
+
+- `to` cannot be the zero address.
+- `from` must be the token owner.
+- `token_id` exists.
+- `to` is either an account contract or supports the `IERC721Receiver` interface.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Mints `token_id` if `to` is either an account or `IERC721Receiver`.
+
+`data` is additional data, it has no specified format and is forwarded in `IERC721Receiver::on_erc721_received` to `to`.
+
+This method makes an external call to the recipient contract, which can lead to reentrancy vulnerabilities.
+
+Requirements:
+
+- `token_id` does not exist.
+- `to` is either an account contract or supports the `IERC721Receiver` interface.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Destroys `token_id`. The approval is cleared when the token is burned.
+
+This internal function does not check if the caller is authorized to operate on the token.
+
+Requirements:
+
+- `token_id` exists.
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+
+
+Transfers `token_id` from its current owner to `to`, or alternatively mints (or burns) if the current owner (or `to`) is the zero address. Returns the owner of the `token_id` before the update.
+
+The `auth` argument is optional. If the value passed is non-zero, then this function will check that `auth` is either the owner of the token, or approved to operate on the token (by the owner).
+
+Emits a [Transfer](#IERC721-Transfer) event.
+
+This function can be extended using the `ERC721HooksTrait`, to add functionality before and/or after the transfer, mint, or burn.
+
+
+
+Internal function that returns the owner address of `token_id`.
+
+
+
+Version of [\_owner\_of](#ERC721Component-_owner_of) that panics if owner is the zero address.
+
+
+
+Approve `to` to operate on `token_id`
+
+The `auth` argument is optional. If the value passed is non-zero, then this function will check that `auth` is either the owner of the token, or approved to operate on all tokens held by this owner.
+
+Emits an [Approval](#IERC721-Approval) event.
+
+
+
+Variant of [\_approve](#ERC721Component-_approve) with an optional flag to enable or disable the `Approval` event. The event is not emitted in the context of transfers.
+
+If `auth` is zero and `emit_event` is false, this function will not check that the token exists.
+
+Requirements:
+
+- if `auth` is non-zero, it must be either the owner of the token or approved to operate on all of its tokens.
+
+May emit an [Approval](#IERC721-Approval) event.
+
+
+
+Enables or disables approval for `operator` to manage all of the `owner` assets.
+
+Requirements:
+
+- `operator` is not the zero address.
+
+Emits an [Approval](#IERC721-Approval) event.
+
+
+
+Internal function that sets the `base_uri`.
+
+
+
+Base URI for computing [token\_uri](#IERC721Metadata-token_uri).
+
+If set, the resulting URI for each token will be the concatenation of the base URI and the token ID. Returns an empty `ByteArray` if not set.
+
+
+
+Returns whether `spender` is allowed to manage `owner`'s tokens, or `token_id` in particular (ignoring whether it is owned by `owner`).
+
+This function assumes that `owner` is the actual owner of `token_id` and does not verify this assumption.
+
+
+
+Checks if `spender` can operate on `token_id`, assuming the provided `owner` is the actual owner.
+
+Requirements:
+
+- `owner` cannot be the zero address.
+- `spender` cannot be the zero address.
+- `spender` must be the owner of `token_id` or be approved to operate on it.
+
+This function assumes that `owner` is the actual owner of `token_id` and does not verify this assumption.
+
+
+#### [](#events_2)Events [!toc] [#events_2]
+
+
+See [IERC721::Approval](#IERC721-Approval).
+
+
+
+See [IERC721::ApprovalForAll](#IERC721-ApprovalForAll).
+
+
+
+See [IERC721::Transfer](#IERC721-Transfer).
+
+
+### `ERC721ReceiverComponent` [toc] [#ERC721ReceiverComponent]
+
+
+```rust
+use openzeppelin_token::erc721::ERC721ReceiverComponent;
+```
+
+ERC721Receiver component implementing [IERC721Receiver](#IERC721Receiver).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### ERCReceiverMixinImpl [!toc] [#ERC721ReceiverComponent-Embeddable-Impls-ERCReceiverMixinImpl]
+
+- [`ERC721ReceiverImpl`](#ERC721ReceiverComponent-Embeddable-Impls-ERC721ReceiverImpl)
+- [`ERC721ReceiverCamelImpl`](#ERC721ReceiverComponent-Embeddable-Impls-ERC721ReceiverCamelImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### ERC721ReceiverImpl [!toc] [#ERC721ReceiverComponent-Embeddable-Impls-ERC721ReceiverImpl]
+
+- [`on_erc721_received(self, operator, from, token_id, data)`](#ERC721ReceiverComponent-on_erc721_received)
+
+#### ERC721ReceiverCamelImpl [!toc] [#ERC721ReceiverComponent-Embeddable-Impls-ERC721ReceiverCamelImpl]
+
+- [`onERC721Received(self, operator, from, tokenId, data)`](#ERC721ReceiverComponent-onERC721Received)
+
+Internal Functions
+
+#### InternalImpl [!toc] [#ERC721ReceiverComponent-InternalImpl]
+
+- [`initializer(self)`](#ERC721ReceiverComponent-initializer)
+
+#### [](#embeddable_functions_2)Embeddable functions [!toc] [#embeddable_functions_2]
+
+
+Returns the `IERC721Receiver` interface ID.
+
+
+
+See [ERC721ReceiverComponent::on\_erc721\_received](#ERC721ReceiverComponent-on_erc721_received).
+
+
+#### [](#internal_functions_2)Internal functions [!toc] [#internal_functions_2]
+
+
+Registers the `IERC721Receiver` interface ID as supported through introspection.
+
+
+## Extensions
+
+### `ERC721EnumerableComponent` [toc] [#ERC721EnumerableComponent]
+
+
+```rust
+use openzeppelin_token::erc721::extensions::ERC721EnumerableComponent;
+```
+
+Extension of ERC721 as defined in the EIP that adds enumerability of all the token ids in the contract as well as all token ids owned by each account. This extension allows contracts to publish their entire list of NFTs and make them discoverable.
+
+Implementing [ERC721Component](#ERC721Component) is a requirement for this component to be implemented.
+
+To properly track token ids, this extension requires that the [ERC721EnumerableComponent::before\_update](#ERC721EnumerableComponent-before_update) function is called before every transfer, mint, or burn operation. For this, the [ERC721HooksTrait::before\_update](#ERC721Component-before_update) hook must be used. Here's how the hook should be implemented in a contract:
+
+```[
+#[starknet::contract]
+mod ERC721EnumerableContract {
+ (...)
+
+ component!(path: ERC721Component, storage: erc721, event: ERC721Event);
+ component!(path: ERC721EnumerableComponent, storage: erc721_enumerable, event: ERC721EnumerableEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ impl ERC721HooksImpl of ERC721Component::ERC721HooksTrait {
+ fn before_update(
+ ref self: ERC721Component::ComponentState,
+ to: ContractAddress,
+ token_id: u256,
+ auth: ContractAddress
+ ) {
+ let mut contract_state = self.get_contract_mut();
+ contract_state.erc721_enumerable.before_update(to, token_id);
+ }
+ }
+}
+```
+
+Embeddable Implementations
+
+#### ERC721EnumerableImpl [!toc] [#ERC721EnumerableComponent-Embeddable-Impls-ERC721EnumerableImpl]
+
+- [`total_supply(self)`](#ERC721EnumerableComponent-total_supply)
+- [`token_by_index(self, index)`](#ERC721EnumerableComponent-token_by_index)
+- [`token_of_owner_by_index(self, address, index)`](#ERC721EnumerableComponent-token_of_owner_by_index)
+
+Internal functions
+
+#### InternalImpl [!toc] [#ERC721EnumerableComponent-InternalImpl]
+
+- [`initializer(self)`](#ERC721EnumerableComponent-initializer)
+- [`before_update(self, to, token_id)`](#ERC721EnumerableComponent-before_update)
+- [`all_tokens_of_owner(self, owner)`](#ERC721EnumerableComponent-all_tokens_of_owner)
+- [`_add_token_to_owner_enumeration(self, to, token_id)`](#ERC721EnumerableComponent-_add_token_to_owner_enumeration)
+- [`_add_token_to_all_tokens_enumeration(self, token_id)`](#ERC721EnumerableComponent-_add_token_to_all_tokens_enumeration)
+- [`_remove_token_from_owner_enumeration(self, from, token_id)`](#ERC721EnumerableComponent-_remove_token_from_owner_enumeration)
+- [`_remove_token_from_all_tokens_enumeration(self, token_id)`](#ERC721EnumerableComponent-_remove_token_from_all_tokens_enumeration)
+
+#### [](#ERC721EnumerableComponent-Embeddable-functions)Embeddable functions [!toc] [#ERC721EnumerableComponent-Embeddable-functions]
+
+
+Returns the current amount of votes that `account` has.
+
+
+
+See [IERC721Enumerable::token\_by\_index](#IERC721Enumerable-token_by_index).
+
+Requirements:
+
+- `index` is less than the total token supply.
+
+
+
+See [IERC721Enumerable::token\_of\_owner\_by\_index](#IERC721Enumerable-token_of_owner_by_index).
+
+Requirements:
+
+- `index` is less than `owner`'s token balance.
+- `owner` is not the zero address.
+
+
+#### [](#ERC721EnumerableComponent-Internal-functions)Internal functions [!toc] [#ERC721EnumerableComponent-Internal-functions]
+
+
+Registers the `IERC721Enumerable` interface ID as supported through introspection.
+
+
+
+Updates the ownership and token-tracking data structures.
+
+When a token is minted (or burned), `token_id` is added to (or removed from) the token-tracking structures.
+
+When a token is transferred, minted, or burned, the ownership-tracking data structures reflect the change in ownership of `token_id`.
+
+This must be added to the implementing contract's [ERC721HooksTrait::before\_update](#ERC721Component-before_update) hook.
+
+
+
+Returns a list of all token ids owned by the specified `owner`. This function provides a more efficient alternative to calling `ERC721::balance_of` and iterating through tokens with `ERC721Enumerable::token_of_owner_by_index`.
+
+Requirements:
+
+- `owner` is not the zero address.
+
+
+
+Adds token to this extension's ownership-tracking data structures.
+
+
+
+Adds token to this extension's token-tracking data structures.
+
+
+
+Removes a token from this extension's ownership-tracking data structures.
+
+This has 0(1) time complexity but alters the indexed order of owned tokens by swapping `token_id` and the index thereof with the last token id and the index thereof e.g. removing `1` from `[1, 2, 3, 4]` results in `[4, 2, 3]`.
+
+
+
+Removes `token_id` from this extension's token-tracking data structures.
+
+This has 0(1) time complexity but alters the indexed order by swapping `token_id` and the index thereof with the last token id and the index thereof e.g. removing `1` from `[1, 2, 3, 4]` results in `[4, 2, 3]`.
+
+
+## Presets
+
+### `ERC721Upgradeable` [toc] [#ERC721Upgradeable]
+
+
+```rust
+use openzeppelin_presets::ERC721Upgradeable;
+```
+
+Upgradeable ERC721 contract leveraging [ERC721Component](#ERC721Component).
+
+[Sierra class hash](../presets)
+
+```text
+{{ERC721UpgradeableClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, name, symbol, recipient, token_ids, base_uri, owner)`](#ERC721Upgradeable-constructor)
+
+Embedded Implementations
+
+ERC721MixinImpl
+
+- [`ERC721MixinImpl`](#ERC721Component-Embeddable-Mixin-Impl)
+
+OwnableMixinImpl
+
+- [`OwnableMixinImpl`](./access#OwnableComponent-Mixin-Impl)
+
+External Functions
+
+- [`upgrade(self, new_class_hash)`](#ERC721Upgradeable-upgrade)
+
+#### [](#ERC721Upgradeable-constructor-section)Constructor [!toc] [#ERC721Upgradeable-constructor-section]
+
+
+Sets the `name` and `symbol`. Mints `token_ids` tokens to `recipient` and sets the `base_uri`. Assigns `owner` as the contract owner with permissions to upgrade.
+
+
+#### [](#ERC721Upgradeable-external-functions)External functions [!toc] [#ERC721Upgradeable-external-functions]
+
+
+Upgrades the contract to a new implementation given by `new_class_hash`.
+
+Requirements:
+
+- The caller is the contract owner.
+- `new_class_hash` cannot be zero.
+
diff --git a/docs/content/contracts-cairo/2.x/api/finance.mdx b/docs/content/contracts-cairo/2.x/api/finance.mdx
new file mode 100644
index 00000000..a41e0c64
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/finance.mdx
@@ -0,0 +1,328 @@
+---
+title: Finance
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate includes primitives for financial systems.
+
+## Interfaces
+
+### `IVesting` [toc] [#IVesting]
+
+
+
+```rust
+use openzeppelin_finance::vesting::interface::IVesting;
+```
+
+Common interface for contracts implementing the vesting functionality.
+
+Functions
+
+- [`start()`](#IVesting-start)
+- [`cliff()`](#IVesting-cliff)
+- [`duration()`](#IVesting-duration)
+- [`end()`](#IVesting-end)
+- [`released(token)`](#IVesting-released)
+- [`releasable(token)`](#IVesting-releasable)
+- [`vested_amount(token, timestamp)`](#IVesting-vested_amount)
+- [`release(token)`](#IVesting-release)
+
+Events
+
+- [`AmountReleased(token, amount)`](#IVesting-AmountReleased)
+
+#### Functions [!toc] [#IVesting-Functions]
+
+
+Returns the timestamp marking the beginning of the vesting period.
+
+
+
+Returns the timestamp marking the end of the cliff period.
+
+
+
+Returns the total duration of the vesting period.
+
+
+
+Returns the timestamp marking the end of the vesting period.
+
+
+
+Returns the already released amount for a given `token`.
+
+
+
+Returns the amount of a given `token` that can be released at the time of the call.
+
+
+
+Returns the total vested amount of a specified `token` at a given `timestamp`.
+
+
+
+Releases the amount of a given `token` that has already vested and returns that amount.
+
+May emit an [AmountReleased](#IVesting-AmountReleased) event.
+
+
+#### Events [!toc] [#IVesting-Events]
+
+
+Emitted when vested tokens are released to the beneficiary.
+
+
+## [](#vesting)Vesting
+
+### `VestingComponent` [toc] [#VestingComponent]
+
+
+
+```rust
+use openzeppelin_finance::vesting::VestingComponent;
+```
+
+Vesting component implementing the [`IVesting`](#IVesting) interface.
+
+Vesting Schedule Trait Implementations
+
+#### functions [!toc] [#VestingComponent-Vesting-Schedule-functions]
+
+- [`calculate_vested_amount(self, token, total_allocation, timestamp, start, duration, cliff)`](#VestingComponent-calculate_vested_amount)
+
+Embeddable Implementations
+
+#### VestingImpl [!toc] [#VestingComponent-Embeddable-Impls-VestingImpl]
+
+- [`start(self)`](#VestingComponent-start)
+- [`cliff(self)`](#VestingComponent-cliff)
+- [`duration(self)`](#VestingComponent-duration)
+- [`end(self)`](#VestingComponent-end)
+- [`released(self, token)`](#VestingComponent-released)
+- [`releasable(self, token)`](#VestingComponent-releasable)
+- [`vested_amount(self, token, timestamp)`](#VestingComponent-vested_amount)
+- [`release(self, token)`](#VestingComponent-release)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#VestingComponent-InternalImpl]
+
+- [`initializer(self, start, duration, cliff_duration)`](#VestingComponent-initializer)
+- [`resolve_vested_amount(self, token, timestamp)`](#VestingComponent-resolve_vested_amount)
+
+A trait that defines the logic for calculating the vested amount based on a given timestamp.
+
+You can read more about the trait's purpose and how to use it [here](../finance#vesting-schedule).
+
+
+Calculates and returns the vested amount at a given `timestamp` based on the core vesting parameters.
+
+
+#### Functions [!toc] [#VestingComponent-Functions]
+
+
+Returns the timestamp marking the beginning of the vesting period.
+
+
+
+Returns the timestamp marking the end of the cliff period.
+
+
+
+Returns the total duration of the vesting period.
+
+
+
+Returns the timestamp marking the end of the vesting period.
+
+
+
+Returns the already released amount for a given `token`.
+
+
+
+Returns the amount of a given `token` that can be released at the time of the call.
+
+
+
+Returns the total vested amount of a specified `token` at a given `timestamp`.
+
+
+
+Releases the amount of a given `token` that has already vested and returns that amount.
+
+If the releasable amount is zero, this function won't emit the event or attempt to transfer the tokens.
+
+Requirements:
+
+- `transfer` call to the `token` must return `true` indicating a successful transfer.
+
+May emit an [AmountReleased](#IVesting-AmountReleased) event.
+
+
+#### Internal functions [!toc] [#VestingComponent-Internal-Functions]
+
+
+Initializes the component by setting the vesting `start`, `duration` and `cliff_duration`. To prevent reinitialization, this should only be used inside of a contract's constructor.
+
+Requirements:
+
+- `cliff_duration` must be less than or equal to `duration`.
+
+
+
+Returns the vested amount that's calculated using the [VestingSchedule](#VestingComponent-Vesting-Schedule) trait implementation.
+
+
+### `LinearVestingSchedule` [toc] [#LinearVestingSchedule]
+
+
+
+```rust
+use openzeppelin_finance::vesting::LinearVestingSchedule;
+```
+
+Defines the logic for calculating the vested amount, incorporating a cliff period. It returns 0 before the cliff ends. After the cliff period, the vested amount returned is directly proportional to the time passed since the start of the vesting schedule.
+
+## [](#presets)Presets
+
+### `VestingWallet` [toc] [#VestingWallet]
+
+
+
+```rust
+use openzeppelin::presets::VestingWallet;
+```
+
+A non-upgradable contract leveraging [VestingComponent](#VestingComponent) and [OwnableComponent](./access#OwnableComponent).
+
+The contract is intentionally designed to be non-upgradable to ensure that neither the vesting initiator nor the vesting beneficiary can modify the vesting schedule without the consent of the other party.
+
+[Sierra class hash](../presets)
+
+```text
+{{VestingWalletClassHash}}
+```
+
+Constructor
+
+- [`constructor(self, beneficiary, start, duration, cliff_duration)`](#VestingWallet-constructor)
+
+Embedded Implementations
+
+VestingComponent
+
+- [`VestingImpl`](#VestingComponent-Embeddable-Impls-VestingImpl)
+
+OwnableComponent
+
+- [`OwnableMixinImpl`](./access#OwnableComponent-Mixin-Impl)
+
+#### Constructor [!toc] [#VestingWallet-constructor-section]
+
+
+Initializes the vesting component by setting the vesting `start`, `duration` and `cliff_duration`. Assigns `beneficiary` as the contract owner and the vesting beneficiary.
+
+Requirements:
+
+- `cliff_duration` must be less than or equal to `duration`.
+
diff --git a/docs/content/contracts-cairo/2.x/api/governance.mdx b/docs/content/contracts-cairo/2.x/api/governance.mdx
new file mode 100644
index 00000000..f0bd318f
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/governance.mdx
@@ -0,0 +1,4059 @@
+---
+title: Governance
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate includes primitives for on-chain governance.
+
+## Interfaces
+
+### `IGovernor` [toc] [#IGovernor]
+
+
+
+```rust
+use openzeppelin_governance::governor::interface::IGovernor;
+```
+
+Interface of a governor contract.
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x1100a1f8546595b5bd75a6cd8fcc5b015370655e66f275963321c5cd0357ac9
+```
+
+Functions
+
+- [`name()`](#IGovernor-name)
+- [`version()`](#IGovernor-version)
+- [`COUNTING_MODE()`](#IGovernor-COUNTING_MODE)
+- [`hash_proposal(calls, description_hash)`](#IGovernor-hash_proposal)
+- [`state(proposal_id)`](#IGovernor-state)
+- [`proposal_threshold()`](#IGovernor-proposal_threshold)
+- [`proposal_snapshot(proposal_id)`](#IGovernor-proposal_snapshot)
+- [`proposal_deadline(proposal_id)`](#IGovernor-proposal_deadline)
+- [`proposal_proposer(proposal_id)`](#IGovernor-proposal_proposer)
+- [`proposal_eta(proposal_id)`](#IGovernor-proposal_eta)
+- [`proposal_needs_queuing(proposal_id)`](#IGovernor-proposal_needs_queuing)
+- [`voting_delay()`](#IGovernor-voting_delay)
+- [`voting_period()`](#IGovernor-voting_period)
+- [`quorum(timepoint)`](#IGovernor-quorum)
+- [`get_votes(account, timepoint)`](#IGovernor-get_votes)
+- [`get_votes_with_params(account, timepoint, params)`](#IGovernor-get_votes_with_params)
+- [`has_voted(proposal_id, account)`](#IGovernor-has_voted)
+- [`propose(calls, description)`](#IGovernor-propose)
+- [`queue(calls, description_hash)`](#IGovernor-queue)
+- [`execute(calls, description_hash)`](#IGovernor-execute)
+- [`cancel(proposal_id, description_hash)`](#IGovernor-cancel)
+- [`cast_vote(proposal_id, support)`](#IGovernor-cast_vote)
+- [`cast_vote_with_reason(proposal_id, support, reason)`](#IGovernor-cast_vote_with_reason)
+- [`cast_vote_with_reason_and_params(proposal_id, support, reason, params)`](#IGovernor-cast_vote_with_reason_and_params)
+- [`cast_vote_by_sig(proposal_id, support, reason, signature)`](#IGovernor-cast_vote_by_sig)
+- [`cast_vote_with_reason_and_params_by_sig(proposal_id, support, reason, params, signature)`](#IGovernor-cast_vote_with_reason_and_params_by_sig)
+- [`nonces(voter)`](#IGovernor-nonces)
+- [`relay(call)`](#IGovernor-relay)
+
+Events
+
+- [`ProposalCreated(proposal_id, proposer, calls, signatures, vote_start, vote_end, description)`](#IGovernor-ProposalCreated)
+- [`ProposalQueued(proposal_id, eta_seconds)`](#IGovernor-ProposalQueued)
+- [`ProposalExecuted(proposal_id)`](#IGovernor-ProposalExecuted)
+- [`ProposalCanceled(proposal_id)`](#IGovernor-ProposalCanceled)
+- [`VoteCast(voter, proposal_id, support, weight, reason)`](#IGovernor-VoteCast)
+- [`VoteCastWithParams(voter, proposal_id, support, weight, reason, params)`](#IGovernor-VoteCastWithParams)
+
+#### Functions [!toc] [#IGovernor-Functions]
+
+
+Name of the governor instance (used in building the [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) domain separator).
+
+
+
+Version of the governor instance (used in building [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) domain separator).
+
+
+
+A description of the possible `support` values for `cast_vote` and the way these votes are counted, meant to be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
+
+There are 2 standard keys: `support` and `quorum`.
+
+- `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
+- `quorum=bravo` means that only For votes are counted towards quorum.
+- `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
+
+If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique name that describes the behavior. For example:
+
+- `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
+- `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
+
+
+The string can be decoded by the standard [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) JavaScript class.
+
+
+
+
+Hashing function used to (re)build the proposal id from the proposal details.
+
+
+
+Returns the state of a proposal, given its id.
+
+
+
+The number of votes required in order for a voter to become a proposer.
+
+
+
+Timepoint used to retrieve user's votes and quorum. If using block number, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the following block.
+
+
+
+Timepoint at which votes close. If using block number, votes close at the end of this block, so it is possible to cast a vote during this block.
+
+
+
+The account that created a proposal.
+
+
+
+The time when a queued proposal becomes executable ("ETA"). Unlike `proposal_snapshot` and `proposal_deadline`, this doesn't use the governor clock, and instead relies on the executor's clock which may be different. In most cases this will be a timestamp.
+
+
+
+Whether a proposal needs to be queued before execution. This indicates if the proposal needs to go through a timelock.
+
+
+
+Delay between when a proposal is created and when the vote starts. The unit this duration is expressed in depends on the clock (see [ERC-6372](https://eips.ethereum.org/EIPS/eip-6372)) this contract uses.
+
+This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a proposal starts.
+
+
+
+Delay between when a vote starts and when it ends. The unit this duration is expressed in depends on the clock (see [ERC-6372](https://eips.ethereum.org/EIPS/eip-6372)) this contract uses.
+
+The `voting_delay` can delay the start of the vote. This must be considered when setting the voting duration compared to the voting delay.
+
+This value is stored when the proposal is submitted so that possible changes to the value do not affect proposals that have already been submitted.
+
+
+
+Minimum number of votes required for a proposal to be successful.
+
+The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows the quorum to scale depending on values such as the total supply of a token at this timepoint.
+
+
+
+Returns the voting power of an `account` at a specific `timepoint`.
+
+This can be implemented in a number of ways, for example by reading the delegated balance from one (or multiple) `ERC20Votes` tokens.
+
+
+
+Returns the voting power of an `account` at a specific `timepoint`, given additional encoded parameters.
+
+
+
+Returns whether an `account` has cast a vote on a proposal.
+
+
+
+Creates a new proposal. Vote starts after a delay specified by `voting_delay` and lasts for a duration specified by `voting_period`.
+
+The state of the Governor and targets may change between the proposal creation and its execution. This may be the result of third party actions on the targeted contracts, or other governor proposals. For example, the balance of this contract could be updated or its access control permissions may be modified, possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough value to cover a proposal with multiple transfers).
+
+Returns the id of the proposal.
+
+
+
+Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing is not necessary, this function may revert.
+
+Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
+
+Returns the id of the proposal.
+
+
+
+Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the deadline to be reached. Depending on the governor it might also be required that the proposal was queued and that some delay passed.
+
+Some modules can modify the requirements for execution, for example by adding an additional timelock (See `timelock_controller`).
+
+Returns the id of the proposal.
+
+
+
+Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e. before the vote starts.
+
+Returns the id of the proposal.
+
+
+
+Cast a vote on a proposal.
+
+Returns the weight of the vote.
+
+
+
+Cast a vote on a proposal with a `reason`.
+
+Returns the weight of the vote.
+
+
+
+Cast a vote on a proposal with a reason and additional encoded parameters.
+
+Returns the weight of the vote.
+
+
+
+Cast a vote on a proposal using the voter's signature.
+
+Returns the weight of the vote.
+
+
+
+Cast a vote on a proposal with a reason and additional encoded parameters using the `voter`'s signature.
+
+Returns the weight of the vote.
+
+
+
+Returns the next unused nonce for an address.
+
+
+
+Relays a transaction or function call to an arbitrary target.
+
+In cases where the governance executor is some contract other than the governor itself, like when using a timelock, this function can be invoked in a governance proposal to recover tokens that were sent to the governor contract by mistake.
+
+If the executor is simply the governor itself, use of `relay` is redundant.
+
+
+#### Events [!toc] [#IGovernor-Events]
+
+
+Emitted when a proposal is created.
+
+
+
+Emitted when a proposal is queued.
+
+
+
+Emitted when a proposal is executed.
+
+
+
+Emitted when a proposal is canceled.
+
+
+
+Emitted when a vote is cast.
+
+
+
+Emitted when a vote is cast with params.
+
+
+### `IMultisig` [toc] [#IMultisig]
+
+
+
+```rust
+use openzeppelin_governance::multisig::interface::IMultisig;
+```
+
+Interface of a multisig contract.
+
+Functions
+
+- [`get_quorum()`](#IMultisig-get_quorum)
+- [`is_signer(signer)`](#IMultisig-is_signer)
+- [`get_signers()`](#IMultisig-get_signers)
+- [`is_confirmed(id)`](#IMultisig-is_confirmed)
+- [`is_confirmed_by(id, signer)`](#IMultisig-is_confirmed_by)
+- [`is_executed(id)`](#IMultisig-is_executed)
+- [`get_submitted_block(id)`](#IMultisig-get_submitted_block)
+- [`get_transaction_state(id)`](#IMultisig-get_transaction_state)
+- [`get_transaction_confirmations(id)`](#IMultisig-get_transaction_confirmations)
+- [`hash_transaction(to, selector, calldata, salt)`](#IMultisig-hash_transaction)
+- [`hash_transaction_batch(calls, salt)`](#IMultisig-hash_transaction_batch)
+- [`add_signers(new_quorum, signers_to_add)`](#IMultisig-add_signers)
+- [`remove_signers(new_quorum, signers_to_remove)`](#IMultisig-remove_signers)
+- [`replace_signer(signer_to_remove, signer_to_add)`](#IMultisig-replace_signer)
+- [`change_quorum(new_quorum)`](#IMultisig-change_quorum)
+- [`submit_transaction(to, selector, calldata, salt)`](#IMultisig-submit_transaction)
+- [`submit_transaction_batch(calls, salt)`](#IMultisig-submit_transaction_batch)
+- [`confirm_transaction(id)`](#IMultisig-confirm_transaction)
+- [`revoke_confirmation(id)`](#IMultisig-revoke_confirmation)
+- [`execute_transaction(to, selector, calldata, salt)`](#IMultisig-execute_transaction)
+- [`execute_transaction_batch(calls, salt)`](#IMultisig-execute_transaction_batch)
+
+Events
+
+- [`SignerAdded(signer)`](#IMultisig-SignerAdded)
+- [`SignerRemoved(signer)`](#IMultisig-SignerRemoved)
+- [`QuorumUpdated(old_quorum, new_quorum)`](#IMultisig-QuorumUpdated)
+- [`TransactionSubmitted(id, signer)`](#IMultisig-TransactionSubmitted)
+- [`TransactionConfirmed(id, signer)`](#IMultisig-TransactionConfirmed)
+- [`ConfirmationRevoked(id, signer)`](#IMultisig-ConfirmationRevoked)
+- [`TransactionExecuted(id)`](#IMultisig-TransactionExecuted)
+- [`CallSalt(id, salt)`](#IMultisig-CallSalt)
+
+#### Functions [!toc] [#IMultisig-Functions]
+
+
+Returns the current quorum value. The quorum is the minimum number of confirmations required to approve a transaction.
+
+
+
+Returns whether the given `signer` is registered. Only registered signers can submit, confirm, or execute transactions.
+
+
+
+Returns the list of all current signers.
+
+
+
+Returns whether the transaction with the given `id` has been confirmed.
+
+
+
+Returns whether the transaction with the given `id` has been confirmed by the specified `signer`.
+
+
+
+Returns whether the transaction with the given `id` has been executed.
+
+
+
+Returns the block number when the transaction with the given `id` was submitted.
+
+
+
+Returns the current state of the transaction with the given `id`.
+
+
+
+Returns the number of confirmations from registered signers for the transaction with the specified `id`.
+
+
+
+Returns the computed identifier of a transaction containing a single call.
+
+
+
+Returns the computed identifier of a transaction containing a batch of calls.
+
+
+
+Adds new signers and updates the quorum.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be less than or equal to the total number of signers after addition.
+
+Emits a [SignerAdded](#IMultisig-SignerAdded) event for each signer added.
+
+Emits a [QuorumUpdated](#IMultisig-QuorumUpdated) event if the quorum changes.
+
+
+
+Removes signers and updates the quorum.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be less than or equal to the total number of signers after removal.
+
+Emits a [SignerRemoved](#IMultisig-SignerRemoved) event for each signer removed.
+
+Emits a [QuorumUpdated](#IMultisig-QuorumUpdated) event if the quorum changes.
+
+
+
+Replaces an existing signer with a new signer.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `signer_to_remove` must be an existing signer.
+- `signer_to_add` must not be an existing signer.
+
+Emits a [SignerRemoved](#IMultisig-SignerRemoved) event for the removed signer.
+
+Emits a [SignerAdded](#IMultisig-SignerAdded) event for the new signer.
+
+
+
+Updates the quorum value to `new_quorum` if it differs from the current quorum.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be non-zero.
+- `new_quorum` must be less than or equal to the total number of signers.
+
+Emits a [QuorumUpdated](#IMultisig-QuorumUpdated) event if the quorum changes.
+
+
+
+Submits a new transaction for confirmation.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must not have been submitted before.
+
+Emits a [TransactionSubmitted](#IMultisig-TransactionSubmitted) event.
+
+Emits a [CallSalt](#IMultisig-CallSalt) event if `salt` is not zero.
+
+
+
+
+Submits a new batch transaction for confirmation.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must not have been submitted before.
+
+Emits a [TransactionSubmitted](#IMultisig-TransactionSubmitted) event.
+
+Emits a [CallSalt](#IMultisig-CallSalt) event if `salt` is not zero.
+
+
+
+Confirms a transaction with the given `id`.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must exist and not be executed.
+- The caller must not have already confirmed the transaction.
+
+Emits a [TransactionConfirmed](#IMultisig-TransactionConfirmed) event.
+
+
+
+Revokes a previous confirmation for a transaction with the given `id`.
+
+Requirements:
+
+- The transaction must exist and not be executed.
+- The caller must have previously confirmed the transaction.
+
+Emits a [ConfirmationRevoked](#IMultisig-ConfirmationRevoked) event.
+
+
+
+Executes a confirmed transaction.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must be confirmed and not yet executed.
+
+Emits a [TransactionExecuted](#IMultisig-TransactionExecuted) event.
+
+
+
+Executes a confirmed batch transaction.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must be confirmed and not yet executed.
+
+Emits a [TransactionExecuted](#IMultisig-TransactionExecuted) event.
+
+
+#### Events [!toc] [#IMultisig-Events]
+
+
+Emitted when a new `signer` is added.
+
+
+
+Emitted when a `signer` is removed.
+
+
+
+Emitted when the `quorum` value is updated.
+
+
+
+Emitted when a new transaction is submitted by a `signer`.
+
+
+
+Emitted when a transaction is confirmed by a `signer`.
+
+
+
+Emitted when a `signer` revokes his confirmation.
+
+
+
+Emitted when a transaction is executed.
+
+
+
+Emitted when a new transaction is submitted with non-zero salt.
+
+
+### `ITimelock` [toc] [#ITimelock]
+
+
+
+```rust
+use openzeppelin_governance::timelock::interface::ITimelock;
+```
+
+Interface of a timelock contract.
+
+Functions
+
+- [`is_operation(id)`](#ITimelock-is_operation)
+- [`is_operation_pending(id)`](#ITimelock-is_operation_pending)
+- [`is_operation_ready(id)`](#ITimelock-is_operation_ready)
+- [`is_operation_done(id)`](#ITimelock-is_operation_done)
+- [`get_timestamp(id)`](#ITimelock-get_timestamp)
+- [`get_operation_state(id)`](#ITimelock-get_operation_state)
+- [`get_min_delay()`](#ITimelock-get_min_delay)
+- [`hash_operation(call, predecessor, salt)`](#ITimelock-hash_operation)
+- [`hash_operation_batch(calls, predecessor, salt)`](#ITimelock-hash_operation_batch)
+- [`schedule(call, predecessor, salt, delay)`](#ITimelock-schedule)
+- [`schedule_batch(calls, predecessor, salt, delay)`](#ITimelock-schedule_batch)
+- [`cancel(id)`](#ITimelock-cancel)
+- [`execute(call, predecessor, salt)`](#ITimelock-execute)
+- [`execute_batch(calls, predecessor, salt)`](#ITimelock-execute_batch)
+- [`update_delay(new_delay)`](#ITimelock-update_delay)
+
+Events
+
+- [`CallScheduled(id, index, call, predecessor, delay)`](#ITimelock-CallScheduled)
+- [`CallExecuted(id, index, call)`](#ITimelock-CallExecuted)
+- [`CallSalt(id, salt)`](#ITimelock-CallSalt)
+- [`CallCancelled(id)`](#ITimelock-CallCancelled)
+- [`MinDelayChanged(old_duration, new_duration)`](#ITimelock-MinDelayChanged)
+
+#### Functions [!toc] [#ITimelock-Functions]
+
+
+Returns whether `id` corresponds to a registered operation. This includes the OperationStates: `Waiting`, `Ready`, and `Done`.
+
+
+
+Returns whether the `id` OperationState is pending or not. Note that a pending operation may be either `Waiting` or `Ready`.
+
+
+
+Returns whether the `id` OperationState is `Ready` or not.
+
+
+
+Returns whether the `id` OperationState is `Done` or not.
+
+
+
+Returns the timestamp at which `id` becomes `Ready`.
+
+`0` means the OperationState is `Unset` and `1` means the OperationState is `Done`.
+
+
+
+
+Returns the current state of the operation with the given `id`.
+
+The possible states are:
+
+- `Unset`: the operation has not been scheduled or has been canceled.
+- `Waiting`: the operation has been scheduled and is pending the scheduled delay.
+- `Ready`: the timer has expired, and the operation is eligible for execution.
+- `Done`: the operation has been executed.
+
+
+
+Returns the minimum delay in seconds for an operation to become valid. This value can be changed by executing an operation that calls `update_delay`.
+
+
+
+Returns the identifier of an operation containing a single transaction.
+
+
+
+Returns the identifier of an operation containing a batch of transactions.
+
+
+
+Schedule an operation containing a single transaction.
+
+Requirements:
+
+- The caller must have the `PROPOSER_ROLE` role.
+
+Emits [CallScheduled](#ITimelock-CallScheduled) event. Emits [CallSalt](#ITimelock-CallSalt) event if `salt` is not zero.
+
+
+
+Schedule an operation containing a batch of transactions.
+
+Requirements:
+
+- The caller must have the `PROPOSER_ROLE` role.
+
+Emits one [CallScheduled](#ITimelock-CallScheduled) event for each transaction in the batch. Emits [CallSalt](#ITimelock-CallSalt) event if `salt` is not zero.
+
+
+
+Cancels an operation. A canceled operation returns to `Unset` OperationState.
+
+Requirements:
+
+- The caller must have the `CANCELLER_ROLE` role.
+- `id` must be a pending operation.
+
+Emits a [CallCancelled](#ITimelock-CallCancelled) event.
+
+
+
+Execute a (Ready) operation containing a single Call.
+
+Requirements:
+
+- Caller must have `EXECUTOR_ROLE`.
+- `id` must be in Ready OperationState.
+- `predecessor` must either be `0` or in Done OperationState.
+
+Emits a [CallExecuted](#ITimelock-CallExecuted) event.
+
+This function can reenter, but it doesn't pose a risk because [`_after_call(self: @ContractState, id: felt252)` internal](#TimelockControllerComponent-_after_call) checks that the proposal is pending, thus any modifications to the operation during reentrancy should be caught.
+
+
+
+Execute a (Ready) operation containing a batch of Calls.
+
+Requirements:
+
+- Caller must have `EXECUTOR_ROLE`.
+- `id` must be in Ready OperationState.
+- `predecessor` must either be `0` or in Done OperationState.
+
+Emits a [CallExecuted](#ITimelock-CallExecuted) event for each Call.
+
+This function can reenter, but it doesn't pose a risk because `_after_call` checks that the proposal is pending, thus any modifications to the operation during reentrancy should be caught.
+
+
+
+Changes the minimum timelock duration for future operations.
+
+Requirements:
+
+- The caller must be the timelock itself. This can only be achieved by scheduling and later executing an operation where the timelock is the target and the data is the serialized call to this function.
+
+Emits a [MinDelayChanged](#ITimelock-MinDelayChanged) event.
+
+
+#### Events [!toc] [#ITimelock-Events]
+
+
+Emitted when `call` is scheduled as part of operation `id`.
+
+
+
+Emitted when `call` is performed as part of operation `id`.
+
+
+
+Emitted when a new proposal is scheduled with non-zero salt.
+
+
+
+Emitted when operation `id` is cancelled.
+
+
+
+Emitted when the minimum delay for future operations is modified.
+
+
+### `IVotes` [toc] [#IVotes]
+
+
+
+```rust
+use openzeppelin_governance::votes::interface::IVotes;
+```
+
+Common interface for Votes-enabled contracts.
+
+Functions
+
+- [`get_votes(account)`](#IVotes-get_votes)
+- [`get_past_votes(account, timepoint)`](#IVotes-get_past_votes)
+- [`get_past_total_supply(timepoint)`](#IVotes-get_past_total_supply)
+- [`delegates(account)`](#IVotes-delegates)
+- [`delegate(delegatee)`](#IVotes-delegate)
+- [`delegate_by_sig(delegator, delegatee, nonce, expiry, signature)`](#IVotes-delegate_by_sig)
+- [`clock()`](#IVotes-clock)
+- [`CLOCK_MODE()`](#IVotes-CLOCK_MODE)
+
+#### Functions [!toc] [#IVotes-Functions]
+
+
+Returns the current amount of votes that `account` has.
+
+
+
+Returns the amount of votes that `account` had at a specific moment in the past.
+
+
+
+Returns the total supply of votes available at a specific moment in the past.
+
+This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. Votes that have not been delegated are still part of total supply, even though they would not participate in a vote.
+
+
+
+Returns the delegate that `account` has chosen.
+
+
+
+Delegates votes from the sender to `delegatee`.
+
+
+
+Delegates votes from `delegator` to `delegatee` through a [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) message signature validation.
+
+
+
+Returns the current timepoint determined by the contract's operational mode, intended for use in time-sensitive logic. See [ERC-6372#clock](https://eips.ethereum.org/EIPS/eip-6372#clock).
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the contract is operating in. See [ERC-6372#CLOCK\_MODE](https://eips.ethereum.org/EIPS/eip-6372#clock_mode).
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+## [](#governor)Governor
+
+This modular system of Governor components allows the deployment of easily customizable on-chain voting protocols.
+
+For a walkthrough of how to implement a Governor, check the [Governor](../governance/governor) page.
+
+### `GovernorComponent` [toc] [#GovernorComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::GovernorComponent;
+```
+
+Core of the governance system.
+
+The extension traits presented below are what make the GovernorComponent a modular and configurable system. The embeddable and internal implementations depends on these trait. They can be implemented locally in the contract, or through the provided library [component extensions](#governor_extensions).
+
+Implementing [SRC5Component](./introspection#SRC5Component) is a requirement for this component to be implemented.
+
+Extensions traits
+
+#### GovernorSettingsTrait [!toc] [#GovernorComponent-GovernorSettingsTrait]
+
+- [`voting_delay(self)`](#GovernorComponent-GovernorSettingsTrait-voting_delay)
+- [`voting_period(self)`](#GovernorComponent-GovernorSettingsTrait-voting_period)
+- [`proposal_threshold(self)`](#GovernorComponent-GovernorSettingsTrait-proposal_threshold)
+
+#### GovernorQuorumTrait [!toc] [#GovernorComponent-GovernorQuorumTrait]
+
+- [`quorum(self, timepoint)`](#GovernorComponent-GovernorQuorumTrait-quorum)
+
+#### GovernorCountingTrait [!toc] [#GovernorComponent-GovernorCountingTrait]
+
+- [`counting_mode(self)`](#GovernorComponent-GovernorCountingTrait-counting_mode)
+- [`count_vote(self, proposal_id, account, support, total_weight, params)`](#GovernorComponent-GovernorCountingTrait-count_vote)
+- [`has_voted(self, proposal_id, account)`](#GovernorComponent-GovernorCountingTrait-has_voted)
+- [`quorum_reached(self, proposal_id)`](#GovernorComponent-GovernorCountingTrait-quorum_reached)
+- [`vote_succeeded(self, proposal_id)`](#GovernorComponent-GovernorCountingTrait-vote_succeeded)
+
+#### GovernorVotesTrait [!toc] [#GovernorComponent-GovernorVotesTrait]
+
+- [`clock(self)`](#GovernorComponent-GovernorVotesTrait-clock)
+- [`CLOCK_MODE(self)`](#GovernorComponent-GovernorVotesTrait-CLOCK_MODE)
+- [`get_votes(self, account, timepoint, params)`](#GovernorComponent-GovernorVotesTrait-get_votes)
+
+#### GovernorExecutionTrait [!toc] [#GovernorComponent-GovernorExecutionTrait]
+
+- [`state(self, proposal_id)`](#GovernorComponent-GovernorExecutionTrait-state)
+- [`executor(self)`](#GovernorComponent-GovernorExecutionTrait-executor)
+- [`execute_operations(self, proposal_id, calls, description_hash)`](#GovernorComponent-GovernorExecutionTrait-execute_operations)
+- [`queue_operations(self, proposal_id, calls, description_hash)`](#GovernorComponent-GovernorExecutionTrait-queue_operations)
+- [`proposal_needs_queuing(self, proposal_id)`](#GovernorComponent-GovernorExecutionTrait-proposal_needs_queuing)
+- [`cancel_operations(self, proposal_id, description_hash)`](#GovernorComponent-GovernorExecutionTrait-cancel_operations)
+
+Embeddable Implementations
+
+#### GovernorImpl [!toc] [#GovernorComponent-GovernorImpl]
+
+- [`name(self)`](#GovernorComponent-name)
+- [`version(self)`](#GovernorComponent-version)
+- [`COUNTING_MODE(self)`](#GovernorComponent-COUNTING_MODE)
+- [`hash_proposal(self, calls, description_hash)`](#GovernorComponent-hash_proposal)
+- [`state(self, proposal_id)`](#GovernorComponent-state)
+- [`proposal_threshold(self)`](#GovernorComponent-proposal_threshold)
+- [`proposal_snapshot(self, proposal_id)`](#GovernorComponent-proposal_snapshot)
+- [`proposal_deadline(self, proposal_id)`](#GovernorComponent-proposal_deadline)
+- [`proposal_proposer(self, proposal_id)`](#GovernorComponent-proposal_proposer)
+- [`proposal_eta(self, proposal_id)`](#GovernorComponent-proposal_eta)
+- [`proposal_needs_queuing(self, proposal_id)`](#GovernorComponent-proposal_needs_queuing)
+- [`voting_delay(self)`](#GovernorComponent-voting_delay)
+- [`voting_period(self)`](#GovernorComponent-voting_period)
+- [`quorum(self, timepoint)`](#GovernorComponent-quorum)
+- [`get_votes(self, account, timepoint)`](#GovernorComponent-get_votes)
+- [`get_votes_with_params(self, account, timepoint, params)`](#GovernorComponent-get_votes_with_params)
+- [`has_voted(self, proposal_id, account)`](#GovernorComponent-has_voted)
+- [`propose(self, calls, description)`](#GovernorComponent-propose)
+- [`queue(self, calls, description_hash)`](#GovernorComponent-queue)
+- [`execute(self, calls, description_hash)`](#GovernorComponent-execute)
+- [`cancel(self, proposal_id, description_hash)`](#GovernorComponent-cancel)
+- [`cast_vote(self, proposal_id, support)`](#GovernorComponent-cast_vote)
+- [`cast_vote_with_reason(self, proposal_id, support, reason)`](#GovernorComponent-cast_vote_with_reason)
+- [`cast_vote_with_reason_and_params(self, proposal_id, support, reason, params)`](#GovernorComponent-cast_vote_with_reason_and_params)
+- [`cast_vote_by_sig(self, proposal_id, support, reason, signature)`](#GovernorComponent-cast_vote_by_sig)
+- [`cast_vote_with_reason_and_params_by_sig(self, proposal_id, support, reason, params, signature)`](#GovernorComponent-cast_vote_with_reason_and_params_by_sig)
+- [`nonces(self, voter)`](#GovernorComponent-nonces)
+- [`relay(self, call)`](#GovernorComponent-relay)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#GovernorComponent-InternalImpl]
+
+- [`initializer(self)`](#GovernorComponent-initializer)
+- [`get_proposal(self, proposal_id)`](#GovernorComponent-get_proposal)
+- [`is_valid_description_for_proposer(self, proposer, description)`](#GovernorComponent-is_valid_description_for_proposer)
+- [`_hash_proposal(self, calls, description_hash)`](#GovernorComponent-_hash_proposal)
+- [`_proposal_snapshot(self, proposal_id)`](#GovernorComponent-_proposal_snapshot)
+- [`_proposal_deadline(self, proposal_id)`](#GovernorComponent-_proposal_deadline)
+- [`_proposal_proposer(self, proposal_id)`](#GovernorComponent-_proposal_proposer)
+- [`_proposal_eta(self, proposal_id)`](#GovernorComponent-_proposal_eta)
+
+#### InternalExtendedImpl [!toc] [#GovernorComponent-InternalExtendedImpl]
+
+- [`assert_only_governance(self)`](#GovernorComponent-assert_only_governance)
+- [`validate_state(self, proposal_id, allowed_states)`](#GovernorComponent-validate_state)
+- [`use_nonce(self, voter)`](#GovernorComponent-use_nonce)
+- [`_get_votes(self, account, timepoint, params)`](#GovernorComponent-_get_votes)
+- [`_proposal_threshold(self)`](#GovernorComponent-_proposal_threshold)
+- [`_state(self, proposal_id)`](#GovernorComponent-_state)
+- [`_propose(self, calls, description, proposer)`](#GovernorComponent-_propose)
+- [`_cancel(self, proposal_id, description_hash)`](#GovernorComponent-_cancel)
+- [`_count_vote(self, proposal_id, account, support, total_weight, params)`](#GovernorComponent-_count_vote)
+- [`_cast_vote(self, proposal_id, voter, support, reason, params)`](#GovernorComponent-_cast_vote)
+
+Events
+
+- [`ProposalCreated(proposal_id, proposer, calls, signatures, vote_start, vote_end, description)`](#GovernorComponent-ProposalCreated)
+- [`ProposalQueued(proposal_id)`](#GovernorComponent-ProposalQueued)
+- [`ProposalExecuted(proposal_id)`](#GovernorComponent-ProposalExecuted)
+- [`ProposalCanceled(proposal_id)`](#GovernorComponent-ProposalCanceled)
+- [`VoteCast(voter, proposal_id, support, weight, reason)`](#GovernorComponent-VoteCast)
+- [`VoteCastWithParams(voter, proposal_id, support, weight, reason, params)`](#GovernorComponent-VoteCastWithParams)
+
+#### Extensions traits functions [!toc] [#GovernorComponent-Extensions-Traits]
+
+
+Must return the delay, in number of timepoints, between when the proposal is created and when the vote starts. This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a proposal starts.
+
+
+
+Must return the delay, in number of timepoints, between the vote start and vote end.
+
+
+
+Must return the minimum number of votes that an account must have to create a proposal.
+
+
+
+Must return the minimum number of votes required for a proposal to succeed.
+
+
+
+Must return a description of the possible `support` values for `cast_vote` and the way these votes are counted, meant to be consumed by UIs to show correct vote options and interpret the results. See [COUNTING\_MODE](#GovernorComponent-COUNTING_MODE) for more details.
+
+
+
+Must register a vote for `proposal_id` by `account` with a given `support`, voting `weight` and voting `params`.
+
+Support is generic and can represent various things depending on the voting system used.
+
+
+
+Must return whether an account has cast a vote on a proposal.
+
+
+
+Must return whether the minimum quorum has been reached for a proposal.
+
+
+
+Must return whether a proposal has succeeded or not.
+
+
+
+Returns the current timepoint determined by the governor's operational mode, intended for use in time-sensitive logic. See [ERC-6372#clock](https://eips.ethereum.org/EIPS/eip-6372#clock).
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the governor is operating in. See [ERC-6372#CLOCK\_MODE](https://eips.ethereum.org/EIPS/eip-6372#clock_mode).
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+
+Must return the voting power of an account at a specific timepoint with the given parameters.
+
+
+
+Must return the state of a proposal at the current time.
+
+The state can be either:
+
+- `Pending`: The proposal does not exist yet.
+- `Active`: The proposal is active.
+- `Canceled`: The proposal has been canceled.
+- `Defeated`: The proposal has been defeated.
+- `Succeeded`: The proposal has succeeded.
+- `Queued`: The proposal has been queued.
+- `Executed`: The proposal has been executed.
+
+
+
+Must return the address through which the governor executes action. Should be used to specify whether the module execute actions through another contract such as a timelock.
+
+MUST be the governor itself, or an instance of TimelockController with the governor as the only proposer, canceller, and executor.
+
+When the executor is not the governor itself (i.e. a timelock), it can call functions that are restricted with the `assert_only_governance` guard, and also potentially execute transactions on behalf of the governor. Because of this, this module is designed to work with the TimelockController as the unique potential external executor.
+
+
+
+
+Execution mechanism. Can be used to modify the way operations are executed (for example adding a vault/timelock).
+
+
+
+Queuing mechanism. Can be used to modify the way queuing is performed (for example adding a vault/timelock).
+
+Requirements:
+
+- Must return a timestamp that describes the expected ETA for execution. If the returned value is 0, the core will consider queueing did not succeed, and the public `queue` function will revert.
+
+
+
+Must return whether proposals need to be queued before execution. This usually indicates if the proposal needs to go through a timelock.
+
+
+
+Cancel mechanism. Can be used to modify the way canceling is performed (for example adding a vault/timelock).
+
+
+#### Embeddable functions [!toc] [#GovernorComponent-Embeddable-Functions]
+
+
+Name of the governor instance (used in building the [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) domain separator).
+
+
+
+Version of the governor instance (used in building [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) domain separator).
+
+
+
+A description of the possible `support` values for `cast_vote` and the way these votes are counted, meant to be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
+
+There are 2 standard keys: `support` and `quorum`.
+
+- `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
+- `quorum=bravo` means that only For votes are counted towards quorum.
+- `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
+
+If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique name that describes the behavior. For example:
+
+- `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
+- `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
+
+The string can be decoded by the standard [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) JavaScript class.
+
+
+
+
+Hashing function used to (re)build the proposal id from the proposal details.
+
+
+
+Returns the state of a proposal, given its id.
+
+
+
+The number of votes required in order for a voter to become a proposer.
+
+
+
+Timepoint used to retrieve user's votes and quorum. If using block number, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the following block.
+
+
+
+Timepoint at which votes close. If using block number, votes close at the end of this block, so it is possible to cast a vote during this block.
+
+
+
+The account that created a proposal.
+
+
+
+The time when a queued proposal becomes executable ("ETA"). Unlike `proposal_snapshot` and `proposal_deadline`, this doesn't use the governor clock, and instead relies on the executor's clock which may be different. In most cases this will be a timestamp.
+
+
+
+Whether a proposal needs to be queued before execution. This indicates if the proposal needs to go through a timelock.
+
+
+
+Delay between when a proposal is created and when the vote starts. The unit this duration is expressed in depends on the clock (see [ERC-6372](https://eips.ethereum.org/EIPS/eip-6372)) this contract uses.
+
+This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a proposal starts.
+
+
+
+Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock (see [ERC-6372](https://eips.ethereum.org/EIPS/eip-6372)) this contract uses.
+
+The `voting_delay` can delay the start of the vote. This must be considered when setting the voting duration compared to the voting delay.
+
+This value is stored when the proposal is submitted so that possible changes to the value do not affect proposals that have already been submitted.
+
+
+
+
+Minimum number of votes required for a proposal to be successful.
+
+The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows the quorum to scale depending on values such as the total supply of a token at this timepoint.
+
+
+
+Returns the voting power of an `account` at a specific `timepoint`.
+
+This can be implemented in a number of ways, for example by reading the delegated balance from one (or multiple) `ERC20Votes` tokens.
+
+
+
+Returns the voting power of an account at a specific timepoint, given additional encoded parameters.
+
+
+
+Returns whether an account has cast a vote on a proposal.
+
+
+
+Creates a new proposal. Voting starts after the delay specified by `voting_delay` and lasts for a duration specified by `voting_period`. Returns the id of the proposal.
+
+This function has opt-in frontrunning protection, described in `is_valid_description_for_proposer`.
+
+The state of the Governor and targets may change between the proposal creation and its execution. This may be the result of third party actions on the targeted contracts, or other governor proposals. For example, the balance of this contract could be updated or its access control permissions may be modified, possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough value to cover a proposal with multiple transfers).
+
+Requirements:
+
+- The proposer must be authorized to submit the proposal.
+- The proposer must have enough votes to submit the proposal if `proposal_threshold` is greater than zero.
+- The proposal must not already exist.
+
+Emits a [ProposalCreated](#GovernorComponent-ProposalCreated) event.
+
+
+
+Queues a proposal. Some governors require this step to be performed before execution can happen. If queuing is not necessary, this function may revert. Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
+
+Returns the id of the proposal.
+
+Requirements:
+
+- The proposal must be in the `Succeeded` state.
+- The queue operation must return a non-zero ETA.
+
+Emits a [ProposalQueued](#GovernorComponent-ProposalQueued) event.
+
+
+
+
+Executes a successful proposal. This requires the quorum to be reached, the vote to be successful, and the deadline to be reached. Depending on the governor it might also be required that the proposal was queued and that some delay passed.
+
+Some modules can modify the requirements for execution, for example by adding an additional timelock (See `timelock_controller`).
+
+Returns the id of the proposal.
+
+Requirements:
+
+- The proposal must be in the `Succeeded` or `Queued` state.
+
+Emits a [ProposalExecuted](#GovernorComponent-ProposalExecuted) event.
+
+
+
+Cancels a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e. before the vote starts.
+
+Returns the id of the proposal.
+
+Requirements:
+
+- The proposal must be in the `Pending` state.
+- The caller must be the proposer of the proposal.
+
+Emits a [ProposalCanceled](#GovernorComponent-ProposalCanceled) event.
+
+
+
+Cast a vote.
+
+Requirements:
+
+- The proposal must be active.
+
+Emits a [VoteCast](#GovernorComponent-VoteCast) event.
+
+
+
+Cast a vote with a `reason`.
+
+Requirements:
+
+- The proposal must be active.
+
+Emits a [VoteCast](#GovernorComponent-VoteCast) event.
+
+
+
+Cast a vote with a `reason` and additional serialized `params`.
+
+Requirements:
+
+- The proposal must be active.
+
+Emits either:
+
+- [VoteCast](#GovernorComponent-VoteCast) event if no params are provided.
+- [VoteCastWithParams](#GovernorComponent-VoteCastWithParams) event otherwise.
+
+
+
+Cast a vote using the `voter`'s signature.
+
+Requirements:
+
+- The proposal must be active.
+- The nonce in the signed message must match the account's current nonce.
+- `voter` must implement `SRC6::is_valid_signature`.
+- `signature` must be valid for the message hash.
+
+Emits a [VoteCast](#GovernorComponent-VoteCast) event.
+
+
+
+Cast a vote with a `reason` and additional serialized `params` using the `voter`'s signature.
+
+Requirements:
+
+- The proposal must be active.
+- The nonce in the signed message must match the account's current nonce.
+- `voter` must implement `SRC6::is_valid_signature`.
+- `signature` must be valid for the message hash.
+
+Emits either:
+
+- [VoteCast](#GovernorComponent-VoteCast) event if no params are provided.
+- [VoteCastWithParams](#GovernorComponent-VoteCastWithParams) event otherwise.
+
+
+
+Returns the next unused nonce for an address.
+
+
+
+Relays a transaction or function call to an arbitrary target.
+
+In cases where the governance executor is some contract other than the governor itself, like when using a timelock, this function can be invoked in a governance proposal to recover tokens that were sent to the governor contract by mistake.
+
+If the executor is simply the governor itself, use of `relay` is redundant.
+
+
+#### Internal functions [!toc] [#GovernorComponent-Internal-Functions]
+
+
+Initializes the contract by registering the supported interface id.
+
+
+
+Returns the proposal object given its id.
+
+
+
+Checks if the proposer is authorized to submit a proposal with the given description.
+
+If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string (case insensitive), then the submission of this proposal will only be authorized to said address.
+
+This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure that no other address can submit the same proposal. An attacker would have to either remove or change that part, which would result in a different proposal id.
+
+In Starknet, the Sequencer ensures the order of transactions, but frontrunning can still be achieved by nodes, and potentially other actors in the future with sequencer decentralization.
+
+If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes:
+
+- If the `0x???` part is not a valid hex string.
+- If the `0x???` part is a valid hex string, but does not contain exactly 64 hex digits.
+- If it ends with the expected suffix followed by newlines or other whitespace.
+- If it ends with some other similar suffix, e.g. `#other=abc`.
+- If it does not end with any such suffix.
+
+
+
+Returns the proposal id computed from the given parameters.
+
+The proposal id is computed as a Pedersen hash of:
+
+- The array of calls being proposed
+- The description hash
+
+
+
+Timepoint used to retrieve user's votes and quorum. If using block number, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the following block.
+
+
+
+Timepoint at which votes close. If using block number, votes close at the end of this block, so it is possible to cast a vote during this block.
+
+
+
+The account that created a proposal.
+
+
+
+The time when a queued proposal becomes executable ("ETA"). Unlike `proposal_snapshot` and `proposal_deadline`, this doesn't use the governor clock, and instead relies on the executor's clock which may be different. In most cases this will be a timestamp.
+
+
+
+Asserts that the caller is the governance executor.
+
+When the executor is not the governor itself (i.e. a timelock), it can call functions that are restricted with this modifier, and also potentially execute transactions on behalf of the governor. Because of this, this module is designed to work with the TimelockController as the unique potential external executor. The timelock MUST have the governor as the only proposer, canceller, and executor.
+
+
+
+Validates that a proposal is in the expected state. Otherwise it panics.
+
+
+
+Consumes a nonce, returns the current value, and increments nonce.
+
+
+
+Internal wrapper for `GovernorVotesTrait::get_votes`.
+
+
+
+Internal wrapper for `GovernorProposeTrait::proposal_threshold`.
+
+
+
+Returns the state of a proposal, given its id.
+
+Requirements:
+
+- The proposal must exist.
+
+
+
+Internal propose mechanism. Returns the proposal id.
+
+Requirements:
+
+- The proposal must not already exist.
+
+Emits a [ProposalCreated](#GovernorComponent-ProposalCreated) event.
+
+
+
+Internal cancel mechanism with minimal restrictions.
+
+A proposal can be cancelled in any state other than Canceled or Executed.
+
+Once cancelled, a proposal can't be re-submitted.
+
+
+
+Internal wrapper for `GovernorCountingTrait::count_vote`.
+
+
+
+Internal vote-casting mechanism.
+
+Checks that the vote is pending and that it has not been cast yet. This function retrieves the voting weight using `get_votes` and then calls the `_count_vote` internal function.
+
+Emits either:
+
+- [VoteCast](#GovernorComponent-VoteCast) event if no params are provided.
+- [VoteCastWithParams](#GovernorComponent-VoteCastWithParams) event otherwise.
+
+
+#### Events [!toc] [#GovernorComponent-Events]
+
+
+Emitted when a proposal is created.
+
+
+
+Emitted when a proposal is queued.
+
+
+
+Emitted when a proposal is executed.
+
+
+
+Emitted when a proposal is canceled.
+
+
+
+Emitted when a vote is cast.
+
+
+
+Emitted when a vote is cast with params.
+
+
+## [](#governor_extensions)Governor extensions
+
+The Governor component can (and must) be extended by implementing the [extensions traits](#GovernorComponent-Extensions-Traits-Traits) to add the desired functionality. This can be achieved by directly implementing the traits on your contract, or by using a set of ready-to-use extensions provided by the library, which are presented below.
+
+### `GovernorCoreExecutionComponent` [toc] [#GovernorCoreExecutionComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorCoreExecutionComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) providing an execution mechanism directly through the Governor itself. For a timelocked execution mechanism, see [GovernorTimelockExecutionComponent](#GovernorTimelockExecutionComponent).
+
+Extension traits implementations
+
+#### GovernorExecution [!toc] [#GovernorCoreExecutionComponent-GovernorExecution]
+
+- [`state(self, proposal_id)`](#GovernorCoreExecutionComponent-state)
+- [`executor(self)`](#GovernorCoreExecutionComponent-executor)
+- [`execute_operations(self, proposal_id, calls, description_hash)`](#GovernorCoreExecutionComponent-execute_operations)
+- [`queue_operations(self, proposal_id, calls, description_hash)`](#GovernorCoreExecutionComponent-queue_operations)
+- [`proposal_needs_queuing(self, proposal_id)`](#GovernorCoreExecutionComponent-proposal_needs_queuing)
+- [`cancel_operations(self, proposal_id, description_hash)`](#GovernorCoreExecutionComponent-cancel_operations)
+
+#### Extension traits functions [!toc] [#GovernorCoreExecutionComponent-Extension-Traits-Functions]
+
+
+Returns the state of a proposal given its id.
+
+Requirements:
+
+- The proposal must exist.
+
+
+
+Returns the executor address.
+
+In this case, it returns the governor contract address since execution is performed directly through it.
+
+
+
+Executes the proposal's operations directly through the governor contract.
+
+
+
+In this implementation, queuing is not required so it returns 0.
+
+
+
+In this implementation, it always returns false.
+
+
+
+Cancels a proposal's operations.
+
+
+### `GovernorCountingSimpleComponent` [toc] [#GovernorCountingSimpleComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorCountingSimpleComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) for simple vote counting with three options.
+
+Extension traits implementations
+
+#### GovernorCounting [!toc] [#GovernorCountingSimpleComponent-GovernorCounting]
+
+- [`counting_mode(self)`](#GovernorCountingSimpleComponent-counting_mode)
+- [`count_vote(self, proposal_id, account, support, total_weight, params)`](#GovernorCountingSimpleComponent-count_vote)
+- [`has_voted(self, proposal_id, account)`](#GovernorCountingSimpleComponent-has_voted)
+- [`quorum_reached(self, proposal_id)`](#GovernorCountingSimpleComponent-quorum_reached)
+- [`vote_succeeded(self, proposal_id)`](#GovernorCountingSimpleComponent-vote_succeeded)
+
+#### Extension traits functions [!toc] [#GovernorCountingSimpleComponent-Extension-Traits-Functions]
+
+
+Returns `"support=bravo&quorum=for,abstain"`.
+
+- `support=bravo` indicates that the support follows the Governor Bravo format where voters can vote For, Against, or Abstain
+- `quorum=for,abstain` indicates that both For and Abstain votes count toward quorum
+
+
+
+Records a vote for a proposal.
+
+The support value follows the `VoteType` enum (0=Against, 1=For, 2=Abstain).
+
+Returns the weight that was counted.
+
+
+
+Returns whether an account has cast a vote on a proposal.
+
+
+
+
+Returns whether a proposal has reached quorum.
+
+In this implementation, both For and Abstain votes count toward quorum.
+
+
+
+Returns whether a proposal has succeeded.
+
+In this implementation, the For votes must be strictly greater than Against votes.
+
+
+### `GovernorSettingsComponent` [toc] [#GovernorSettingsComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorSettingsComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) for settings that are updatable through governance.
+
+Extension traits implementations
+
+#### GovernorSettings [!toc] [#GovernorSettingsComponent-GovernorSettings]
+
+- [`voting_delay(self)`](#GovernorSettingsComponent-voting_delay)
+- [`voting_period(self)`](#GovernorSettingsComponent-voting_period)
+- [`proposal_threshold(self)`](#GovernorSettingsComponent-proposal_threshold)
+
+Embeddable implementations
+
+#### GovernorSettingsAdminImpl [!toc] [#GovernorSettingsComponent-GovernorSettingsAdminImpl]
+
+- [`set_voting_delay(self, new_voting_delay)`](#GovernorSettingsComponent-set_voting_delay)
+- [`set_voting_period(self, new_voting_period)`](#GovernorSettingsComponent-set_voting_period)
+- [`set_proposal_threshold(self, new_proposal_threshold)`](#GovernorSettingsComponent-set_proposal_threshold)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#GovernorSettingsComponent-InternalImpl]
+
+- [`initializer(self, new_voting_delay, new_voting_period, new_proposal_threshold)`](#GovernorSettingsComponent-initializer)
+- [`assert_only_governance(self)`](#GovernorSettingsComponent-assert_only_governance)
+- [`_set_voting_delay(self, new_voting_delay)`](#GovernorSettingsComponent-_set_voting_delay)
+- [`_set_voting_period(self, new_voting_period)`](#GovernorSettingsComponent-_set_voting_period)
+- [`_set_proposal_threshold(self, new_proposal_threshold)`](#GovernorSettingsComponent-_set_proposal_threshold)
+
+Events
+
+- [`VotingDelayUpdated(old_voting_delay, new_voting_delay)`](#GovernorSettingsComponent-VotingDelayUpdated)
+- [`VotingPeriodUpdated(old_voting_period, new_voting_period)`](#GovernorSettingsComponent-VotingPeriodUpdated)
+- [`ProposalThresholdUpdated(old_proposal_threshold, new_proposal_threshold)`](#GovernorSettingsComponent-ProposalThresholdUpdated)
+
+#### Extension traits functions [!toc] [#GovernorSettingsComponent-ExtensionTraitsFunctions]
+
+
+Returns the delay, between when a proposal is created and when voting starts.
+
+
+
+Returns the time period, during which votes can be cast.
+
+
+
+Returns the minimum number of votes required for an account to create a proposal.
+
+
+#### Embeddable functions [!toc] [#GovernorSettingsComponent-EmbeddableFunctions]
+
+
+Sets the voting delay.
+
+Requirements:
+
+- Caller must be the governance executor.
+
+This function does not emit an event if the new voting delay is the same as the old one.
+
+May emit a [VotingDelayUpdated](#GovernorSettingsComponent-VotingDelayUpdated) event.
+
+
+
+Sets the voting period.
+
+This function does not emit an event if the new voting period is the same as the old one.
+
+Requirements:
+
+- Caller must be the governance executor.
+- `new_voting_period` must be greater than 0.
+
+May emit a [VotingPeriodUpdated](#GovernorSettingsComponent-VotingPeriodUpdated) event.
+
+
+
+Sets the proposal threshold.
+
+This function does not emit an event if the new proposal threshold is the same as the old one.
+
+Requirements:
+
+- Caller must be the governance executor.
+
+May emit a [ProposalThresholdUpdated](#GovernorSettingsComponent-ProposalThresholdUpdated) event.
+
+
+#### Internal functions [!toc] [#GovernorSettingsComponent-InternalFunctions]
+
+
+Initializes the component by setting the default values.
+
+Requirements:
+
+- `new_voting_period` must be greater than 0.
+
+Emits a [VotingDelayUpdated](#GovernorSettingsComponent-VotingDelayUpdated), [VotingPeriodUpdated](#GovernorSettingsComponent-VotingPeriodUpdated), and [ProposalThresholdUpdated](#GovernorSettingsComponent-ProposalThresholdUpdated) event.
+
+
+
+Asserts that the caller is the governance executor.
+
+
+
+Internal function to update the voting delay.
+
+This function does not emit an event if the new voting delay is the same as the old one.
+
+May emit a [VotingDelayUpdated](#GovernorSettingsComponent-VotingDelayUpdated) event.
+
+
+
+Internal function to update the voting period.
+
+Requirements:
+
+- `new_voting_period` must be greater than 0.
+
+This function does not emit an event if the new voting period is the same as the old one.
+
+May emit a [VotingPeriodUpdated](#GovernorSettingsComponent-VotingPeriodUpdated) event.
+
+
+
+Internal function to update the proposal threshold.
+
+This function does not emit an event if the new proposal threshold is the same as the old one.
+
+May emit a [ProposalThresholdUpdated](#GovernorSettingsComponent-ProposalThresholdUpdated) event.
+
+
+#### Events [!toc] [#GovernorSettingsComponent-Events]
+
+
+Emitted when the voting delay is updated.
+
+
+
+Emitted when the voting period is updated.
+
+
+
+Emitted when the proposal threshold is updated.
+
+
+### `GovernorVotesComponent` [toc] [#GovernorVotesComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorVotesComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) for voting weight extraction from a token with the [IVotes](#IVotes) extension.
+
+Extension traits implementations
+
+#### GovernorVotes [!toc] [#GovernorVotesComponent-GovernorVotes]
+
+- [`clock(self)`](#GovernorVotesComponent-clock)
+- [`CLOCK_MODE(self)`](#GovernorVotesComponent-CLOCK_MODE)
+- [`get_votes(self, account, timepoint, params)`](#GovernorVotesComponent-get_votes)
+
+Embeddable implementations
+
+#### VotesTokenImpl [!toc] [#GovernorVotesComponent-VotesTokenImpl]
+
+- [`token(self)`](#GovernorVotesComponent-token)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#GovernorVotesComponent-InternalImpl]
+
+- [`initializer(self, votes_token)`](#GovernorVotesComponent-initializer)
+
+#### Extension traits functions [!toc] [#GovernorVotesComponent-ExtensionTraitsFunctions]
+
+
+Returns the current timepoint determined by the governor's operational mode, intended for use in time-sensitive logic. See [ERC-6372#clock](https://eips.ethereum.org/EIPS/eip-6372#clock).
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the governor is operating in. See [ERC-6372#CLOCK\_MODE](https://eips.ethereum.org/EIPS/eip-6372#clock_mode).
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+
+Returns the voting power of `account` at a specific `timepoint` using the votes token.
+
+
+#### Embeddable functions [!toc] [#GovernorVotesComponent-EmbeddableFunctions]
+
+
+Returns the votes token that voting power is sourced from.
+
+
+#### Internal functions [!toc] [#GovernorVotesComponent-InternalFunctions]
+
+
+Initializes the component by setting the votes token.
+
+Requirements:
+
+- `votes_token` must not be zero.
+
+
+### `GovernorVotesQuorumFractionComponent` [toc] [#GovernorVotesQuorumFractionComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorVotesQuorumFractionComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) for voting weight extraction from a token with the [IVotes](#IVotes) extension and a quorum expressed as a fraction of the total supply.
+
+Extension traits implementations
+
+#### GovernorQuorum [!toc] [#GovernorVotesQuorumFractionComponent-GovernorQuorum]
+
+- [`quorum(self, timepoint)`](#GovernorVotesQuorumFractionComponent-quorum)
+
+#### GovernorVotes [!toc] [#GovernorVotesQuorumFractionComponent-GovernorVotes]
+
+- [`clock(self)`](#GovernorVotesQuorumFractionComponent-clock)
+- [`CLOCK_MODE(self)`](#GovernorVotesQuorumFractionComponent-CLOCK_MODE)
+- [`get_votes(self, account, timepoint, params)`](#GovernorVotesQuorumFractionComponent-get_votes)
+
+Embeddable implementations
+
+#### QuorumFractionImpl [!toc] [#GovernorVotesQuorumFractionComponent-QuorumFractionImpl]
+
+- [`token(self)`](#GovernorVotesQuorumFractionComponent-token)
+- [`current_quorum_numerator(self)`](#GovernorVotesQuorumFractionComponent-current_quorum_numerator)
+- [`quorum_numerator(self, timepoint)`](#GovernorVotesQuorumFractionComponent-quorum_numerator)
+- [`quorum_denominator(self)`](#GovernorVotesQuorumFractionComponent-quorum_denominator)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#GovernorVotesQuorumFractionComponent-InternalImpl]
+
+- [`initializer(self, votes_token, quorum_numerator)`](#GovernorVotesQuorumFractionComponent-initializer)
+- [`update_quorum_numerator(self, new_quorum_numerator)`](#GovernorVotesQuorumFractionComponent-update_quorum_numerator)
+
+Events
+
+- [`QuorumNumeratorUpdated(old_quorum_numerator, new_quorum_numerator)`](#GovernorVotesQuorumFractionComponent-QuorumNumeratorUpdated)
+
+#### Extension traits functions [!toc] [#GovernorVotesQuorumFractionComponent-ExtensionTraitsFunctions]
+
+
+It is computed as a percentage of the votes token total supply at a given `timepoint` in the past.
+
+
+
+Returns the current timepoint determined by the governor's operational mode, intended for use in time-sensitive logic. See [ERC-6372#clock](https://eips.ethereum.org/EIPS/eip-6372#clock).
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the governor is operating in. See [ERC-6372#CLOCK\_MODE](https://eips.ethereum.org/EIPS/eip-6372#clock_mode).
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+
+Returns the voting power of `account` at a specific `timepoint` using the votes token.
+
+
+#### Embeddable functions [!toc] [#GovernorVotesQuorumFractionComponent-EmbeddableFunctions]
+
+
+Returns the address of the votes token used for voting power extraction.
+
+
+
+Returns the current quorum numerator value.
+
+
+
+Returns the quorum numerator value at a specific `timepoint` in the past.
+
+
+
+Returns the quorum denominator value.
+
+
+#### Internal functions [!toc] [#GovernorVotesQuorumFractionComponent-InternalFunctions]
+
+
+Initializes the component by setting the votes token and the initial quorum numerator value.
+
+Requirements:
+
+- `votes_token` must not be zero.
+- `quorum_numerator` must be less than `quorum_denominator`.
+
+Emits a [QuorumNumeratorUpdated](#GovernorVotesQuorumFractionComponent-QuorumNumeratorUpdated) event.
+
+
+
+Updates the quorum numerator.
+
+This function does not emit an event if the new quorum numerator is the same as the old one.
+
+Requirements:
+
+- `new_quorum_numerator` must be less than `quorum_denominator`.
+
+May emit a [QuorumNumeratorUpdated](#GovernorVotesQuorumFractionComponent-QuorumNumeratorUpdated) event.
+
+
+#### Events [!toc] [#GovernorVotesQuorumFractionComponent-Events]
+
+
+Emitted when the quorum numerator is updated.
+
+
+### `GovernorTimelockExecutionComponent` [toc] [#GovernorTimelockExecutionComponent]
+
+
+
+```rust
+use openzeppelin_governance::governor::extensions::GovernorTimelockExecutionComponent;
+```
+
+Extension of [GovernorComponent](#GovernorComponent) that binds the execution process to an instance of a contract implementing [TimelockControllerComponent](#TimelockControllerComponent). This adds a delay, enforced by the timelock to all successful proposals (in addition to the voting duration).
+
+The Governor needs the [PROPOSER, EXECUTOR, and CANCELLER roles](../governance/timelock#roles) to work properly.
+
+Using this model means the proposal will be operated by the timelock and not by the governor. Thus, the assets and permissions must be attached to the timelock. Any asset sent to the governor will be inaccessible from a proposal, unless executed via `Governor::relay`.
+
+Setting up the timelock to have additional proposers or cancellers besides the governor is very risky, as it grants them the ability to: 1) execute operations as the timelock, and thus possibly performing operations or accessing funds that are expected to only be accessible through a vote, and 2) block governance proposals that have been approved by the voters, effectively executing a Denial of Service attack.
+
+Extension traits implementations
+
+#### GovernorExecution [!toc] [#GovernorTimelockExecutionComponent-GovernorExecution]
+
+- [`state(self, proposal_id)`](#GovernorTimelockExecutionComponent-state)
+- [`executor(self)`](#GovernorTimelockExecutionComponent-executor)
+- [`execute_operations(self, proposal_id, calls, description_hash)`](#GovernorTimelockExecutionComponent-execute_operations)
+- [`queue_operations(self, proposal_id, calls, description_hash)`](#GovernorTimelockExecutionComponent-queue_operations)
+- [`proposal_needs_queuing(self, proposal_id)`](#GovernorTimelockExecutionComponent-proposal_needs_queuing)
+- [`cancel_operations(self, proposal_id, description_hash)`](#GovernorTimelockExecutionComponent-cancel_operations)
+
+Embeddable implementations
+
+#### TimelockedImpl [!toc] [#GovernorTimelockExecutionComponent-TimelockedImpl]
+
+- [`timelock(self)`](#GovernorTimelockExecutionComponent-timelock)
+- [`get_timelock_id(self, proposal_id)`](#GovernorTimelockExecutionComponent-get_timelock_id)
+- [`update_timelock(self, new_timelock)`](#GovernorTimelockExecutionComponent-update_timelock)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#GovernorTimelockExecutionComponent-InternalImpl]
+
+- [`initializer(self, timelock_controller)`](#GovernorTimelockExecutionComponent-initializer)
+- [`assert_only_governance(self)`](#GovernorTimelockExecutionComponent-assert_only_governance)
+- [`timelock_salt(self, description_hash)`](#GovernorTimelockExecutionComponent-timelock_salt)
+- [`get_timelock_dispatcher(self)`](#GovernorTimelockExecutionComponent-get_timelock_dispatcher)
+- [`_update_timelock(self, new_timelock)`](#GovernorTimelockExecutionComponent-_update_timelock)
+
+Events
+
+- [`TimelockUpdated(old_timelock, new_timelock)`](#GovernorTimelockExecutionComponent-TimelockUpdated)
+
+#### Extension traits functions [!toc] [#GovernorTimelockExecutionComponent-ExtensionTraitsFunctions]
+
+
+Returns the state of a proposal given its id.
+
+Requirements:
+
+- The proposal must exist.
+
+
+
+Returns the executor address.
+
+In this module, the executor is the timelock controller.
+
+
+
+Runs the already queued proposal through the timelock.
+
+
+
+Queue a proposal to the timelock.
+
+Returns the eta for the execution of the queued proposal.
+
+
+
+In this implementation, it always returns true.
+
+
+
+Cancels the timelocked proposal if it has already been queued.
+
+
+#### Embeddable functions [!toc] [#GovernorTimelockExecutionComponent-EmbeddableFunctions]
+
+
+Returns the timelock controller address.
+
+
+
+Returns the timelock proposal id for a given proposal id.
+
+
+
+Updates the associated timelock.
+
+Requirements:
+
+- The caller must be the governance.
+
+Emits a [TimelockUpdated](#GovernorTimelockExecutionComponent-TimelockUpdated) event.
+
+
+#### Internal functions [!toc] [#GovernorTimelockExecutionComponent-InternalFunctions]
+
+
+Initializes the timelock controller.
+
+Requirements:
+
+- The timelock must not be the zero address.
+
+
+
+Ensures the caller is the executor (the timelock controller in this case).
+
+
+
+Computes the `TimelockController` operation salt as the XOR of the governor address and `description_hash`.
+
+It is computed with the governor address itself to avoid collisions across governor instances using the same timelock.
+
+
+
+Returns a dispatcher for interacting with the timelock controller.
+
+
+
+Internal function to update the timelock controller address.
+
+Emits a [TimelockUpdated](#GovernorTimelockExecutionComponent-TimelockUpdated) event.
+
+
+#### Events [!toc] [#GovernorTimelockExecutionComponent-Events]
+
+
+Emitted when the timelock controller is updated.
+
+
+## [](#multisig)Multisig
+
+A Multisig module enhances security and decentralization by requiring multiple signers to approve and execute transactions. Features include configurable quorum, signer management, and self-administration, ensuring collective decision-making and transparency for critical operations.
+
+### `MultisigComponent` [toc] [#MultisigComponent]
+
+
+
+```rust
+use openzeppelin_governance::multisig::MultisigComponent;
+```
+
+Component that implements [IMultisig](#IMultisig) and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations.
+
+Embeddable Implementations
+
+#### MultisigImpl [!toc] [#MultisigComponent-MultisigImpl]
+
+- [`get_quorum(self)`](#MultisigComponent-get_quorum)
+- [`is_signer(self, signer)`](#MultisigComponent-is_signer)
+- [`get_signers(self)`](#MultisigComponent-get_signers)
+- [`is_confirmed(self, id)`](#MultisigComponent-is_confirmed)
+- [`is_confirmed_by(self, id, signer)`](#MultisigComponent-is_confirmed_by)
+- [`is_executed(self, id)`](#MultisigComponent-is_executed)
+- [`get_submitted_block(self, id)`](#MultisigComponent-get_submitted_block)
+- [`get_transaction_state(self, id)`](#MultisigComponent-get_transaction_state)
+- [`get_transaction_confirmations(self, id)`](#MultisigComponent-get_transaction_confirmations)
+- [`hash_transaction(self, to, selector, calldata, salt)`](#MultisigComponent-hash_transaction)
+- [`hash_transaction_batch(self, calls, salt)`](#MultisigComponent-hash_transaction_batch)
+- [`add_signers(ref self, new_quorum, signers_to_add)`](#MultisigComponent-add_signers)
+- [`remove_signers(ref self, new_quorum, signers_to_remove)`](#MultisigComponent-remove_signers)
+- [`replace_signer(ref self, signer_to_remove, signer_to_add)`](#MultisigComponent-replace_signer)
+- [`change_quorum(ref self, new_quorum)`](#MultisigComponent-change_quorum)
+- [`submit_transaction(ref self, to, selector, calldata, salt)`](#MultisigComponent-submit_transaction)
+- [`submit_transaction_batch(ref self, calls, salt)`](#MultisigComponent-submit_transaction_batch)
+- [`confirm_transaction(ref self, id)`](#MultisigComponent-confirm_transaction)
+- [`revoke_confirmation(ref self, id)`](#MultisigComponent-revoke_confirmation)
+- [`execute_transaction(ref self, to, selector, calldata, salt)`](#MultisigComponent-execute_transaction)
+- [`execute_transaction_batch(ref self, calls, salt)`](#MultisigComponent-execute_transaction_batch)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#MultisigComponent-InternalImpl]
+
+- [`initializer(ref self, quorum, signers)`](#MultisigComponent-initializer)
+- [`resolve_tx_state(self, id)`](#MultisigComponent-resolve_tx_state)
+- [`assert_one_of_signers(self, caller)`](#MultisigComponent-assert_one_of_signers)
+- [`assert_tx_exists(self, id)`](#MultisigComponent-assert_tx_exists)
+- [`assert_only_self(self)`](#MultisigComponent-assert_only_self)
+- [`_add_signers(ref self, new_quorum, signers_to_add)`](#MultisigComponent-_add_signers)
+- [`_remove_signers(ref self, new_quorum, signers_to_remove)`](#MultisigComponent-_remove_signers)
+- [`_replace_signer(ref self, signer_to_remove, signer_to_add)`](#MultisigComponent-_replace_signer)
+- [`_change_quorum(ref self, new_quorum)`](#MultisigComponent-_change_quorum)
+
+Events
+
+- [`SignerAdded(signer)`](#MultisigComponent-SignerAdded)
+- [`SignerRemoved(signer)`](#MultisigComponent-SignerRemoved)
+- [`QuorumUpdated(old_quorum, new_quorum)`](#MultisigComponent-QuorumUpdated)
+- [`TransactionSubmitted(id, signer)`](#MultisigComponent-TransactionSubmitted)
+- [`TransactionConfirmed(id, signer)`](#MultisigComponent-TransactionConfirmed)
+- [`ConfirmationRevoked(id, signer)`](#MultisigComponent-ConfirmationRevoked)
+- [`TransactionExecuted(id)`](#MultisigComponent-TransactionExecuted)
+- [`CallSalt(id, salt)`](#MultisigComponent-CallSalt)
+
+#### Embeddable functions [!toc] [#MultisigComponent-EmbeddableFunctions]
+
+
+Returns the current quorum value.
+
+
+
+Checks if a given `signer` is registered.
+
+
+
+Returns a list of all current signers.
+
+
+
+Returns whether the transaction with the given `id` has been confirmed. A confirmed transaction has received the required number of confirmations (quorum).
+
+
+
+Returns whether the transaction with the given `id` has been confirmed by the specified `signer`.
+
+
+
+Returns whether the transaction with the given `id` has been executed.
+
+
+
+Returns the block number when the transaction with the given `id` was submitted.
+
+
+
+Returns the current state of the transaction with the given `id`.
+
+The possible states are:
+
+- `NotFound`: the transaction does not exist.
+- `Pending`: the transaction exists but hasn't reached the required confirmations.
+- `Confirmed`: the transaction has reached the required confirmations but hasn't been executed.
+- `Executed`: the transaction has been executed.
+
+
+
+Returns the number of confirmations from registered signers for the transaction with the specified `id`.
+
+
+
+Returns the computed identifier of a transaction containing a single call.
+
+
+
+Returns the computed identifier of a transaction containing a batch of calls.
+
+
+
+Adds new signers and updates the quorum.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be less than or equal to the total number of signers after addition.
+
+Emits a [SignerAdded](#MultisigComponent-SignerAdded) event for each signer added.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+
+Removes signers and updates the quorum.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be less than or equal to the total number of signers after removal.
+
+Emits a [SignerRemoved](#MultisigComponent-SignerRemoved) event for each signer removed.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+
+Replaces an existing signer with a new signer.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `signer_to_remove` must be an existing signer.
+- `signer_to_add` must not be an existing signer.
+
+Emits a [SignerRemoved](#MultisigComponent-SignerRemoved) event for the removed signer.
+
+Emits a [SignerAdded](#MultisigComponent-SignerAdded) event for the new signer.
+
+
+
+Updates the quorum value to `new_quorum`.
+
+Requirements:
+
+- The caller must be the contract itself.
+- `new_quorum` must be non-zero.
+- `new_quorum` must be less than or equal to the total number of signers.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+
+Submits a new transaction for confirmation.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must not have been submitted before.
+
+Emits a [TransactionSubmitted](#MultisigComponent-TransactionSubmitted) event.
+
+Emits a [CallSalt](#MultisigComponent-CallSalt) event if `salt` is not zero.
+
+
+
+Submits a new batch transaction for confirmation.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must not have been submitted before.
+
+Emits a [TransactionSubmitted](#MultisigComponent-TransactionSubmitted) event.
+
+Emits a [CallSalt](#MultisigComponent-CallSalt) event if `salt` is not zero.
+
+
+
+Confirms a transaction with the given `id`.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must exist and not be executed.
+- The caller must not have already confirmed the transaction.
+
+Emits a [TransactionConfirmed](#MultisigComponent-TransactionConfirmed) event.
+
+
+
+Revokes a previous confirmation for a transaction with the given `id`.
+
+Requirements:
+
+- The transaction must exist and not be executed.
+- The caller must have previously confirmed the transaction.
+
+Emits a [ConfirmationRevoked](#MultisigComponent-ConfirmationRevoked) event.
+
+
+
+Executes a confirmed transaction.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must be confirmed and not yet executed.
+
+Emits a [TransactionExecuted](#MultisigComponent-TransactionExecuted) event.
+
+
+
+Executes a confirmed batch transaction.
+
+Requirements:
+
+- The caller must be a registered signer.
+- The transaction must be confirmed and not yet executed.
+
+Emits a [TransactionExecuted](#MultisigComponent-TransactionExecuted) event.
+
+
+#### Internal functions [!toc] [#MultisigComponent-InternalFunctions]
+
+
+Initializes the Multisig component with the initial `quorum` and `signers`. This function must be called during contract initialization to set up the initial state.
+
+Requirements:
+
+- `quorum` must be non-zero and less than or equal to the number of `signers`.
+
+Emits a [SignerAdded](#MultisigComponent-SignerAdded) event for each signer added.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event.
+
+
+
+Resolves and returns the current state of the transaction with the given `id`.
+
+The possible states are:
+
+- `NotFound`: the transaction does not exist.
+- `Pending`: the transaction exists but hasn't reached the required confirmations.
+- `Confirmed`: the transaction has reached the required confirmations but hasn't been executed.
+- `Executed`: the transaction has been executed.
+
+
+
+Asserts that the `caller` is one of the registered signers.
+
+Requirements:
+
+- The `caller` must be a registered signer.
+
+
+
+Asserts that a transaction with the given `id` exists.
+
+Requirements:
+
+- The transaction with the given `id` must have been submitted.
+
+
+
+Asserts that the caller is the contract itself.
+
+Requirements:
+
+- The caller must be the contract's own address.
+
+
+
+Adds new signers and updates the quorum.
+
+Requirements:
+
+- Each signer address must be non-zero.
+- `new_quorum` must be non-zero and less than or equal to the total number of signers after addition.
+
+Emits a [SignerAdded](#MultisigComponent-SignerAdded) event for each new signer added.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+
+Removes existing signers and updates the quorum.
+
+Requirements:
+
+- `new_quorum` must be non-zero and less than or equal to the total number of signers after removal.
+
+Emits a [SignerRemoved](#MultisigComponent-SignerRemoved) event for each signer removed.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+
+Replaces an existing signer with a new signer.
+
+Requirements:
+
+- `signer_to_remove` must be an existing signer.
+- `signer_to_add` must not be an existing signer.
+- `signer_to_add` must be a non-zero address.
+
+Emits a [SignerRemoved](#MultisigComponent-SignerRemoved) event for the removed signer.
+
+Emits a [SignerAdded](#MultisigComponent-SignerAdded) event for the new signer.
+
+
+
+Updates the quorum value to `new_quorum` if it differs from the current quorum.
+
+Requirements:
+
+- `new_quorum` must be non-zero.
+- `new_quorum` must be less than or equal to the total number of signers.
+
+Emits a [QuorumUpdated](#MultisigComponent-QuorumUpdated) event if the quorum changes.
+
+
+#### Events [!toc] [#MultisigComponent-Events]
+
+
+Emitted when a new `signer` is added.
+
+
+
+Emitted when a `signer` is removed.
+
+
+
+Emitted when the `quorum` value is updated.
+
+
+
+Emitted when a new transaction is submitted by a `signer`.
+
+
+
+Emitted when a transaction is confirmed by a `signer`.
+
+
+
+Emitted when a `signer` revokes his confirmation.
+
+
+
+Emitted when a transaction is executed.
+
+
+
+Emitted when a new transaction is submitted with non-zero salt.
+
+
+## [](#timelock)Timelock
+
+In a governance system, `TimelockControllerComponent` is in charge of introducing a delay between a proposal and its execution.
+
+### `TimelockControllerComponent` [toc] [#TimelockControllerComponent]
+
+
+
+```rust
+use openzeppelin_governance::timelock::TimelockControllerComponent;
+```
+
+Component that implements [ITimelock](#ITimelock) and enables the implementing contract to act as a timelock controller.
+
+[Embeddable Mixin Implementations](../components#mixins)
+
+#### TimelockMixinImpl [!toc] [#TimelockControllerComponent-TimelockMixinImpl]
+
+- [`TimelockImpl`](#TimelockControllerComponent-Embeddable-Impls-TimelockImpl)
+- [`SRC5Impl`](./introspection#SRC5Component-Embeddable-Impls)
+- [`AccessControlImpl`](./access#AccessControlComponent-Embeddable-Impls)
+- [`AccessControlCamelImpl`](./access#AccessControlComponent-Embeddable-Impls)
+
+Embeddable Implementations
+
+#### TimelockImpl [!toc] [#TimelockControllerComponent-TimelockImpl]
+
+- [`is_operation(self, id)`](#TimelockControllerComponent-is_operation)
+- [`is_operation_pending(self, id)`](#TimelockControllerComponent-is_operation_pending)
+- [`is_operation_ready(self, id)`](#TimelockControllerComponent-is_operation_ready)
+- [`is_operation_done(self, id)`](#TimelockControllerComponent-is_operation_done)
+- [`get_timestamp(self, id)`](#TimelockControllerComponent-get_timestamp)
+- [`get_operation_state(self, id)`](#TimelockControllerComponent-get_operation_state)
+- [`get_min_delay(self)`](#TimelockControllerComponent-get_min_delay)
+- [`hash_operation(self, call, predecessor, salt)`](#TimelockControllerComponent-hash_operation)
+- [`hash_operation_batch(self, calls, predecessor, salt)`](#TimelockControllerComponent-hash_operation_batch)
+- [`schedule(self, call, predecessor, salt, delay)`](#TimelockControllerComponent-schedule)
+- [`schedule_batch(self, calls, predecessor, salt, delay)`](#TimelockControllerComponent-schedule_batch)
+- [`cancel(self, id)`](#TimelockControllerComponent-cancel)
+- [`execute(self, call, predecessor, salt)`](#TimelockControllerComponent-execute)
+- [`execute_batch(self, calls, predecessor, salt)`](#TimelockControllerComponent-execute_batch)
+- [`update_delay(self, new_delay)`](#TimelockControllerComponent-update_delay)
+
+#### SRC5Impl [!toc] [#TimelockControllerComponent-SRC5Impl]
+
+- [`supports_interface(self, interface_id: felt252)`](./introspection#ISRC5-supports_interface)
+
+#### AccessControlImpl [!toc] [#TimelockControllerComponent-AccessControlImpl]
+
+- [`has_role(self, role, account)`](./access#IAccessControl-has_role)
+- [`get_role_admin(self, role)`](./access#IAccessControl-get_role_admin)
+- [`grant_role(self, role, account)`](./access#IAccessControl-grant_role)
+- [`revoke_role(self, role, account)`](./access#IAccessControl-revoke_role)
+- [`renounce_role(self, role, account)`](./access#IAccessControl-renounce_role)
+
+#### AccessControlCamelImpl [!toc] [#TimelockControllerComponent-AccessControlCamelImpl]
+
+- [`hasRole(self, role, account)`](./access#IAccessControl-hasRole)
+- [`getRoleAdmin(self, role)`](./access#IAccessControl-getRoleAdmin)
+- [`grantRole(self, role, account)`](./access#IAccessControl-grantRole)
+- [`revokeRole(self, role, account)`](./access#IAccessControl-revokeRole)
+- [`renounceRole(self, role, account)`](./access#IAccessControl-renounceRole)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#TimelockControllerComponent-InternalImpl]
+
+- [`initializer(self, min_delay, proposers, executors, admin)`](#TimelockControllerComponent-initializer)
+- [`assert_only_role(self, role)`](#TimelockControllerComponent-assert_only_role)
+- [`assert_only_role_or_open_role(self, role)`](#TimelockControllerComponent-assert_only_role_or_open_role)
+- [`assert_only_self(self)`](#TimelockControllerComponent-assert_only_self)
+- [`_before_call(self, id, predecessor)`](#TimelockControllerComponent-_before_call)
+- [`_after_call(self, id)`](#TimelockControllerComponent-_after_call)
+- [`_schedule(self, id, delay)`](#TimelockControllerComponent-_schedule)
+- [`_execute(self, call)`](#TimelockControllerComponent-_execute)
+
+Events
+
+- [`CallScheduled(id, index, call, predecessor, delay)`](#TimelockControllerComponent-CallScheduled)
+- [`CallExecuted(id, index, call)`](#TimelockControllerComponent-CallExecuted)
+- [`CallSalt(id, salt)`](#TimelockControllerComponent-CallSalt)
+- [`CallCancelled(id)`](#TimelockControllerComponent-CallCancelled)
+- [`MinDelayChanged(old_duration, new_duration)`](#TimelockControllerComponent-MinDelayChanged)
+
+#### Embeddable functions [!toc] [#TimelockControllerComponent-EmbeddableFunctions]
+
+
+Returns whether `id` corresponds to a registered operation. This includes the OperationStates: `Waiting`, `Ready`, and `Done`.
+
+
+
+Returns whether the `id` OperationState is pending or not. Note that a pending operation may be either `Waiting` or `Ready`.
+
+
+
+Returns whether the `id` OperationState is `Ready` or not.
+
+
+
+Returns whether the `id` OperationState is `Done` or not.
+
+
+
+Returns the timestamp at which `id` becomes `Ready`.
+
+`0` means the OperationState is `Unset` and `1` means the OperationState is `Done`.
+
+
+
+Returns the current state of the operation with the given `id`.
+
+The possible states are:
+
+- `Unset`: the operation has not been scheduled or has been canceled.
+- `Waiting`: the operation has been scheduled and is pending the scheduled delay.
+- `Ready`: the timer has expired, and the operation is eligible for execution.
+- `Done`: the operation has been executed.
+
+
+
+Returns the minimum delay in seconds for an operation to become valid. This value can be changed by executing an operation that calls `update_delay`.
+
+
+
+Returns the identifier of an operation containing a single transaction.
+
+
+
+Returns the identifier of an operation containing a batch of transactions.
+
+
+
+Schedule an operation containing a single transaction.
+
+Requirements:
+
+- The caller must have the `PROPOSER_ROLE` role.
+- The proposal must not already exist.
+- `delay` must be greater than or equal to the min delay.
+
+Emits [CallScheduled](#TimelockControllerComponent-CallScheduled) event. Emits [CallSalt](#TimelockControllerComponent-CallSalt) event if `salt` is not zero.
+
+
+
+Schedule an operation containing a batch of transactions.
+
+Requirements:
+
+- The caller must have the `PROPOSER_ROLE` role.
+- The proposal must not already exist.
+- `delay` must be greater than or equal to the min delay.
+
+Emits one [CallScheduled](#TimelockControllerComponent-CallScheduled) event for each transaction in the batch. Emits [CallSalt](#TimelockControllerComponent-CallSalt) event if `salt` is not zero.
+
+
+
+Cancels an operation. A canceled operation returns to `Unset` OperationState.
+
+Requirements:
+
+- The caller must have the `CANCELLER_ROLE` role.
+- `id` must be a pending operation.
+
+Emits a [CallCancelled](#TimelockControllerComponent-CallCancelled) event.
+
+
+
+Execute a (Ready) operation containing a single Call.
+
+Requirements:
+
+- Caller must have `EXECUTOR_ROLE`.
+- `id` must be in Ready OperationState.
+- `predecessor` must either be `0` or in Done OperationState.
+
+Emits a [CallExecuted](#TimelockControllerComponent-CallExecuted) event.
+
+This function can reenter, but it doesn't pose a risk because [`_after_call(self: @ContractState, id: felt252)` internal](#TimelockControllerComponent-_after_call) checks that the proposal is pending, thus any modifications to the operation during reentrancy should be caught.
+
+
+
+Execute a (Ready) operation containing a batch of Calls.
+
+Requirements:
+
+- Caller must have `EXECUTOR_ROLE`.
+- `id` must be in Ready OperationState.
+- `predecessor` must either be `0` or in Done OperationState.
+
+Emits a [CallExecuted](#TimelockControllerComponent-CallExecuted) event for each Call.
+
+This function can reenter, but it doesn't pose a risk because `_after_call` checks that the proposal is pending, thus any modifications to the operation during reentrancy should be caught.
+
+
+
+Changes the minimum timelock duration for future operations.
+
+Requirements:
+
+- The caller must be the timelock itself. This can only be achieved by scheduling and later executing an operation where the timelock is the target and the data is the serialized call to this function.
+
+Emits a [MinDelayChanged](#TimelockControllerComponent-MinDelayChanged) event.
+
+
+#### Internal functions [!toc] [#TimelockControllerComponent-InternalFunctions]
+
+
+Initializes the contract by registering support for SRC5 and AccessControl.
+
+This function also configures the contract with the following parameters:
+
+- `min_delay`: initial minimum delay in seconds for operations.
+- `proposers`: accounts to be granted proposer and canceller roles.
+- `executors`: accounts to be granted executor role.
+- `admin`: optional account to be granted admin role; disable with zero address.
+
+The optional admin can aid with initial configuration of roles after deployment without being subject to delay, but this role should be subsequently renounced in favor of administration through timelocked proposals.
+
+Emits two [IAccessControl::RoleGranted](./access#IAccessControl-RoleGranted) events for each account in `proposers` with `PROPOSER_ROLE` and `CANCELLER_ROLE` roles.
+
+Emits a [IAccessControl::RoleGranted](./access#IAccessControl-RoleGranted) event for each account in `executors` with `EXECUTOR_ROLE` role.
+
+May emit a [IAccessControl::RoleGranted](./access#IAccessControl-RoleGranted) event for `admin` with `DEFAULT_ADMIN_ROLE` role (if `admin` is not zero).
+
+Emits [MinDelayChanged](#TimelockControllerComponent-MinDelayChanged) event.
+
+
+
+Validates that the caller has the given `role`. Otherwise it panics.
+
+
+
+Validates that the caller has the given `role`. If `role` is granted to the zero address, then this is considered an open role which allows anyone to be the caller.
+
+
+
+Validates that the caller is the timelock contract itself. Otherwise it panics.
+
+
+
+Private function that checks before execution of an operation's calls.
+
+Requirements:
+
+- `id` must be in the `Ready` OperationState.
+- `predecessor` must either be zero or be in the `Done` OperationState.
+
+
+
+Private function that checks after execution of an operation's calls and sets the OperationState of `id` to `Done`.
+
+Requirements:
+
+- `id` must be in the Ready OperationState.
+
+
+
+Private function that schedules an operation that is to become valid after a given `delay`.
+
+
+
+Private function that executes an operation's calls.
+
+
+#### Events [!toc] [#TimelockControllerComponent-Events]
+
+
+Emitted when `call` is scheduled as part of operation `id`.
+
+
+
+Emitted when `call` is performed as part of operation `id`.
+
+
+
+Emitted when a new proposal is scheduled with non-zero salt.
+
+
+
+Emitted when operation `id` is cancelled.
+
+
+
+Emitted when the minimum delay for future operations is modified.
+
+
+## [](#votes)Votes
+
+The `VotesComponent` provides a flexible system for tracking and delegating voting power. This system allows users to delegate their voting power to other addresses, enabling more active participation in governance.
+
+### `VotesComponent` [toc] [#VotesComponent]
+
+
+
+```rust
+use openzeppelin_governance::votes::VotesComponent;
+```
+
+Component that implements the [IVotes](#IVotes) interface and provides a flexible system for tracking and delegating voting power.
+
+By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
+
+When using this module, your contract must implement the [VotingUnitsTrait](#VotingUnitsTrait). For convenience, this is done automatically for `ERC20` and `ERC721` tokens.
+
+Voting Units Trait Implementations
+
+#### ERC20VotesImpl [!toc] [#VotesComponent-ERC20VotesImpl]
+
+- [`get_voting_units(self, account)`](#VotesComponent-ERC20VotesImpl-get_voting_units)
+
+#### ERC721VotesImpl [!toc] [#VotesComponent-ERC721VotesImpl]
+
+- [`get_voting_units(self, account)`](#VotesComponent-ERC721VotesImpl-get_voting_units)
+
+Embeddable Implementations
+
+#### VotesImpl [!toc] [#VotesComponent-VotesImpl]
+
+- [`get_votes(self, account)`](#VotesComponent-get_votes)
+- [`get_past_votes(self, account, timepoint)`](#VotesComponent-get_past_votes)
+- [`get_past_total_supply(self, timepoint)`](#VotesComponent-get_past_total_supply)
+- [`delegates(self, account)`](#VotesComponent-delegates)
+- [`delegate(self, delegatee)`](#VotesComponent-delegate)
+- [`delegate_by_sig(self, delegator, delegatee, nonce, expiry, signature)`](#VotesComponent-delegate_by_sig)
+- [`clock(self)`](#VotesComponent-clock)
+- [`CLOCK_MODE(self)`](#VotesComponent-CLOCK_MODE)
+
+Internal implementations
+
+#### InternalImpl [!toc] [#VotesComponent-InternalImpl]
+
+- [`get_total_supply(self)`](#VotesComponent-get_total_supply)
+- [`move_delegate_votes(self, from, to, amount)`](#VotesComponent-move_delegate_votes)
+- [`transfer_voting_units(self, from, to, amount)`](#VotesComponent-transfer_voting_units)
+- [`num_checkpoints(self, account)`](#VotesComponent-num_checkpoints)
+- [`checkpoints(self, account, pos)`](#VotesComponent-checkpoints)
+- [`_delegate(self, account, delegatee)`](#VotesComponent-_delegate)
+
+Events
+
+- [`DelegateChanged(delegator, from_delegate, to_delegate)`](#VotesComponent-DelegateChanged)
+- [`DelegateVotesChanged(delegate, previous_votes, new_votes)`](#VotesComponent-DelegateVotesChanged)
+
+
+Returns the number of voting units for a given account.
+
+This implementation is specific to ERC20 tokens, where the balance of tokens directly represents the number of voting units.
+
+This implementation will work out of the box if the ERC20 component is implemented in the final contract.
+
+This implementation assumes tokens map to voting units 1:1. Any deviation from this formula when transferring voting units (e.g. by using hooks) may compromise the internal vote accounting.
+
+
+
+Returns the number of voting units for a given account.
+
+This implementation is specific to ERC721 tokens, where each token represents one voting unit. The function returns the balance of ERC721 tokens for the specified account.
+
+This implementation will work out of the box if the ERC721 component is implemented in the final contract.
+
+This implementation assumes tokens map to voting units 1:1. Any deviation from this formula when transferring voting units (e.g. by using hooks) may compromise the internal vote accounting.
+
+
+#### Embeddable functions [!toc] [#VotesComponent-EmbeddableFunctions]
+
+
+Returns the current amount of votes that `account` has.
+
+
+
+Returns the amount of votes that `account` had at a specific moment in the past.
+
+Requirements:
+
+- `timepoint` must be in the past.
+
+
+
+Returns the total supply of votes available at a specific moment in the past.
+
+This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. Votes that have not been delegated are still part of total supply, even though they would not participate in a vote.
+
+Requirements:
+
+- `timepoint` must be in the past.
+
+
+
+Returns the delegate that `account` has chosen.
+
+
+
+Delegates votes from the sender to `delegatee`.
+
+Emits a [DelegateChanged](#VotesComponent-DelegateChanged) event.
+
+May emit one or two [DelegateVotesChanged](#VotesComponent-DelegateVotesChanged) events.
+
+
+
+Delegates votes from `delegator` to `delegatee` through a [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) message signature validation.
+
+Requirements:
+
+- `expiry` must not be in the past.
+- `nonce` must match the account's current nonce.
+- `delegator` must implement `SRC6::is_valid_signature`.
+- `signature` should be valid for the message hash.
+
+Emits a [DelegateChanged](#VotesComponent-DelegateChanged) event.
+
+May emit one or two [DelegateVotesChanged](#VotesComponent-DelegateVotesChanged) events.
+
+
+
+Returns the current timepoint determined by the contract's operational mode, intended for use in time-sensitive logic. See [ERC-6372#clock](https://eips.ethereum.org/EIPS/eip-6372#clock).
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the contract is operating in. See [ERC-6372#CLOCK\_MODE](https://eips.ethereum.org/EIPS/eip-6372#clock_mode).
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+#### Internal functions [!toc] [#VotesComponent-InternalFunctions]
+
+
+Returns the current total supply of votes.
+
+
+
+Moves delegated votes from one delegate to another.
+
+May emit one or two [DelegateVotesChanged](#VotesComponent-DelegateVotesChanged) events.
+
+
+
+Transfers, mints, or burns voting units.
+
+To register a mint, `from` should be zero. To register a burn, `to` should be zero. Total supply of voting units will be adjusted with mints and burns.
+
+If voting units are based on an underlying transferable asset (like a token), you must call this function every time the asset is transferred to keep the internal voting power accounting in sync. For ERC20 and ERC721 tokens, this is typically handled using hooks.
+
+May emit one or two [DelegateVotesChanged](#VotesComponent-DelegateVotesChanged) events.
+
+
+
+Returns the number of checkpoints for `account`.
+
+
+
+Returns the `pos`-th checkpoint for `account`.
+
+
+
+Delegates all of `account`'s voting units to `delegatee`.
+
+Emits a [DelegateChanged](#VotesComponent-DelegateChanged) event.
+
+May emit one or two [DelegateVotesChanged](#VotesComponent-DelegateVotesChanged) events.
+
+
+#### Events [!toc] [#VotesComponent-Events]
+
+
+Emitted when an account changes their delegate.
+
+
+
+Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
+
+
+### `VotingUnitsTrait` [toc] [#VotingUnitsTrait]
+
+
+
+```rust
+pub trait VotingUnitsTrait {
+ fn get_voting_units(self: @TState, account: ContractAddress) -> u256;
+}
+```
+
+A trait that must be implemented when integrating [VotesComponent](#VotesComponent) into a contract. It offers a mechanism to retrieve the number of voting units for a given account at the current time.
+
+Functions
+
+- [`get_voting_units(self, account)`](#VotingUnitsTrait-get_voting_units)
+
+#### Functions [!toc] [#VotingUnitsTrait-Functions]
+
+
+Returns the number of voting units for a given account. For ERC20, this is typically the token balance. For ERC721, this is typically the number of tokens owned.
+
+While any formula can be used as a measure of voting units, the internal vote accounting of the contract may be compromised if voting units are transferred in any external flow by following a different formula.
+For example, when implementing the hook for ERC20, the number of voting units transferred should match the formula given by the `get_voting_units` implementation.
+
diff --git a/docs/content/contracts-cairo/2.x/api/introspection.mdx b/docs/content/contracts-cairo/2.x/api/introspection.mdx
new file mode 100644
index 00000000..a0bb6158
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/introspection.mdx
@@ -0,0 +1,100 @@
+---
+title: Introspection
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate handles [type introspection](https://en.wikipedia.org/wiki/Type_introspection) of contracts. In other words, it examines which functions can be called on a given contract. This is referred to as the contract's interface.
+
+## Interfaces
+
+### `ISRC5` [toc] [#ISRC5]
+
+
+
+```rust
+use openzeppelin_introspection::interface::ISRC5;
+```
+
+Interface of the SRC5 Introspection Standard as defined in [SNIP-5](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md).
+
+[SRC5 ID](#ISRC5)
+
+```text
+0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055
+```
+
+Functions
+
+- [`supports_interface(interface_id)`](#ISRC5-supports_interface)
+
+#### Functions [!toc] [#ISRC5-Functions]
+
+
+Checks whether the contract implements the given interface.
+
+Check [Computing the Interface ID](../introspection#computing-the-interface-id) for more information on how to compute this ID.
+
+
+## [](#core)Core
+
+### `SRC5Component` [toc] [#SRC5Component]
+
+
+
+```rust
+use openzeppelin_introspection::src5::SRC5Component;
+```
+
+SRC5 component extending [`ISRC5`](#ISRC5).
+
+Embeddable Implementations
+
+#### SRC5Impl [!toc] [#SRC5Component-SRC5Impl]
+
+- [`supports_interface(self, interface_id)`](#SRC5Component-supports_interface)
+
+Internal Implementations
+
+#### InternalImpl [!toc] [#SRC5Component-InternalImpl]
+
+- [`register_interface(self, interface_id)`](#SRC5Component-register_interface)
+- [`deregister_interface(self, interface_id)`](#SRC5Component-deregister_interface)
+
+#### Embeddable functions [!toc] [#SRC5Component-EmbeddableFunctions]
+
+
+See [`ISRC5::supports_interface`](#ISRC5-supports_interface).
+
+
+#### Internal functions [!toc] [#SRC5Component-InternalFunctions]
+
+
+Registers support for the given `interface_id`.
+
+
+
+Deregisters support for the given `interface_id`.
+
diff --git a/docs/content/contracts-cairo/2.x/api/merkle-tree.mdx b/docs/content/contracts-cairo/2.x/api/merkle-tree.mdx
new file mode 100644
index 00000000..5772e073
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/merkle-tree.mdx
@@ -0,0 +1,185 @@
+---
+title: Merkle Tree
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate provides a set of utilities for verifying Merkle Tree proofs on-chain. The tree and the proofs can be generated using this [JavaScript library](https://github.com/ericnordelo/strk-merkle-tree).
+
+This module provides:
+
+- `verify` - can prove that some value is part of a Merkle tree.
+- `verify_multi_proof` - can prove multiple values are part of a Merkle tree.
+
+`openzeppelin_merkle_tree` doesn’t have dependencies outside of `corelib`, and can be used in projects that are not Starknet-related.
+
+To use it as a standalone package, you can add it in your `Scarb.toml` as follows:
+
+`openzeppelin_merkle_tree = "3.0.0-alpha.1"`
+
+## [](#modules)Modules
+
+### [](#merkle_proof)`merkle_proof` [toc] [#merkle_proof]
+
+
+
+```rust
+use openzeppelin_merkle_tree::merkle_proof;
+```
+
+These functions deal with verification of Merkle Tree proofs.
+
+The tree and the proofs can be generated using this [JavaScript library](https://github.com/ericnordelo/strk-merkle-tree). You will find a quickstart guide in the readme.
+
+You should avoid using leaf values that are two felt252 values long prior to hashing, or use a hash function other than the one used to hash internal nodes for hashing leaves. This is because the concatenation of a sorted pair of internal nodes in the Merkle tree could be reinterpreted as a leaf value. The JavaScript library generates Merkle trees that are safe against this attack out of the box.
+
+Functions
+
+- [`verify(proof, root, leaf)`](#merkle_proof-verify)
+- [`verify_pedersen(proof, root, leaf)`](#merkle_proof-verify_pedersen)
+- [`verify_poseidon(proof, root, leaf)`](#merkle_proof-verify_poseidon)
+- [`process_proof(proof, leaf)`](#merkle_proof-process_proof)
+- [`verify_multi_proof(proof, proof_flags, root, leaves)`](#merkle_proof-verify_multi_proof)
+- [`process_multi_proof(proof, proof_flags, leaf)`](#merkle_proof-process_multi_proof)
+
+#### [](#merkle_proof-Functions)Functions [!toc]
+
+
+Returns true if a `leaf` can be proved to be a part of a Merkle tree defined by `root`.
+
+For this, a `proof` must be provided, containing sibling hashes on the branch from the leaf to the root of the tree.
+
+Each pair of leaves and each pair of pre-images are assumed to be sorted.
+
+This function expects a `CommutativeHasher` implementation. See [hashes::CommutativeHasher](#hashes-CommutativeHasher) for more information.
+
+`verify_pedersen` and `verify_poseidon` already include the corresponding `Hasher` implementations.
+
+
+
+Version of `verify` using Pedersen as the hashing function.
+
+
+
+Version of `verify` using Poseidon as the hashing function.
+
+
+
+Returns the rebuilt hash obtained by traversing a Merkle tree up from `leaf` using `proof`.
+
+A `proof` is valid if and only if the rebuilt hash matches the root of the tree.
+
+When processing the proof, the pairs of leaves & pre-images are assumed to be sorted.
+
+This function expects a `CommutativeHasher` implementation. See [hashes::CommutativeHasher](#hashes-CommutativeHasher) for more information.
+
+
+
+Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by `root`, according to `proof` and `proof_flags` as described in `process_multi_proof`.
+
+The `leaves` must be validated independently.
+
+Not all Merkle trees admit multiproofs. See `process_multi_proof` for details.
+
+Consider the case where `root == proof.at(0) && leaves.len() == 0` as it will return `true`.
+
+This function expects a `CommutativeHasher` implementation. See [hashes::CommutativeHasher](#hashes-CommutativeHasher) for more information.
+
+
+
+Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`.
+
+The reconstruction proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another leaf/inner node or a proof sibling node, depending on whether each `proof_flags` item is true or false respectively.
+
+Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that:
+
+1. The tree is complete (but not necessarily perfect).
+2. The leaves to be proven are in the opposite order than they are in the tree. (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
+
+The *empty set* (i.e. the case where `proof.len() == 1 && leaves.len() == 0`) is considered a no-op, and therefore a valid multiproof (i.e. it returns `proof.at(0)`). Consider disallowing this case if you're not validating the leaves elsewhere.
+
+This function expects a `CommutativeHasher` implementation. See [hashes::CommutativeHasher](#hashes-CommutativeHasher) for more information.
+
+
+### [](#hashes)`hashes` [toc] [#hashes]
+
+
+
+```rust
+use openzeppelin_merkle_tree::hashes;
+```
+
+Module providing the trait and default implementations for the commutative hash functions used in [`merkle_proof`](#merkle_proof).
+
+The `PedersenCHasher` implementation matches the default node hashing function used in the [JavaScript library](https://github.com/ericnordelo/strk-merkle-tree).
+
+Traits
+
+- [`CommutativeHasher`](#hashes-CommutativeHasher)
+
+Impls
+
+- [`PedersenCHasher`](#hashes-PedersenCHasher)
+- [`PoseidonCHasher`](#hashes-PoseidonCHasher)
+
+#### [](#hashes-Traits)Traits [!toc]
+
+
+Declares a commutative hash function with the following signature:
+
+`commutative_hash(a: felt252, b: felt252) → felt252;`
+
+which computes a commutative hash of a sorted pair of felt252 values.
+
+This is usually implemented as an extension of a non-commutative hash function, like Pedersen or Poseidon, returning the hash of the concatenation of the two values by first sorting them.
+
+Frequently used when working with merkle proofs.
+
+The `commutative_hash` function MUST follow the invariant that `commutative_hash(a, b) == commutative_hash(b, a)`.
+
+
+#### [](#hashes-Impls)Impls [!toc]
+
+
+Implementation of the `CommutativeHasher` trait which computes the Pedersen hash of chaining the two input values with the len (2), sorting the pair first.
+
+
+
+Implementation of the `CommutativeHasher` trait which computes the Poseidon hash of the concatenation of two values, sorting the pair first.
+
diff --git a/docs/content/contracts-cairo/2.x/api/security.mdx b/docs/content/contracts-cairo/2.x/api/security.mdx
new file mode 100644
index 00000000..12e3a01f
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/security.mdx
@@ -0,0 +1,202 @@
+---
+title: Security
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate provides components to handle common security-related tasks.
+
+## [](#initializable)Initializable
+
+### [](#InitializableComponent)`InitializableComponent` [toc] [#InitializableComponent]
+
+
+
+```rust
+use openzeppelin_security::InitializableComponent;
+```
+
+Component enabling one-time initialization for contracts.
+
+Embeddable Implementations
+
+InitializableImpl
+
+- [`is_initialized(self)`](#InitializableComponent-is_initialized)
+
+Internal Implementations
+
+InternalImpl
+
+- [`initialize(self)`](#InitializableComponent-initialize)
+
+#### [](#InitializableComponent-Embeddable-Functions)Embeddable functions [!toc]
+
+
+Returns whether the contract has been initialized.
+
+
+#### [](#InitializableComponent-Internal-Functions)Internal functions [!toc]
+
+
+Initializes the contract. Can only be called once.
+
+Requirements:
+
+- the contract must not have been initialized before.
+
+
+## [](#pausable)Pausable
+
+### [](#PausableComponent)`PausableComponent` [toc] [#PausableComponent]
+
+
+
+```rust
+use openzeppelin_security::PausableComponent;
+```
+
+Component to implement an emergency stop mechanism.
+
+Embeddable Implementations
+
+PausableImpl
+
+- [`is_paused(self)`](#PausableComponent-is_paused)
+
+Internal Implementations
+
+InternalImpl
+
+- [`assert_not_paused(self)`](#PausableComponent-assert_not_paused)
+- [`assert_paused(self)`](#PausableComponent-assert_paused)
+- [`pause(self)`](#PausableComponent-pause)
+- [`unpause(self)`](#PausableComponent-unpause)
+
+Events
+
+- [`Paused(account)`](#PausableComponent-Paused)
+- [`Unpaused(account)`](#PausableComponent-Unpaused)
+
+#### [](#PausableComponent-Embeddable-Functions)Embeddable functions [!toc]
+
+
+Returns whether the contract is currently paused.
+
+
+#### [](#PausableComponent-Internal-Functions)Internal functions [!toc]
+
+
+Panics if the contract is paused.
+
+
+
+Panics if the contract is not paused.
+
+
+
+Pauses the contract.
+
+Requirements:
+
+- the contract must not be paused.
+
+Emits a [Paused](#PausableComponent-Paused) event.
+
+
+
+Unpauses the contract.
+
+Requirements:
+
+- the contract must be paused.
+
+Emits an [Unpaused](#PausableComponent-Unpaused) event.
+
+
+#### [](#PausableComponent-Events)Events [!toc]
+
+
+Emitted when the contract is paused by `account`.
+
+
+
+Emitted when the contract is unpaused by `account`.
+
+
+## [](#reentrancyguard)ReentrancyGuard
+
+### [](#ReentrancyGuardComponent)`ReentrancyGuardComponent` [toc] [#ReentrancyGuardComponent]
+
+
+
+```rust
+use openzeppelin_security::ReentrancyGuardComponent;
+```
+
+Component to help prevent reentrant calls.
+
+Internal Implementations
+
+InternalImpl
+
+- [`start(self)`](#ReentrancyGuardComponent-start)
+- [`end(self)`](#ReentrancyGuardComponent-end)
+
+#### [](#ReentrancyGuardComponent-Internal-Functions)Internal functions [!toc]
+
+
+Prevents a contract's function from calling itself or another protected function, directly or indirectly.
+
+Requirements:
+
+- the guard must not be currently enabled.
+
+
+
+Removes the reentrant guard.
+
diff --git a/docs/content/contracts-cairo/2.x/api/testing.mdx b/docs/content/contracts-cairo/2.x/api/testing.mdx
new file mode 100644
index 00000000..7a9b3cc6
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/testing.mdx
@@ -0,0 +1,10 @@
+---
+title: Testing
+---
+
+
+The `openzeppelin_testing` package version is now decoupled from the `cairo-contracts` version.
+
+
+You can find the documentation for the `openzeppelin_testing` package in the README for the corresponding version in the
+[scarb registry](https://scarbs.xyz/packages/openzeppelin_testing).
diff --git a/docs/content/contracts-cairo/2.x/api/token_common.mdx b/docs/content/contracts-cairo/2.x/api/token_common.mdx
new file mode 100644
index 00000000..3be2e45f
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/token_common.mdx
@@ -0,0 +1,469 @@
+---
+title: Common (Token)
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This module provides extensions and utilities that are common to multiple token standards.
+
+## Interfaces
+
+### [](#IERC2981)`IERC2981` [toc] [#IERC2981]
+
+
+
+```rust
+use openzeppelin_token::common::erc2981::interface::IERC2981;
+```
+
+[SRC5 ID](./introspection#ISRC5)
+
+```text
+0x2d3414e45a8700c29f119a54b9f11dca0e29e06ddcb214018fc37340e165ed6
+```
+
+Interface of the ERC2981 standard as defined in [EIP-2981](https://eips.ethereum.org/EIPS/eip-2981).
+
+Functions
+
+- [`royalty_info(token_id, sale_price)`](#IERC2981-royalty_info)
+
+#### [](#IERC2981-Functions)Functions [!toc]
+
+
+Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of exchange. The royalty amount is denominated and must be paid in that same unit of exchange.
+
+
+### [](#IERC2981Info)`IERC2981Info` [toc] [#IERC2981Info]
+
+
+
+```rust
+use openzeppelin_token::common::erc2981::interface::IERC2981Info;
+```
+
+Interface providing external read functions for discovering the state of ERC2981 component.
+
+Functions
+
+- [`default_royalty()`](#IERC2981Info-default_royalty)
+- [`token_royalty(token_id)`](#IERC2981Info-token_royalty)
+
+#### [](#IERC2981Info-Functions)Functions [!toc]
+
+
+Returns the royalty information that all ids in this contract will default to.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+
+Returns the royalty information specific to a token.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+### [](#IERC2981Admin)`IERC2981Admin` [toc] [#IERC2981Admin]
+
+
+
+```rust
+use openzeppelin_token::common::erc2981::interface::IERC2981Admin;
+```
+
+Interface providing external admin functions for managing the settings of ERC2981 component.
+
+Functions
+
+- [`set_default_royalty(receiver, fee_numerator)`](#IERC2981Admin-set_default_royalty)
+- [`delete_default_royalty()`](#IERC2981Admin-delete_default_royalty)
+- [`set_token_royalty(token_id, receiver, fee_numerator)`](#IERC2981Admin-set_token_royalty)
+- [`reset_token_royalty(token_id)`](#IERC2981Admin-reset_token_royalty)
+
+#### [](#IERC2981Admin-Functions)Functions [!toc]
+
+
+Sets the royalty information that all ids in this contract will default to.
+
+
+
+Sets the default royalty percentage and receiver to zero.
+
+
+
+Sets the royalty information for a specific token id that takes precedence over the global default.
+
+
+
+Resets royalty information for the token id back to unset.
+
+
+## [](#erc2981)ERC2981
+
+### [](#ERC2981Component)`ERC2981Component` [toc] [#ERC2981Component]
+
+
+
+```rust
+use openzeppelin_token::common::erc2981::ERC2981Component;
+```
+
+ERC2981 component extending [IERC2981](#IERC2981).
+
+[Immutable Component Config](../components#immutable-config)
+
+constants
+
+- [`FEE_DENOMINATOR`](#ERC2981Component-IC-FEE_DENOMINATOR)
+
+functions
+
+- [`validate()`](#ERC2981Component-IC-validate)
+
+Embeddable Implementations
+
+ERC2981Impl
+
+- [`royalty_info(self, token_id, sale_price)`](#ERC2981Component-royalty_info)
+
+ERC2981InfoImpl
+
+- [`default_royalty(self)`](#ERC2981InfoImpl-default_royalty)
+- [`token_royalty(self, token_id)`](#ERC2981InfoImpl-token_royalty)
+
+ERC2981AdminOwnableImpl
+
+- [`set_default_royalty(self, receiver, fee_numerator)`](#ERC2981AdminOwnableImpl-set_default_royalty)
+- [`delete_default_royalty(self)`](#ERC2981AdminOwnableImpl-delete_default_royalty)
+- [`set_token_royalty(self, token_id, receiver, fee_numerator)`](#ERC2981AdminOwnableImpl-set_token_royalty)
+- [`reset_token_royalty(self, token_id)`](#ERC2981AdminOwnableImpl-reset_token_royalty)
+
+ERC2981AdminAccessControlImpl
+
+- [`set_default_royalty(self, receiver, fee_numerator)`](#ERC2981AdminAccessControlImpl-set_default_royalty)
+- [`delete_default_royalty(self)`](#ERC2981AdminAccessControlImpl-delete_default_royalty)
+- [`set_token_royalty(self, token_id, receiver, fee_numerator)`](#ERC2981AdminAccessControlImpl-set_token_royalty)
+- [`reset_token_royalty(self, token_id)`](#ERC2981AdminAccessControlImpl-reset_token_royalty)
+
+Internal implementations
+
+InternalImpl
+
+- [`initializer(self, default_receiver, default_royalty_fraction)`](#ERC2981Component-initializer)
+- [`_default_royalty(self)`](#ERC2981Component-_default_royalty)
+- [`_set_default_royalty(self, receiver, fee_numerator)`](#ERC2981Component-_set_default_royalty)
+- [`_delete_default_royalty(self)`](#ERC2981Component-_delete_default_royalty)
+- [`_token_royalty(self, token_id)`](#ERC2981Component-_token_royalty)
+- [`_set_token_royalty(self, token_id, receiver, fee_numerator)`](#ERC2981Component-_set_token_royalty)
+- [`_reset_token_royalty(self, token_id)`](#ERC2981Component-_reset_token_royalty)
+
+#### [](#ERC2981Component-Immutable-Config)Immutable Config constants [!toc]
+
+
+The denominator with which to interpret the fee set in `_set_token_royalty` and `_set_default_royalty` as a fraction of the sale price.
+
+
+
+Validates the given implementation of the contract's configuration.
+
+Requirements:
+
+- `FEE_DENOMINATOR` must be greater than 0.
+
+This function is called by the contract's initializer.
+
+
+#### [](#ERC2981Component-Embeddable-functions)Embeddable functions [!toc]
+
+
+Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The amount of royalty payment.
+
+
+
+Returns the royalty information that all ids in this contract will default to.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+
+Returns the royalty information specific to a token. If no specific royalty information is set for the token, the default is returned.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+#### [](#ERC2981Component-ERC2981AdminOwnableImpl)ERC2981AdminOwnableImpl [!toc]
+
+Provides admin functions for managing royalty settings that are restricted to be called only by the contract's owner. Requires the contract to implement [OwnableComponent](./access#OwnableComponent).
+
+
+Sets the royalty information that all ids in this contract will default to.
+
+Requirements:
+
+- The caller is the contract owner.
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Sets the default royalty percentage and receiver to zero.
+
+Requirements:
+
+- The caller is the contract owner.
+
+
+
+Sets the royalty information for a specific token id that takes precedence over the global default.
+
+Requirements:
+
+- The caller is the contract owner.
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Resets royalty information for the token id back to unset.
+
+Requirements:
+
+- The caller is the contract owner.
+
+
+#### [](#ERC2981Component-ERC2981AdminAccessControlImpl)ERC2981AdminAccessControlImpl [!toc]
+
+Provides admin functions for managing royalty settings that require `ROYALTY_ADMIN_ROLE` to be granted to the caller. Requires the contract to implement [AccessControlComponent](./access#AccessControlComponent).
+
+
+Role for the admin responsible for managing royalty settings.
+
+
+
+Sets the royalty information that all ids in this contract will default to.
+
+Requirements:
+
+- The caller must have `ROYALTY_ADMIN_ROLE` role.
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Sets the default royalty percentage and receiver to zero.
+
+Requirements:
+
+- The caller must have `ROYALTY_ADMIN_ROLE` role.
+
+
+
+Sets the royalty information for a specific token id that takes precedence over the global default.
+
+Requirements:
+
+- The caller must have `ROYALTY_ADMIN_ROLE` role.
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Resets royalty information for the token id back to unset.
+
+Requirements:
+
+- The caller must have `ROYALTY_ADMIN_ROLE` role.
+
+
+#### [](#ERC2981Component-Internal-functions)Internal functions [!toc]
+
+
+Initializes the contract by setting the default royalty and registering the supported interface.
+
+Requirements:
+
+- `default_receiver` cannot be the zero address.
+- `default_royalty_fraction` cannot be greater than the fee denominator.
+- The fee denominator must be greater than 0.
+
+The fee denominator is set by the contract using the [Immutable Component Config](../components#immutable-config).
+
+
+
+Returns the royalty information that all ids in this contract will default to.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+
+Sets the royalty information that all ids in this contract will default to.
+
+Requirements:
+
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Sets the default royalty percentage and receiver to zero.
+
+
+
+Returns the royalty information that all ids in this contract will default to.
+
+The returned tuple contains:
+
+- `t.0`: The receiver of the royalty payment.
+- `t.1`: The numerator of the royalty fraction.
+- `t.2`: The denominator of the royalty fraction.
+
+
+
+Sets the royalty information for a specific token id that takes precedence over the global default.
+
+Requirements:
+
+- `receiver` cannot be the zero address.
+- `fee_numerator` cannot be greater than the fee denominator.
+
+
+
+Resets royalty information for the token id back to unset.
+
diff --git a/docs/content/contracts-cairo/2.x/api/udc.mdx b/docs/content/contracts-cairo/2.x/api/udc.mdx
new file mode 100644
index 00000000..28bc000a
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/udc.mdx
@@ -0,0 +1,85 @@
+---
+title: Universal Deployer
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+Reference of the Universal Deployer Contract (UDC) interface and preset.
+
+## Interfaces
+
+### [](#IUniversalDeployer)`IUniversalDeployer` [toc] [#IUniversalDeployer]
+
+
+
+```rust
+use openzeppelin_utils::interfaces::IUniversalDeployer;
+```
+
+Functions
+
+- [`deploy_contract(class_hash, salt, not_from_zero, calldata)`](#IUniversalDeployer-deploy_contract)
+
+Events
+
+- [`ContractDeployed(address, deployer, not_from_zero, class_hash, calldata, salt)`](#IUniversalDeployer-ContractDeployed)
+
+#### [](#IUniversalDeployer-Functions)Functions [!toc]
+
+
+Deploys a contract through the Universal Deployer Contract.
+
+
+#### [](#IUniversalDeployer-Events)Events [!toc]
+
+
+Emitted when `deployer` deploys a contract through the Universal Deployer Contract.
+
+
+## [](#presets)Presets
+
+### [](#UniversalDeployer)`UniversalDeployer` [toc] [#UniversalDeployer]
+
+
+
+```rust
+use openzeppelin_presets::UniversalDeployer;
+```
+
+The standard Universal Deployer Contract.
+
+[Sierra class hash](../presets)
+
+```text
+{{UniversalDeployerClassHash}}
+```
+
+Embedded Implementations
+
+UniversalDeployerImpl
+
+- [`deploy_contract(self, address, deployer, not_from_zero, class_hash, calldata, salt)`](#UniversalDeployer-deploy_contract)
+
+#### [](#UniversalDeployer-External-functions)External functions [!toc]
+
+
+Deploys a contract through the Universal Deployer Contract.
+
+When `not_from_zero` is `true`, `salt` is hashed with the caller address and the modified salt is passed to the inner `deploy_syscall`. This type of deployment is [origin-dependent](../udc#origin-dependent).
+
+When `not_from_zero` is `false`, the deployment type is [origin-independent](../udc#origin-independent).
+
+Emits an [ContractDeployed](#IUniversalDeployer-ContractDeployed) event.
+
diff --git a/docs/content/contracts-cairo/2.x/api/upgrades.mdx b/docs/content/contracts-cairo/2.x/api/upgrades.mdx
new file mode 100644
index 00000000..493a1408
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/upgrades.mdx
@@ -0,0 +1,128 @@
+---
+title: Upgrades
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate provides interfaces and utilities related to upgradeability.
+
+## Interfaces
+
+### [](#IUpgradeable)`IUpgradeable` [toc] [#IUpgradeable]
+
+
+
+```rust
+use openzeppelin_upgrades::interface::IUpgradeable;
+```
+
+Interface of an upgradeable contract.
+
+Functions
+
+- [`upgrade(new_class_hash)`](#IUpgradeable-upgrade)
+
+#### [](#IUpgradeable-Functions)Functions [!toc]
+
+
+Upgrades the contract code by updating its [class hash](https://docs.starknet.io/architecture-and-concepts/smart-contracts/class-hash/).
+
+This function is usually protected by an [Access Control](../access) mechanism.
+
+
+### [](#IUpgradeAndCall)`IUpgradeAndCall` [toc] [#IUpgradeAndCall]
+
+
+
+```rust
+use openzeppelin_upgrades::interface::IUpgradeAndCall;
+```
+
+Interface for an upgradeable contract that couples an upgrade with a function call in the upgraded context.
+
+Functions
+
+- [`upgrade_and_call(new_class_hash, selector, calldata)`](#IUpgradeAndCall-upgrade_and_call)
+
+#### [](#IUpgradeAndCall-Functions)Functions [!toc]
+
+
+Upgrades the contract code by updating its [class hash](https://docs.starknet.io/architecture-and-concepts/smart-contracts/class-hash/) and calls `selector` with the upgraded context.
+
+This function is usually protected by an [Access Control](../access) mechanism.
+
+
+## [](#core)Core
+
+### [](#UpgradeableComponent)`UpgradeableComponent` [toc] [#UpgradeableComponent]
+
+
+
+```rust
+use openzeppelin_upgrades::upgradeable::UpgradeableComponent;
+```
+
+Upgradeable component.
+
+Internal Implementations
+
+InternalImpl
+
+- [`upgrade(self, new_class_hash)`](#UpgradeableComponent-upgrade)
+- [`upgrade_and_call(self, new_class_hash, selector, calldata)`](#UpgradeableComponent-upgrade_and_call)
+
+Events
+
+- [`Upgraded(class_hash)`](#UpgradeableComponent-Upgraded)
+
+#### [](#UpgradeableComponent-Internal-Functions)Internal Functions [!toc]
+
+
+Upgrades the contract by updating the contract [class hash](https://docs.starknet.io/architecture-and-concepts/smart-contracts/class-hash/).
+
+Requirements:
+
+- `new_class_hash` must be different from zero.
+
+Emits an [Upgraded](#UpgradeableComponent-Upgraded) event.
+
+
+
+Replaces the contract's class hash with `new_class_hash` and then calls `selector` from the upgraded context. This function returns the unwrapped `call_contract_syscall` return value(s), if available, of the `selector` call.
+
+Requirements:
+
+- `new_class_hash` must be different from zero.
+
+The function call comes from the upgraded contract itself and not the account.
+
+A similar behavior to `upgrade_and_call` can also be achieved with a list of calls from an account since the [SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md) account standard supports multicall. An account can execute a list of calls with [upgrade](#IUpgradeable-upgrade) being the first element in the list and the extra function call as the second. With this approach, the calls will execute from the account's context and can't be front-ran.
+
+Emits an [Upgraded](#UpgradeableComponent-Upgraded) event.
+
+
+#### [](#UpgradeableComponent-Events)Events [!toc]
+
+
+Emitted when the [class hash](https://docs.starknet.io/architecture-and-concepts/smart-contracts/class-hash/) is upgraded.
+
diff --git a/docs/content/contracts-cairo/2.x/api/utilities.mdx b/docs/content/contracts-cairo/2.x/api/utilities.mdx
new file mode 100644
index 00000000..7aef39e7
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/api/utilities.mdx
@@ -0,0 +1,381 @@
+---
+title: Utilities
+---
+
+import { UMBRELLA_VERSION } from "../utils/constants.js";
+
+This crate provides miscellaneous components and libraries containing utility functions to handle common tasks.
+
+## Core
+
+### `utils` [toc] [#utils]
+
+
+
+```rust
+use openzeppelin_utils;
+```
+
+Module containing core utilities of the library.
+
+Members
+
+Inner modules
+
+- [`cryptography`](#utils-cryptography)
+- [`deployments`](#utils-deployments)
+- [`math`](#utils-math)
+- [`contract_clock`](#utils-contract_clock)
+- [`serde`](#utils-serde)
+
+#### Inner modules [!toc] [#utils-Inner-Modules]
+
+
+See [`openzeppelin_utils::cryptography`](#cryptography).
+
+
+
+See [`openzeppelin_utils::deployments`](#deployments).
+
+
+
+See [`openzeppelin_utils::math`](#math).
+
+
+
+See [`openzeppelin_utils::contract_clock`](#contract_clock).
+
+
+
+See [`openzeppelin_utils::serde`](#serde).
+
+
+### `cryptography` [toc] [#cryptography]
+
+
+
+```rust
+use openzeppelin_utils::cryptography;
+```
+
+Module containing utilities related to cryptography.
+
+Members
+
+Inner modules
+
+- [`nonces`](#cryptography-nonces)
+- [`snip12`](#cryptography-snip12)
+
+#### Inner modules [!toc] [#cryptography-Inner-Modules]
+
+
+See [`openzeppelin_utils::cryptography::nonces::NoncesComponent`](#NoncesComponent).
+
+
+
+See [`openzeppelin_utils::cryptography::snip12`](#snip12).
+
+
+### `deployments` [toc] [#deployments]
+
+
+
+```rust
+use openzeppelin_utils::deployments;
+```
+
+Module containing utility functions for calculating contract addresses through [deploy\_syscall](https://docs.starknet.io/architecture-and-concepts/smart-contracts/system-calls-cairo1/#deploy) and the [Universal Deployer Contract](../udc) (UDC).
+
+Members
+
+Structs
+
+- [`DeployerInfo(caller_address, udc_address)`](#deployments-DeployerInfo)
+
+Functions
+
+- [`calculate_contract_address_from_deploy_syscall(salt, class_hash, constructor_calldata, deployer_address)`](#deployments-calculate_contract_address_from_deploy_syscall)
+- [`compute_hash_on_elements(data)`](#deployments-compute_hash_on_elements)
+- [`calculate_contract_address_from_udc(salt, class_hash, constructor_calldata, deployer_info)`](#deployments-calculate_contract_address_from_udc)
+
+#### Structs [!toc] [#deployments-Structs]
+
+
+Struct containing arguments necessary in [utils::calculate\_contract\_address\_from\_udc](#deployments-calculate_contract_address_from_udc) for origin-dependent deployment calculations.
+
+
+#### Functions [!toc] [#deployments-Functions]
+
+
+Returns the contract address when passing the given arguments to [deploy\_syscall](https://docs.starknet.io/architecture-and-concepts/smart-contracts/system-calls-cairo1/#deploy).
+
+
+
+Creates a Pedersen hash chain with the elements of `data` and returns the finalized hash.
+
+
+
+Returns the calculated contract address for UDC deployments.
+
+Origin-independent deployments (deployed from zero) should pass `Option::None` as `deployer_info`.
+
+Origin-dependent deployments hash `salt` with `caller_address` (member of [DeployerInfo](#deployments-DeployerInfo)) and pass the hashed salt to the inner [deploy\_syscall](https://docs.starknet.io/architecture-and-concepts/smart-contracts/system-calls-cairo1/#deploy) as the `contract_address_salt` argument.
+
+
+### `math` [toc] [#math]
+
+
+
+```rust
+use openzeppelin_utils::math;
+```
+
+Module containing math utilities.
+
+Members
+
+Functions
+
+- [`average(a, b)`](#math-average)
+
+#### Functions [!toc] [#math-Functions]
+
+
+Returns the average of two unsigned integers. The result is rounded down.
+
+`T` is a generic value matching different numeric implementations.
+
+
+### `contract_clock` [toc] [#contract_clock]
+
+
+```rust
+use openzeppelin_utils::contract_clock;
+```
+
+Module providing a trait for the [EIP-6372](https://eips.ethereum.org/EIPS/eip-6372) standard along with default clock implementations based on either block number or block timestamp.
+
+Traits
+
+- [`ERC6372Clock`](#ERC6372Clock)
+
+Implementations
+
+- [`ERC6372BlockNumberClock`](#contract_clock-ERC6372BlockNumberClock)
+- [`ERC6372TimestampClock`](#contract_clock-ERC6372TimestampClock)
+
+#### `ERC6372Clock` [toc] [#ERC6372Clock]
+
+
+```rust
+use openzeppelin_utils::contract_clock::ERC6372Clock;
+```
+
+A trait for the [EIP-6372](https://eips.ethereum.org/EIPS/eip-6372) standard that allows flexible internal clock implementation — based on block timestamp, block number, or a custom logic.
+
+Functions
+
+- [`clock()`](#ERC6372Clock-clock)
+- [`CLOCK_MODE()`](#ERC6372Clock-CLOCK_MODE)
+
+#### Functions [!toc] [#ERC6372Clock-Functions]
+
+
+Returns the current timepoint determined by the contract's operational mode, intended for use in time-sensitive logic.
+
+Requirements:
+
+- This function MUST always be non-decreasing.
+
+
+
+Returns a description of the clock the contract is operating in.
+
+Requirements:
+
+- The output MUST be formatted like a URL query string, decodable in standard JavaScript.
+
+
+#### Implementations [!toc] [#contract_clock-Impls]
+
+
+Implementation of the `ERC6372Clock` trait that uses the block number as its clock reference.
+
+
+
+Implementation of the `ERC6372Clock` trait that uses the block timestamp as its clock reference.
+
+
+### `serde` [toc] [#serde]
+
+
+
+```rust
+use openzeppelin_utils::serde;
+```
+
+Module containing utilities related to serialization and deserialization of Cairo data structures.
+
+Members
+
+Traits
+
+- [`SerializedAppend`](#serde-SerializedAppend)
+
+#### Traits [!toc] [#serde-Traits]
+
+
+Importing this trait allows the ability to append a serialized representation of a Cairo data structure already implementing the `Serde` trait to a `felt252` buffer.
+
+Usage example:
+
+```rust
+use openzeppelin_utils::serde::SerializedAppend;
+use starknet::ContractAddress;
+
+fn to_calldata(recipient: ContractAddress, amount: u256) -> Array {
+ let mut calldata = array![];
+ calldata.append_serde(recipient);
+ calldata.append_serde(amount);
+ calldata
+}
+```
+
+Note that the `append_serde` method is automatically available for arrays of felts, and it accepts any data structure that implements the `Serde` trait.
+
+
+## Cryptography [#cryptography-toc]
+
+### `NoncesComponent` [toc] [#NoncesComponent]
+
+
+
+```rust
+use openzeppelin_utils::cryptography::nonces::NoncesComponent;
+```
+
+This component provides a simple mechanism for handling incremental nonces for a set of addresses. It is commonly used to prevent replay attacks when contracts accept signatures as input.
+
+Embeddable Implementations
+
+NoncesImpl
+
+- [`nonces(self, owner)`](#NoncesComponent-nonces)
+
+Internal Implementations
+
+InternalImpl
+
+- [`use_nonce(self, owner)`](#NoncesComponent-use_nonce)
+- [`use_checked_nonce(self, owner, nonce)`](#NoncesComponent-use_checked_nonce)
+
+#### Embeddable functions [!toc] [#NoncesComponent-Embeddable-Functions]
+
+
+Returns the next unused nonce for an `owner`.
+
+
+#### Internal functions [!toc] [#NoncesComponent-Internal-Functions]
+
+
+Consumes a nonce, returns the current value, and increments nonce.
+
+For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be decremented or reset. This guarantees that the nonce never overflows.
+
+
+
+Same as `use_nonce` but checking that `nonce` is the next valid one for `owner`.
+
+
+### `snip12` [toc] [#snip12]
+
+
+
+```rust
+use openzeppelin_utils::snip12;
+```
+
+Supports on-chain generation of message hashes compliant with [SNIP12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md).
+
+For a full walkthrough on how to use this module, see the [SNIP12 and Typed Messages](../guides/snip12) guide.
diff --git a/docs/content/contracts-cairo/2.x/backwards-compatibility.mdx b/docs/content/contracts-cairo/2.x/backwards-compatibility.mdx
new file mode 100644
index 00000000..3c63bfcd
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/backwards-compatibility.mdx
@@ -0,0 +1,35 @@
+---
+title: Backwards Compatibility
+---
+
+OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. Patch and minor updates will generally be backwards compatible, with rare exceptions as detailed below. Major updates should be assumed incompatible with previous releases. On this page, we provide details about these guarantees.
+
+Bear in mind that while releasing versions, we treat minors as majors and patches as minors, in accordance with semantic versioning. This means that `v2.1.0` could be adding features to `v2.0.0`, while `v3.0.0` would be considered a breaking release.
+
+## API
+
+In backwards compatible releases, all changes should be either additions or modifications to internal implementation details. Most code should continue to compile and behave as expected. The exceptions to this rule are listed below.
+
+### Security
+
+Infrequently, a patch or minor update will remove or change an API in a breaking way but only if the previous API is considered insecure. These breaking changes will be noted in the changelog and release notes, and published along with a security advisory.
+
+### Errors
+
+The specific error format and data that is included with reverts should not be assumed stable unless otherwise specified.
+
+### Major releases
+
+Major releases should be assumed incompatible. Nevertheless, the external interfaces of contracts will remain compatible if they are standardized, or if the maintainers judge that changing them would cause significant strain on the ecosystem.
+
+An important aspect that major releases may break is "upgrade compatibility", in particular storage layout compatibility. It will never be safe for a live contract to upgrade from one major release to another.
+
+In the case of breaking "upgrade compatibility", an entry to the changelog will be added listing those breaking changes.
+
+## Storage layout
+
+Patch updates will always preserve storage layout compatibility, and after `1.0.0` minors will too. This means that a live contract can be upgraded from one minor to another without corrupting the storage layout. In some cases it may be necessary to initialize new state variables when upgrading, although we expect this to be infrequent.
+
+## Cairo version
+
+The minimum Cairo version required to compile the contracts will remain unchanged for patch updates, but it may change for minors.
diff --git a/docs/content/contracts-cairo/2.x/components.mdx b/docs/content/contracts-cairo/2.x/components.mdx
new file mode 100644
index 00000000..5266792a
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/components.mdx
@@ -0,0 +1,667 @@
+---
+title: Components
+---
+
+The following documentation provides reasoning and examples on how to use Contracts for Cairo components.
+
+Starknet components are separate modules that contain storage, events, and implementations that can be integrated into a contract.
+Components themselves cannot be declared or deployed.
+Another way to think of components is that they are abstract modules that must be instantiated.
+
+[shamans_post]: https://community.starknet.io/t/cairo-components/101136#components-1
+[cairo_book]: https://book.cairo-lang.org/ch103-02-00-composability-and-components.html
+
+
+For more information on the construction and design of Starknet components, see the [Starknet Shamans post][shamans_post] and the [Cairo book][cairo_book].
+
+
+## Building a contract
+
+### Setup
+
+The contract should first import the component and declare it with the `component!` macro:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ // Import the component
+ use openzeppelin_security::InitializableComponent;
+
+ // Declare the component
+ component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
+}
+```
+
+The `path` argument should be the imported component itself (in this case, [InitializableComponent](./security#initializable)).
+The `storage` and `event` arguments are the variable names that will be set in the `Storage` struct and `Event` enum, respectively.
+Note that even if the component doesn’t define any events, the compiler will still create an empty event enum inside the component module.
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_security::InitializableComponent;
+
+ component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ initializable: InitializableComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ InitializableEvent: InitializableComponent::Event
+ }
+}
+```
+
+The `#[substorage(v0)]` attribute must be included for each component in the `Storage` trait.
+This allows the contract to have indirect access to the component’s storage.
+See [Accessing component storage](#accessing-component-storage) for more on this.
+
+The `#[flat]` attribute for events in the `Event` enum, however, is not required.
+For component events, the first key in the event log is the component ID.
+Flattening the component event removes it, leaving the event ID as the first key.
+
+### Implementations
+
+Components come with granular implementations of different interfaces.
+This allows contracts to integrate only the implementations that they’ll use and avoid unnecessary bloat.
+Integrating an implementation looks like this:
+
+```rust
+mod MyContract {
+ use openzeppelin_security::InitializableComponent;
+
+ component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
+
+ (...)
+
+ // Gives the contract access to the implementation methods
+ impl InitializableImpl =
+ InitializableComponent::InitializableImpl;
+}
+```
+
+Defining an `impl` gives the contract access to the methods within the implementation from the component.
+For example, `is_initialized` is defined in the `InitializableImpl`.
+A function on the contract level can expose it like this:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_security::InitializableComponent;
+
+ component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
+
+ (...)
+
+ impl InitializableImpl =
+ InitializableComponent::InitializableImpl;
+
+ #[external(v0)]
+ fn is_initialized(ref self: ContractState) -> bool {
+ self.initializable.is_initialized()
+ }
+}
+```
+
+While there’s nothing wrong with manually exposing methods like in the previous example, this process can be tedious for implementations with many methods.
+Fortunately, a contract can embed implementations which will expose all of the methods of the implementation.
+To embed an implementation, add the `#[abi(embed_v0)]` attribute above the `impl`:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ (...)
+
+ // This attribute exposes the methods of the `impl`
+ #[abi(embed_v0)]
+ impl InitializableImpl =
+ InitializableComponent::InitializableImpl;
+}
+```
+
+`InitializableImpl` defines the `is_initialized` method in the component.
+By adding the embed attribute, `is_initialized` becomes a contract entrypoint for `MyContract`.
+
+
+Embeddable implementations, when available in this library’s components, are segregated from the internal component implementation which makes it easier to safely expose.
+Components also separate granular implementations from [mixin](#mixins) implementations.
+The API documentation design reflects these groupings.
+See [ERC20Component](/contracts-cairo/2.x/api/erc20#erc20component) as an example which includes:
+
+* **Embeddable Mixin Implementation**
+* **Embeddable Implementations**
+* **Internal Implementations**
+* **Events**
+
+
+
+### Mixins
+
+Mixins are impls made of a combination of smaller, more specific impls.
+While separating components into granular implementations offers flexibility,
+integrating components with many implementations can appear crowded especially if the contract uses all of them.
+Mixins simplify this by allowing contracts to embed groups of implementations with a single directive.
+
+Compare the following code blocks to see the benefit of using a mixin when creating an account contract.
+
+#### Account without mixin
+
+```rust
+component!(path: AccountComponent, storage: account, event: AccountEvent);
+component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+#[abi(embed_v0)]
+impl SRC6Impl = AccountComponent::SRC6Impl;
+#[abi(embed_v0)]
+impl DeclarerImpl = AccountComponent::DeclarerImpl;
+#[abi(embed_v0)]
+impl DeployableImpl = AccountComponent::DeployableImpl;
+#[abi(embed_v0)]
+impl PublicKeyImpl = AccountComponent::PublicKeyImpl;
+#[abi(embed_v0)]
+impl SRC6CamelOnlyImpl = AccountComponent::SRC6CamelOnlyImpl;
+#[abi(embed_v0)]
+impl PublicKeyCamelImpl = AccountComponent::PublicKeyCamelImpl;
+impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+#[abi(embed_v0)]
+impl SRC5Impl = SRC5Component::SRC5Impl;
+```
+
+#### Account with mixin
+
+```rust
+component!(path: AccountComponent, storage: account, event: AccountEvent);
+component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+#[abi(embed_v0)]
+impl AccountMixinImpl = AccountComponent::AccountMixinImpl;
+impl AccountInternalImpl = AccountComponent::InternalImpl;
+```
+
+The rest of the setup for the contract, however, does not change.
+This means that component dependencies must still be included in the `Storage` struct and `Event` enum.
+Here’s a full example of an account contract that embeds the `AccountMixinImpl`:
+
+```rust
+#[starknet::contract]
+mod Account {
+ use openzeppelin_account::AccountComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+
+ component!(path: AccountComponent, storage: account, event: AccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // This embeds all of the methods from the many AccountComponent implementations
+ // and also includes `supports_interface` from `SRC5Impl`
+ #[abi(embed_v0)]
+ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;
+ impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ account: AccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccountEvent: AccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: felt252) {
+ self.account.initializer(public_key);
+ }
+}
+```
+
+### Initializers
+
+
+Failing to use a component’s `initializer` can result in irreparable contract deployments.
+
+Always read the API Reference documentation for each integrated component.
+
+
+
+Some components require some sort of setup upon construction.
+Usually, this would be a job for a constructor; however, components themselves cannot implement constructors.
+Components instead offer ``initializer``s within their `InternalImpl` to call from the contract’s constructor.
+Let’s look at how a contract would integrate [OwnableComponent](/contracts-cairo/2.x/api/access#OwnableComponent):
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::ownable::OwnableComponent;
+ use starknet::ContractAddress;
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+
+ // Instantiate `InternalImpl` to give the contract access to the `initializer`
+ impl InternalImpl = OwnableComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, owner: ContractAddress) {
+ // Invoke ownable's `initializer`
+ self.ownable.initializer(owner);
+ }
+}
+```
+
+### Immutable Config
+
+While initializers help set up the component’s initial state, some require configuration that may be defined
+as constants, saving gas by avoiding the necessity of reading from storage each time the variable needs to be used. The
+Immutable Component Config pattern helps with this matter by allowing the implementing contract to define a set of
+constants declared in the component, customizing its functionality.
+
+
+The Immutable Component Config standard is defined in the SRC-107.
+
+
+Here’s an example of how to use the Immutable Component Config pattern with the [ERC2981Component](/contracts-cairo/2.x/api/token_common#erc2981component):
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::common::erc2981::ERC2981Component;
+ use starknet::contract_address_const;
+
+ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ // Instantiate `InternalImpl` to give the contract access to the `initializer`
+ impl InternalImpl = ERC2981Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc2981: ERC2981Component::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC2981Event: ERC2981Component::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ // Define the immutable config
+ pub impl ERC2981ImmutableConfig of ERC2981Component::ImmutableConfig {
+ const FEE_DENOMINATOR: u128 = 10_000;
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ let default_receiver = contract_address_const::<'RECEIVER'>();
+ let default_royalty_fraction = 1000;
+ // Invoke erc2981's `initializer`
+ self.erc2981.initializer(default_receiver, default_royalty_fraction);
+ }
+}
+```
+
+#### Default config
+
+Sometimes, components implementing the Immutable Component Config pattern provide a default configuration that can be
+directly used without implementing the `ImmutableConfig` trait locally. When provided, this implementation will be named
+`DefaultConfig` and will be available in the same module containing the component, as a sibling.
+
+In the following example, the `DefaultConfig` trait is used to define the `FEE_DENOMINATOR` config constant.
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_introspection::src5::SRC5Component;
+ // Bring the DefaultConfig trait into scope
+ use openzeppelin_token::common::erc2981::{ERC2981Component, DefaultConfig};
+ use starknet::contract_address_const;
+
+ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ // Instantiate `InternalImpl` to give the contract access to the `initializer`
+ impl InternalImpl = ERC2981Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ (...)
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ (...)
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ let default_receiver = contract_address_const::<'RECEIVER'>();
+ let default_royalty_fraction = 1000;
+ // Invoke erc2981's `initializer`
+ self.erc2981.initializer(default_receiver, default_royalty_fraction);
+ }
+}
+```
+
+#### `validate` function
+
+The `ImmutableConfig` trait may also include a `validate` function with a default implementation, which
+asserts that the configuration is correct, and must not be overridden by the implementing contract. For more information
+on how to use this function, refer to the [validate section of the SRC-107](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-107.md#validate-function).
+
+### Dependencies
+
+Some components include dependencies of other components.
+Contracts that integrate components with dependencies must also include the component dependency.
+For instance, [AccessControlComponent](/contracts-cairo/2.x/api/access#accesscontrolcomponent) depends on [SRC5Component](/contracts-cairo/2.x/api/introspection#src5component).
+Creating a contract with `AccessControlComponent` should look like this:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_access::accesscontrol::AccessControlComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+
+ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // AccessControl
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ #[abi(embed_v0)]
+ impl AccessControlCamelImpl =
+ AccessControlComponent::AccessControlCamelImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ accesscontrol: AccessControlComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ (...)
+}
+```
+
+## Customization
+
+
+Customizing implementations and accessing component storage can potentially corrupt the state, bypass security checks, and undermine the component logic.
+
+**Exercise extreme caution**. See [Security](#security).
+
+
+
+### Hooks
+
+Hooks are entrypoints to the business logic of a token component that are accessible at the contract level.
+This allows contracts to insert additional behaviors before and/or after token transfers (including mints and burns).
+Prior to hooks, extending functionality required contracts to create [custom implementations](#custom-implementations).
+
+All token components include a generic hooks trait that include empty default functions.
+When creating a token contract, the using contract must create an implementation of the hooks trait.
+Suppose an ERC20 contract wanted to include Pausable functionality on token transfers.
+The following snippet leverages the `before_update` hook to include this behavior.
+
+```rust
+#[starknet::contract]
+mod MyToken {
+ use openzeppelin_security::pausable::PausableComponent::InternalTrait;
+ use openzeppelin_security::pausable::PausableComponent;
+ use openzeppelin_token::erc20::{ERC20Component, DefaultConfig};
+ use starknet::ContractAddress;
+
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+ component!(path: PausableComponent, storage: pausable, event: PausableEvent);
+
+ // ERC20 Mixin
+ #[abi(embed_v0)]
+ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl PausableImpl = PausableComponent::PausableImpl;
+ impl PausableInternalImpl = PausableComponent::InternalImpl;
+
+ // Create the hooks implementation
+ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {
+ // Occurs before token transfers
+ fn before_update(
+ ref self: ERC20Component::ComponentState,
+ from: ContractAddress,
+ recipient: ContractAddress,
+ amount: u256
+ ) {
+ // Access local state from component state
+ let contract_state = self.get_contract();
+ // Call function from integrated component
+ contract_state.pausable.assert_not_paused();
+ }
+
+ // Omitting the `after_update` hook because the default behavior
+ // is already implemented in the trait
+ }
+
+ (...)
+}
+```
+
+Notice that the `self` parameter expects a component state type.
+Instead of passing the component state, the using contract’s state can be passed which simplifies the syntax.
+The hook then moves the scope up with the Cairo-generated `get_contract` through the `HasComponent` trait (as illustrated with ERC20Component in this example).
+From here, the hook can access the using contract’s integrated components, storage, and implementations.
+
+Be advised that even if a token contract does not require hooks, the hooks trait must still be implemented.
+The using contract may instantiate an empty impl of the trait;
+however, the Contracts for Cairo library already provides the instantiated impl to abstract this away from contracts.
+The using contract just needs to bring the implementation into scope like this:
+
+```rust
+#[starknet::contract]
+mod MyToken {
+ use openzeppelin_token::erc20::{ERC20Component, DefaultConfig};
+ use openzeppelin_token::erc20::ERC20HooksEmptyImpl;
+
+ (...)
+}
+```
+
+
+For a more in-depth guide on hooks, see [Extending Cairo Contracts with Hooks](https://fleming-andrew.medium.com/extending-cairo-contracts-with-hooks-c3ca21d1d6b8).
+
+
+### Custom implementations
+
+There are instances where a contract requires different or amended behaviors from a component implementation.
+In these scenarios, a contract must create a custom implementation of the interface.
+Let’s break down a pausable ERC20 contract to see what that looks like.
+Here’s the setup:
+
+```rust
+#[starknet::contract]
+mod ERC20Pausable {
+ use openzeppelin_security::pausable::PausableComponent;
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ // Import the ERC20 interfaces to create custom implementations
+ use openzeppelin_token::erc20::interface::{IERC20, IERC20CamelOnly};
+ use starknet::ContractAddress;
+
+ component!(path: PausableComponent, storage: pausable, event: PausableEvent);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ #[abi(embed_v0)]
+ impl PausableImpl = PausableComponent::PausableImpl;
+ impl PausableInternalImpl = PausableComponent::InternalImpl;
+
+ // `ERC20MetadataImpl` can keep the embed directive because the implementation
+ // will not change
+ #[abi(embed_v0)]
+ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;
+ // Do not add the embed directive to these implementations because
+ // these will be customized
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;
+
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ (...)
+}
+```
+
+The first thing to notice is that the contract imports the interfaces of the implementations that will be customized.
+These will be used in the next code example.
+
+Next, the contract includes the [ERC20Component](/contracts-cairo/2.x/api/erc20#erc20component) implementations; however, `ERC20Impl` and `ERC20CamelOnlyImpl` are **not** embedded.
+Instead, we want to expose our custom implementation of an interface.
+The following example shows the pausable logic integrated into the ERC20 implementations:
+
+```rust
+#[starknet::contract]
+mod ERC20Pausable {
+ (...)
+
+ // Custom ERC20 implementation
+ #[abi(embed_v0)]
+ impl CustomERC20Impl of IERC20 {
+ fn transfer(
+ ref self: ContractState, recipient: ContractAddress, amount: u256
+ ) -> bool {
+ // Add the custom logic
+ self.pausable.assert_not_paused();
+ // Add the original implementation method from `IERC20Impl`
+ self.erc20.transfer(recipient, amount)
+ }
+
+ fn total_supply(self: @ContractState) -> u256 {
+ // This method's behavior does not change from the component
+ // implementation, but this method must still be defined.
+ // Simply add the original implementation method from `IERC20Impl`
+ self.erc20.total_supply()
+ }
+
+ (...)
+ }
+
+ // Custom ERC20CamelOnly implementation
+ #[abi(embed_v0)]
+ impl CustomERC20CamelOnlyImpl of IERC20CamelOnly {
+ fn totalSupply(self: @ContractState) -> u256 {
+ self.erc20.total_supply()
+ }
+
+ fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {
+ self.erc20.balance_of(account)
+ }
+
+ fn transferFrom(
+ ref self: ContractState,
+ sender: ContractAddress,
+ recipient: ContractAddress,
+ amount: u256
+ ) -> bool {
+ self.pausable.assert_not_paused();
+ self.erc20.transfer_from(sender, recipient, amount)
+ }
+ }
+}
+```
+
+Notice that in the `CustomERC20Impl`, the `transfer` method integrates `pausable.assert_not_paused` as well as `erc20.transfer` from `PausableImpl` and `ERC20Impl` respectively.
+This is why the contract defined the `ERC20Impl` from the component in the previous example.
+
+Creating a custom implementation of an interface must define **all** methods from that interface.
+This is true even if the behavior of a method does not change from the component implementation (as `total_supply` exemplifies in this example).
+
+### Accessing component storage
+
+There may be cases where the contract must read or write to an integrated component’s storage.
+To do so, use the same syntax as calling an implementation method except replace the name of the method with the storage variable like this:
+
+```rust
+#[starknet::contract]
+mod MyContract {
+ use openzeppelin_security::InitializableComponent;
+
+ component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ initializable: InitializableComponent::Storage
+ }
+
+ (...)
+
+ fn write_to_comp_storage(ref self: ContractState) {
+ self.initializable.Initializable_initialized.write(true);
+ }
+
+ fn read_from_comp_storage(self: @ContractState) -> bool {
+ self.initializable.Initializable_initialized.read()
+ }
+}
+```
+
+## Security
+
+The maintainers of OpenZeppelin Contracts for Cairo are mainly concerned with the correctness and security of the code as published in the library.
+
+Customizing implementations and manipulating the component state may break some important assumptions and introduce vulnerabilities.
+While we try to ensure the components remain secure in the face of a wide range of potential customizations, this is done in a best-effort manner.
+Any and all customizations to the component logic should be carefully reviewed and checked against the source code of the component they are customizing so as to fully understand their impact and guarantee their security.
diff --git a/docs/content/contracts-cairo/2.x/erc1155.mdx b/docs/content/contracts-cairo/2.x/erc1155.mdx
new file mode 100644
index 00000000..d3e05494
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/erc1155.mdx
@@ -0,0 +1,239 @@
+---
+title: ERC1155
+---
+
+The ERC1155 multi-token standard is a specification for [fungibility-agnostic](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) token contracts.
+The ERC1155 library implements an approximation of [EIP-1155](https://eips.ethereum.org/EIPS/eip-1155) in Cairo for StarkNet.
+
+## Multi Token Standard
+
+The distinctive feature of ERC1155 is that it uses a single smart contract to represent multiple tokens at once. This
+is why its [balance_of](/contracts-cairo/2.x/api/erc1155#IERC1155-balance_of) function differs from ERC20’s and ERC777’s: it has an additional ID argument for the
+identifier of the token that you want to query the balance of.
+
+This is similar to how ERC721 does things, but in that standard a token ID has no concept of balance: each token is
+non-fungible and exists or doesn’t. The ERC721 [balance_of](/contracts-cairo/2.x/api/erc721#IERC721-balance_of) function refers to how many different tokens an account
+has, not how many of each. On the other hand, in ERC1155 accounts have a distinct balance for each token ID, and
+non-fungible tokens are implemented by simply minting a single one of them.
+
+This approach leads to massive gas savings for projects that require multiple tokens. Instead of deploying a new
+contract for each token type, a single ERC1155 token contract can hold the entire system state, reducing deployment
+costs and complexity.
+
+## Usage
+
+Using Contracts for Cairo, constructing an ERC1155 contract requires integrating both `ERC1155Component` and `SRC5Component`.
+The contract should also set up the constructor to initialize the token’s URI and interface support.
+Here’s an example of a basic contract:
+
+```rust
+#[starknet::contract]
+mod MyERC1155 {
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};
+ use starknet::ContractAddress;
+
+ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // ERC1155 Mixin
+ #[abi(embed_v0)]
+ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;
+ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc1155: ERC1155Component::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC1155Event: ERC1155Component::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ token_uri: ByteArray,
+ recipient: ContractAddress,
+ token_ids: Span,
+ values: Span
+ ) {
+ self.erc1155.initializer(token_uri);
+ self
+ .erc1155
+ .batch_mint_with_acceptance_check(recipient, token_ids, values, array![].span());
+ }
+}
+```
+
+## Interface
+
+The following interface represents the full ABI of the Contracts for Cairo [ERC1155Component](/contracts-cairo/2.x/api/erc1155#ERC1155Component).
+The interface includes the [IERC1155](/contracts-cairo/2.x/api/erc1155#IERC1155) standard interface and the optional [IERC1155MetadataURI](/contracts-cairo/2.x/api/erc1155#IERC1155MetadataURI) interface together with [ISRC5](/contracts-cairo/2.x/api/introspection#ISRC5).
+
+To support older token deployments, as mentioned in [Dual interfaces](./guides/interfaces-and-dispatchers#dual-interfaces), the component also includes implementations of the interface written in camelCase.
+
+```rust
+#[starknet::interface]
+pub trait ERC1155ABI {
+ // IERC1155
+ fn balance_of(account: ContractAddress, token_id: u256) -> u256;
+ fn balance_of_batch(
+ accounts: Span, token_ids: Span
+ ) -> Span;
+ fn safe_transfer_from(
+ from: ContractAddress,
+ to: ContractAddress,
+ token_id: u256,
+ value: u256,
+ data: Span
+ );
+ fn safe_batch_transfer_from(
+ from: ContractAddress,
+ to: ContractAddress,
+ token_ids: Span,
+ values: Span,
+ data: Span
+ );
+ fn is_approved_for_all(
+ owner: ContractAddress, operator: ContractAddress
+ ) -> bool;
+ fn set_approval_for_all(operator: ContractAddress, approved: bool);
+
+ // IERC1155MetadataURI
+ fn uri(token_id: u256) -> ByteArray;
+
+ // ISRC5
+ fn supports_interface(interface_id: felt252) -> bool;
+
+ // IERC1155Camel
+ fn balanceOf(account: ContractAddress, tokenId: u256) -> u256;
+ fn balanceOfBatch(
+ accounts: Span, tokenIds: Span
+ ) -> Span;
+ fn safeTransferFrom(
+ from: ContractAddress,
+ to: ContractAddress,
+ tokenId: u256,
+ value: u256,
+ data: Span
+ );
+ fn safeBatchTransferFrom(
+ from: ContractAddress,
+ to: ContractAddress,
+ tokenIds: Span,
+ values: Span,
+ data: Span
+ );
+ fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool;
+ fn setApprovalForAll(operator: ContractAddress, approved: bool);
+}
+```
+
+## ERC1155 Compatibility
+
+Although Starknet is not EVM compatible, this implementation aims to be as close as possible to the ERC1155 standard but some differences can still be found, such as:
+
+* The optional `data` argument in both `safe_transfer_from` and `safe_batch_transfer_from` is implemented as `Span`.
+* `IERC1155Receiver` compliant contracts must implement SRC5 and register the `IERC1155Receiver` interface ID.
+* `IERC1155Receiver::on_erc1155_received` must return that interface ID on success.
+
+## Batch operations
+
+Because all state is held in a single contract, it is possible to operate over multiple tokens in a single transaction very efficiently. The standard provides two functions, [balance_of_batch](/contracts-cairo/2.x/api/erc1155#IERC1155-balance_of_batch) and [safe_batch_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_batch_transfer_from), that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive. We also have [safe_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_transfer_from) for non-batch operations.
+
+In the spirit of the standard, we’ve also included batch operations in the non-standard functions, such as
+[batch_mint_with_acceptance_check](/contracts-cairo/2.x/api/erc1155#ERC1155Component-batch_mint_with_acceptance_check).
+
+
+While [safe_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_transfer_from) and [safe_batch_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_batch_transfer_from) prevent loss by checking the receiver can handle the
+tokens, this yields execution to the receiver which can result in a [reentrant call](./security#reentrancy-guard).
+
+
+## Receiving tokens
+
+In order to be sure a non-account contract can safely accept ERC1155 tokens, the contract must implement the `IERC1155Receiver` interface.
+The recipient contract must also implement the [SRC5](./introspection#src5) interface which supports interface introspection.
+
+### IERC1155Receiver
+
+```rust
+#[starknet::interface]
+pub trait IERC1155Receiver {
+ fn on_erc1155_received(
+ operator: ContractAddress,
+ from: ContractAddress,
+ token_id: u256,
+ value: u256,
+ data: Span
+ ) -> felt252;
+ fn on_erc1155_batch_received(
+ operator: ContractAddress,
+ from: ContractAddress,
+ token_ids: Span,
+ values: Span,
+ data: Span
+ ) -> felt252;
+}
+```
+
+Implementing the `IERC1155Receiver` interface exposes the [on_erc1155_received](/contracts-cairo/2.x/api/erc1155#IERC1155Receiver-on_erc1155_received) and [on_erc1155_batch_received](/contracts-cairo/2.x/api/erc1155#IERC1155Receiver-on_erc1155_batch_received) methods.
+When [safe_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_transfer_from) and [safe_batch_transfer_from](/contracts-cairo/2.x/api/erc1155#IERC1155-safe_batch_transfer_from) are called, they invoke the recipient contract’s `on_erc1155_received` or `on_erc1155_batch_received` methods respectively which **must** return the [IERC1155Receiver interface ID](/contracts-cairo/2.x/api/erc1155#IERC1155Receiver).
+Otherwise, the transaction will fail.
+
+
+For information on how to calculate interface IDs, see [Computing the interface ID](./introspection#computing-the-interface-id).
+
+
+### Creating a token receiver contract
+
+The Contracts for Cairo ERC1155ReceiverComponent already returns the correct interface ID for safe token transfers.
+To integrate the `IERC1155Receiver` interface into a contract, simply include the ABI embed directive to the implementations and add the `initializer` in the contract’s constructor.
+Here’s an example of a simple token receiver contract:
+
+```rust
+#[starknet::contract]
+mod MyTokenReceiver {
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc1155::ERC1155ReceiverComponent;
+ use starknet::ContractAddress;
+
+ component!(path: ERC1155ReceiverComponent, storage: erc1155_receiver, event: ERC1155ReceiverEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // ERC1155Receiver Mixin
+ #[abi(embed_v0)]
+ impl ERC1155ReceiverMixinImpl = ERC1155ReceiverComponent::ERC1155ReceiverMixinImpl;
+ impl ERC1155ReceiverInternalImpl = ERC1155ReceiverComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc1155_receiver: ERC1155ReceiverComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC1155ReceiverEvent: ERC1155ReceiverComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ self.erc1155_receiver.initializer();
+ }
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/erc20.mdx b/docs/content/contracts-cairo/2.x/erc20.mdx
new file mode 100644
index 00000000..601d4902
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/erc20.mdx
@@ -0,0 +1,252 @@
+---
+title: ERC20
+---
+
+The ERC20 token standard is a specification for [fungible tokens](https://docs.openzeppelin.com/contracts/4.x/tokens#different-kinds-of-tokens), a type of token where all the units are exactly equal to each other.
+`token::erc20::ERC20Component` provides an approximation of [EIP-20](https://eips.ethereum.org/EIPS/eip-20) in Cairo for Starknet.
+
+
+Prior to [Contracts v0.7.0](https://github.com/OpenZeppelin/cairo-contracts/releases/tag/v0.7.0), ERC20 contracts store and read `decimals` from storage; however, this implementation returns a static `18`.
+If upgrading an older ERC20 contract that has a decimals value other than `18`, the upgraded contract **must** use a custom `decimals` implementation.
+See the [Customizing decimals](#customizing-decimals) guide.
+
+
+## Usage
+
+Using Contracts for Cairo, constructing an ERC20 contract requires setting up the constructor and instantiating the token implementation.
+Here’s what that looks like:
+
+```rust
+#[starknet::contract]
+mod MyToken {
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ use starknet::ContractAddress;
+
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ // ERC20 Mixin
+ #[abi(embed_v0)]
+ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc20: ERC20Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC20Event: ERC20Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ initial_supply: u256,
+ recipient: ContractAddress
+ ) {
+ let name = "MyToken";
+ let symbol = "MTK";
+
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+ }
+}
+```
+
+`MyToken` integrates both the `ERC20Impl` and `ERC20MetadataImpl` with the embed directive which marks the implementations as external in the contract.
+While the `ERC20MetadataImpl` is optional, it’s generally recommended to include it because the vast majority of ERC20 tokens provide the metadata methods.
+The above example also includes the `ERC20InternalImpl` instance.
+This allows the contract’s constructor to initialize the contract and create an initial supply of tokens.
+
+
+For a more complete guide on ERC20 token mechanisms, see [Creating ERC20 Supply](./guides/erc20-supply).
+
+
+## Interface
+
+The following interface represents the full ABI of the Contracts for Cairo [ERC20Component](/contracts-cairo/2.x/api/erc20#ERC20Component).
+The interface includes the [IERC20](/contracts-cairo/2.x/api/erc20#IERC20) standard interface as well as the optional [IERC20Metadata](/contracts-cairo/2.x/api/erc20#IERC20Metadata).
+
+To support older token deployments, as mentioned in [Dual interfaces](./guides/interfaces-and-dispatchers#dual-interfaces), the component also includes an implementation of the interface written in camelCase.
+
+```rust
+#[starknet::interface]
+pub trait ERC20ABI {
+ // IERC20
+ fn total_supply() -> u256;
+ fn balance_of(account: ContractAddress) -> u256;
+ fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;
+ fn transfer(recipient: ContractAddress, amount: u256) -> bool;
+ fn transfer_from(
+ sender: ContractAddress, recipient: ContractAddress, amount: u256
+ ) -> bool;
+ fn approve(spender: ContractAddress, amount: u256) -> bool;
+
+ // IERC20Metadata
+ fn name() -> ByteArray;
+ fn symbol() -> ByteArray;
+ fn decimals() -> u8;
+
+ // IERC20Camel
+ fn totalSupply() -> u256;
+ fn balanceOf(account: ContractAddress) -> u256;
+ fn transferFrom(
+ sender: ContractAddress, recipient: ContractAddress, amount: u256
+ ) -> bool;
+}
+```
+
+## ERC20 compatibility
+
+Although Starknet is not EVM compatible, this component aims to be as close as possible to the ERC20 token standard.
+Some notable differences, however, can still be found, such as:
+
+* The `ByteArray` type is used to represent strings in Cairo.
+* The component offers a [dual interface](./guides/interfaces-and-dispatchers#dual-interfaces) which supports both snake_case and camelCase methods, as opposed to just camelCase in Solidity.
+* `transfer`, `transfer_from` and `approve` will never return anything different from `true` because they will revert on any error.
+* Function selectors are calculated differently between [Cairo](https://github.com/starkware-libs/cairo/blob/7dd34f6c57b7baf5cd5a30c15e00af39cb26f7e1/crates/cairo-lang-starknet/src/contract.rs#L39-L48) and [Solidity](https://solidity-by-example.org/function-selector/).
+
+## Customizing decimals
+
+Cairo, like Solidity, does not support [floating-point numbers](https://en.wikipedia.org//wiki/Floating-point_arithmetic).
+To get around this limitation, ERC20 token contracts may offer a `decimals` field which communicates to outside interfaces (wallets, exchanges, etc.) how the token should be displayed.
+For instance, suppose a token had a `decimals` value of `3` and the total token supply was `1234`.
+An outside interface would display the token supply as `1.234`.
+In the actual contract, however, the supply would still be the integer `1234`.
+In other words, **the decimals field in no way changes the actual arithmetic** because all operations are still performed on integers.
+
+Most contracts use `18` decimals and this was even proposed to be compulsory (see the [EIP discussion](https://github.com/ethereum/EIPs/issues/724)).
+
+### The static approach (SRC-107)
+
+The Contracts for Cairo `ERC20` component leverages SRC-107 to allow for a static and configurable number of decimals.
+To use the default `18` decimals, you can use the `DefaultConfig` implementation by just importing it:
+
+```rust
+#[starknet::contract]
+mod MyToken {
+ // Importing the DefaultConfig implementation would make decimals 18 by default.
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl, DefaultConfig};
+ use starknet::ContractAddress;
+
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ (...)
+}
+```
+
+To customize this value, you can implement the ImmutableConfig trait locally in the contract.
+The following example shows how to set the decimals to `6`:
+
+```rust
+mod MyToken {
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl};
+ use starknet::ContractAddress;
+
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ (...)
+
+ // Custom implementation of the ERC20Component ImmutableConfig.
+ impl ERC20ImmutableConfig of ERC20Component::ImmutableConfig {
+ const DECIMALS: u8 = 6;
+ }
+}
+```
+
+### The storage approach
+
+For more complex scenarios, such as a factory deploying multiple tokens with differing values for decimals, a flexible solution might be appropriate.
+
+
+Note that we are not using the MixinImpl or the DefaultConfig in this case, since we need to customize the IERC20Metadata implementation.
+
+
+```rust
+#[starknet::contract]
+mod MyToken {
+ use openzeppelin_token::erc20::interface as interface;
+ use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl};
+ use starknet::ContractAddress;
+
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc20: ERC20Component::Storage,
+ // The decimals value is stored locally
+ decimals: u8,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC20Event: ERC20Component::Event,
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState, decimals: u8, initial_supply: u256, recipient: ContractAddress,
+ ) {
+ // Call the internal function that writes decimals to storage
+ self._set_decimals(decimals);
+
+ // Initialize ERC20
+ let name = "MyToken";
+ let symbol = "MTK";
+
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+ }
+
+ #[abi(embed_v0)]
+ impl ERC20CustomMetadataImpl of interface::IERC20Metadata {
+ fn name(self: @ContractState) -> ByteArray {
+ self.erc20.ERC20_name.read()
+ }
+
+ fn symbol(self: @ContractState) -> ByteArray {
+ self.erc20.ERC20_symbol.read()
+ }
+
+ fn decimals(self: @ContractState) -> u8 {
+ self.decimals.read()
+ }
+ }
+
+ #[generate_trait]
+ impl InternalImpl of InternalTrait {
+ fn _set_decimals(ref self: ContractState, decimals: u8) {
+ self.decimals.write(decimals);
+ }
+ }
+}
+```
+
+This contract expects a `decimals` argument in the constructor and uses an internal function to write the decimals to storage.
+Note that the `decimals` state variable must be defined in the contract’s storage because this variable does not exist in the component offered by OpenZeppelin Contracts for Cairo.
+It’s important to include a custom ERC20 metadata implementation and NOT use the Contracts for Cairo `ERC20MetadataImpl` in this specific case since the `decimals` method will always return `18`.
diff --git a/docs/content/contracts-cairo/2.x/erc4626.mdx b/docs/content/contracts-cairo/2.x/erc4626.mdx
new file mode 100644
index 00000000..e22f162e
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/erc4626.mdx
@@ -0,0 +1,433 @@
+---
+title: ERC4626
+---
+
+[ERC4626](https://eips.ethereum.org/EIPS/eip-4626) is an extension of [ERC20](./erc20) that proposes a standard interface for token vaults.
+This standard interface can be used by widely different contracts (including lending markets, aggregators, and intrinsically interest bearing tokens),
+which brings a number of subtleties. Navigating these potential issues is essential to implementing a compliant and composable token vault.
+
+We provide a base component of ERC4626 which is designed to allow developers to easily re-configure the vault’s behavior, using traits and hooks, while
+staying compliant. In this guide, we will discuss some security considerations that affect ERC4626. We will also discuss common customizations of the vault.
+
+## Security concern: Inflation attack
+
+### Visualizing the vault
+
+In exchange for the assets deposited into an ERC4626 vault, a user receives shares. These shares can later be burned to redeem the corresponding underlying assets.
+The number of shares a user gets depends on the amount of assets they put in and on the exchange rate of the vault. This exchange rate is defined by the
+current liquidity held by the vault.
+
+* If a vault has 100 tokens to back 200 shares, then each share is worth 0.5 assets.
+* If a vault has 200 tokens to back 100 shares, then each share is worth 2.0 assets.
+
+In other words, the exchange rate can be defined as the slope of the line that passes through the origin and the current number of assets and shares in the vault.
+Deposits and withdrawals move the vault in this line.
+
+
+
+When plotted in log-log scale, the rate is defined similarly, but appears differently (because the point (0,0) is infinitely far away). Rates are represented by "diagonal" lines with different offsets.
+
+
+
+In such a representation, widely different rates can be clearly visible in the same graph. This wouldn’t be the case in linear scale.
+
+
+
+### The attack
+
+When depositing tokens, the number of shares a user gets is rounded towards zero. This rounding takes away value from the user in favor of
+the vault (i.e. in favor of all the current shareholders). This rounding is often negligible because of the amount at stake. If you deposit 1e9 shares
+worth of tokens, the rounding will have you lose at most 0.0000001% of your deposit. However if you deposit 10 shares worth of tokens, you could
+lose 10% of your deposit. Even worse, if you deposit less than 1 share worth of tokens, you will receive 0 shares, effectively making a donation.
+
+For a given amount of assets, the more shares you receive the safer you are. If you want to limit your losses to at most 1%, you need to receive at least 100 shares.
+
+
+
+In the figure we can see that for a given deposit of 500 assets, the number of shares we get and the corresponding rounding losses depend on the exchange rate.
+If the exchange rate is that of the orange curve, we are getting less than a share, so we lose 100% of our deposit. However, if the exchange rate
+is that of the green curve, we get 5000 shares, which limits our rounding losses to at most 0.02%.
+
+
+
+Symmetrically, if we focus on limiting our losses to a maximum of 0.5%, we need to get at least 200 shares. With the green exchange rate that requires
+just 20 tokens, but with the orange rate that requires 200000 tokens.
+
+We can clearly see that the blue and green curves correspond to vaults that are safer than the yellow and orange curves.
+
+The idea of an inflation attack is that an attacker can donate assets to the vault to move the rate curve to the right, and make the vault unsafe.
+
+
+
+Figure 6 shows how an attacker can manipulate the rate of an empty vault. First the attacker must deposit a small amount of tokens (1 token) and follow up with
+a donation of 1e5 tokens directly to the vault to move the exchange rate "right". This puts the vault in a state where any deposit smaller than 1e5 would be
+completely lost to the vault. Given that the attacker is the only shareholder (from their donation), the attacker would steal all the tokens deposited.
+
+An attacker would typically wait for a user to do the first deposit into the vault, and would frontrun that operation with the attack described above. The risk is
+low, and the size of the "donation" required to manipulate the vault is equivalent to the size of the deposit that is being attacked.
+
+In math that gives:
+
+* $a_0$ the attacker deposit
+* $a_1$ the attacker donation
+* $u$ the user deposit
+
+| | Assets | Shares | Rate |
+| --- | --- | --- | --- |
+| initial | $0$ | $0$ | - |
+| after attacker's deposit | $a_0$ | $a_0$ | $1$ |
+| after attacker's donation | $a_0 + a_1$ | $a_0$ | $\frac{a_0}{a_1 + a_0}$ |
+
+This means a deposit of $u$ will give this number of shares:
+
+```math
+\frac{u \times a_0}{a_0 + a_1}
+```
+
+For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that
+
+```math
+\frac{u \times a_0}{a_0+a_1} < 1 \iff u < 1 + \frac{a_1}{a_0}
+```
+
+Using $a_0 = 1$ and $a_1 = u$ is enough. So the attacker only needs $u+1$ assets to perform a successful attack.
+
+It is easy to generalize the above results to scenarios where the attacker is going after a smaller fraction of the user’s deposit. In order to target $\frac{u}{n}$, the user needs to suffer rounding of a similar fraction, which means the user must receive at most $n$ shares. This results in:
+
+```math
+\frac{u \times a_0}{a_0+a_1} < n \iff \frac{u}{n} < 1 + \frac{a_1}{a_0}
+```
+
+In this scenario, the attack is $n$ times less powerful (in how much it is stealing) and costs $n$ times less to execute. In both cases, the amount of funds the attacker needs to commit is equivalent to its potential earnings.
+
+### Defending with a virtual offset
+
+The defense we propose is based on the approach used in [YieldBox](https://github.com/boringcrypto/YieldBox). It consists of two parts:
+
+* Use an offset between the "precision" of the representation of shares and assets. Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets.
+* Include virtual shares and virtual assets in the exchange rate computation. These virtual assets enforce the conversion rate when the vault is empty.
+
+These two parts work together in enforcing the security of the vault. First, the increased precision corresponds to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable to perform an attack.
+
+Following the previous math definitions, we have:
+
+* $\delta$ the vault offset
+* $a_0$ the attacker deposit
+* $a_1$ the attacker donation
+* $u$ the user deposit
+
+| | Assets | Shares | Rate |
+| --- | --- | --- | --- |
+| initial | $1$ | $10^\delta$ | $10^\delta$ |
+| after attacker's deposit | $1+a_0$ | $10^\delta \times (1+a_0)$ | $10^\delta$ |
+| after attacker's donation | $1+a_0+a_1$ | $10^\delta \times (1+a_0)$ | $10^\delta$ |
+
+One important thing to note is that the attacker only owns a fraction $\frac{a_0}{1 + a_0}$ of the shares, so when doing the donation, he will only be able
+to recover that fraction $\frac{a_1 * a_0}{1 + a_0}$ of the donation. The remaining $\frac{a_1}{1+a_0}$ are captured by the vault.
+
+```math
+\mathit{loss} = \frac{a_1}{1+a_0}
+```
+
+When the user deposits $u$, he receives
+
+```math
+10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1}
+```
+
+For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that
+
+```math
+10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} < 1
+```
+
+```math
+\iff 10^\delta \times u < \frac{1+a_0+a_1}{1+a_0}
+```
+
+```math
+\iff 10^\delta \times u < 1 + \frac{a_1}{1+a_0}
+```
+
+```math
+\iff 10^\delta \times u \le \mathit{loss}
+```
+
+* If the offset is 0, the attacker loss is at least equal to the user’s deposit.
+* If the offset is greater than 0, the attacker will have to suffer losses that are orders of magnitude bigger than the amount of value that can hypothetically be stolen from the user.
+
+This shows that even with an offset of 0, the virtual shares and assets make this attack non profitable for the attacker. Bigger offsets increase the security even further by making any attack on the user extremely wasteful.
+
+The following figure shows how the offset impacts the initial rate and limits the ability of an attacker with limited funds to inflate it effectively.
+
+
+$\delta = 3$, $a_0 = 1$, $a_1 = 10^5$
+
+
+$\delta = 3$, $a_0 = 100$, $a_1 = 10^5$
+
+
+$\delta = 6$, $a_0 = 1$, $a_1 = 10^5$
+
+## Usage
+
+### Custom behavior: Adding fees to the vault
+
+In ERC4626 vaults, fees can be captured during deposit/mint and/or withdraw/redeem operations. It is essential to remain
+compliant with the ERC4626 requirements regarding the preview functions. Fees are calculated through the [FeeConfigTrait](/contracts-cairo/2.x/api/erc20#ERC4626Component-FeeConfigTrait)
+implementation. By default, the ERC4626 component charges no fees. If this is the desired behavior, you can use the default
+[ERC4626DefaultNoFees](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/token/src/erc20/extensions/erc4626/erc4626.cairo#L899) implementation.
+
+
+Starting from v3.0.0, fees can be charged in either assets or shares. Prior versions only supported fees taken in assets.
+See the updated [FeeConfigTrait](/contracts-cairo/2.x/api/erc20#ERC4626Component-FeeConfigTrait) and implementation examples in [ERC4626 mocks](https://github.com/OpenZeppelin/cairo-contracts/tree/main/packages/test_common/src/mocks/erc4626.cairo).
+
+
+For example, if calling `deposit(100, receiver)`, the caller should deposit exactly 100 underlying tokens, including fees, and the receiver should receive a number of shares that matches the value returned by `preview_deposit(100)`.
+Similarly, `preview_mint` should account for the fees that the user will have to pay on top of share’s cost.
+
+As for the `Deposit` event, while this is less clear in the EIP spec itself,
+there seems to be consensus that it should include the number of assets paid for by the user, including the fees.
+
+On the other hand, when withdrawing assets, the number given by the user should correspond to what the user receives.
+Any fees should be added to the quote (in shares) performed by `preview_withdraw`.
+
+The `Withdraw` event should include the number of shares the user burns (including fees) and the number of assets the user actually receives (after fees are deducted).
+
+The consequence of this design is that both the `Deposit` and `Withdraw` events will describe two exchange rates.
+The spread between the "Buy-in" and the "Exit" prices correspond to the fees taken by the vault.
+
+The following example describes how fees taken in assets on deposits/withdrawals and in shares on mints/redemptions
+proportional to the deposited/withdrawn amount can be implemented:
+
+```rust
+#[starknet::contract]
+#[with_components(./erc20, ERC4626)]
+pub mod ERC4626Fees {
+ use openzeppelin_token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
+ use openzeppelin_token::erc20::extensions::erc4626::ERC4626Component::{Fee, FeeConfigTrait};
+ use openzeppelin_token::erc20::extensions::erc4626::{
+ DefaultConfig, ERC4626DefaultNoLimits, ERC4626SelfAssetsManagement,
+ };
+ use openzeppelin_token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20HooksEmptyImpl};
+ use openzeppelin_utils::math;
+ use openzeppelin_utils::math::Rounding;
+ use starknet::ContractAddress;
+ use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
+
+ const _BASIS_POINT_SCALE: u256 = 10_000;
+ const FEE_TRANSFER_FAILED: felt252 = 0x1;
+
+ // ERC4626
+ #[abi(embed_v0)]
+ impl ERC4626ComponentImpl = ERC4626Component::ERC4626Impl;
+ // ERC4626MetadataImpl is a custom impl of IERC20Metadata
+ #[abi(embed_v0)]
+ impl ERC4626MetadataImpl = ERC4626Component::ERC4626MetadataImpl;
+
+ // ERC20
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;
+
+ #[storage]
+ pub struct Storage {
+ pub entry_fee_basis_point_value: u256,
+ pub entry_fee_recipient: ContractAddress,
+ pub exit_fee_basis_point_value: u256,
+ pub exit_fee_recipient: ContractAddress,
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ name: ByteArray,
+ symbol: ByteArray,
+ underlying_asset: ContractAddress,
+ initial_supply: u256,
+ recipient: ContractAddress,
+ entry_fee: u256,
+ entry_treasury: ContractAddress,
+ exit_fee: u256,
+ exit_treasury: ContractAddress,
+ ) {
+ self.erc20.initializer(name, symbol);
+ self.erc20.mint(recipient, initial_supply);
+ self.erc4626.initializer(underlying_asset);
+
+ self.entry_fee_basis_point_value.write(entry_fee);
+ self.entry_fee_recipient.write(entry_treasury);
+ self.exit_fee_basis_point_value.write(exit_fee);
+ self.exit_fee_recipient.write(exit_treasury);
+ }
+
+ /// Hooks
+ impl ERC4626HooksImpl of ERC4626Component::ERC4626HooksTrait {
+ fn after_deposit(
+ ref self: ERC4626Component::ComponentState,
+ caller: ContractAddress,
+ receiver: ContractAddress,
+ assets: u256,
+ shares: u256,
+ fee: Option,
+ ) {
+ if let Option::Some(fee) = fee {
+ let mut contract_state = self.get_contract_mut();
+ let fee_recipient = contract_state.entry_fee_recipient.read();
+ match fee {
+ Fee::Assets(fee) => {
+ let asset_address = contract_state.asset();
+ let asset_dispatcher = IERC20Dispatcher { contract_address: asset_address };
+ assert(
+ asset_dispatcher.transfer(fee_recipient, fee), FEE_TRANSFER_FAILED,
+ );
+ },
+ Fee::Shares(fee) => contract_state.erc20.mint(fee_recipient, fee),
+ };
+ }
+ }
+
+ fn before_withdraw(
+ ref self: ERC4626Component::ComponentState,
+ caller: ContractAddress,
+ receiver: ContractAddress,
+ owner: ContractAddress,
+ assets: u256,
+ shares: u256,
+ fee: Option,
+ ) {
+ if let Option::Some(fee) = fee {
+ let mut contract_state = self.get_contract_mut();
+ let fee_recipient = contract_state.exit_fee_recipient.read();
+ match fee {
+ Fee::Assets(fee) => {
+ let asset_address = contract_state.asset();
+ let asset_dispatcher = IERC20Dispatcher { contract_address: asset_address };
+ assert(
+ asset_dispatcher.transfer(fee_recipient, fee), FEE_TRANSFER_FAILED,
+ );
+ },
+ Fee::Shares(fee) => {
+ if caller != owner {
+ contract_state.erc20._spend_allowance(owner, caller, fee);
+ }
+ contract_state.erc20._transfer(owner, fee_recipient, fee);
+ },
+ };
+ }
+ }
+ }
+
+ /// Calculate fees
+ impl FeeConfigImpl of FeeConfigTrait {
+ fn calculate_deposit_fee(
+ self: @ERC4626Component::ComponentState, assets: u256, shares: u256,
+ ) -> Option {
+ let contract_state = self.get_contract();
+ let fee = fee_on_total(assets, contract_state.entry_fee_basis_point_value.read());
+ Option::Some(Fee::Assets(fee))
+ }
+
+ fn calculate_mint_fee(
+ self: @ERC4626Component::ComponentState, assets: u256, shares: u256,
+ ) -> Option {
+ let contract_state = self.get_contract();
+ let fee = fee_on_raw(shares, contract_state.entry_fee_basis_point_value.read());
+ Option::Some(Fee::Shares(fee))
+ }
+
+ fn calculate_withdraw_fee(
+ self: @ERC4626Component::ComponentState, assets: u256, shares: u256,
+ ) -> Option {
+ let contract_state = self.get_contract();
+ let fee = fee_on_raw(assets, contract_state.exit_fee_basis_point_value.read());
+ Option::Some(Fee::Assets(fee))
+ }
+
+ fn calculate_redeem_fee(
+ self: @ERC4626Component::ComponentState, assets: u256, shares: u256,
+ ) -> Option {
+ let contract_state = self.get_contract();
+ let fee = fee_on_total(shares, contract_state.exit_fee_basis_point_value.read());
+ Option::Some(Fee::Shares(fee))
+ }
+ }
+
+ /// Calculates the fees that should be added to an amount `assets` that does not already
+ /// include fees.
+ /// Used in IERC4626::mint and IERC4626::withdraw operations.
+ fn fee_on_raw(
+ assets: u256,
+ fee_basis_points: u256,
+ ) -> u256 {
+ math::u256_mul_div(assets, fee_basis_points, _BASIS_POINT_SCALE, Rounding::Ceil)
+ }
+
+ /// Calculates the fee part of an amount `assets` that already includes fees.
+ /// Used in IERC4626::deposit and IERC4626::redeem operations.
+ fn fee_on_total(
+ assets: u256,
+ fee_basis_points: u256,
+ ) -> u256 {
+ math::u256_mul_div(
+ assets, fee_basis_points, fee_basis_points + _BASIS_POINT_SCALE, Rounding::Ceil,
+ )
+ }
+}
+```
+
+## Interface
+
+The following interface represents the full ABI of the Contracts for Cairo [ERC4626Component](/contracts-cairo/2.x/api/erc20#ERC4626Component).
+The full interface includes the [IERC4626](/contracts-cairo/2.x/api/erc20#IERC4626), [IERC20](/contracts-cairo/2.x/api/erc20#IERC20), and [IERC20Metadata](/contracts-cairo/2.x/api/erc20#IERC20Metadata) interfaces.
+Note that implementing the IERC20Metadata interface is a requirement of IERC4626.
+
+```rust
+#[starknet::interface]
+pub trait ERC4626ABI {
+ // IERC4626
+ fn asset() -> ContractAddress;
+ fn total_assets() -> u256;
+ fn convert_to_shares(assets: u256) -> u256;
+ fn convert_to_assets(shares: u256) -> u256;
+ fn max_deposit(receiver: ContractAddress) -> u256;
+ fn preview_deposit(assets: u256) -> u256;
+ fn deposit(assets: u256, receiver: ContractAddress) -> u256;
+ fn max_mint(receiver: ContractAddress) -> u256;
+ fn preview_mint(shares: u256) -> u256;
+ fn mint(shares: u256, receiver: ContractAddress) -> u256;
+ fn max_withdraw(owner: ContractAddress) -> u256;
+ fn preview_withdraw(assets: u256) -> u256;
+ fn withdraw(
+ assets: u256, receiver: ContractAddress, owner: ContractAddress,
+ ) -> u256;
+ fn max_redeem(owner: ContractAddress) -> u256;
+ fn preview_redeem(shares: u256) -> u256;
+ fn redeem(
+ shares: u256, receiver: ContractAddress, owner: ContractAddress,
+ ) -> u256;
+
+ // IERC20
+ fn total_supply() -> u256;
+ fn balance_of(account: ContractAddress) -> u256;
+ fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;
+ fn transfer(recipient: ContractAddress, amount: u256) -> bool;
+ fn transfer_from(
+ sender: ContractAddress, recipient: ContractAddress, amount: u256,
+ ) -> bool;
+ fn approve(spender: ContractAddress, amount: u256) -> bool;
+
+ // IERC20Metadata
+ fn name() -> ByteArray;
+ fn symbol() -> ByteArray;
+ fn decimals() -> u8;
+
+ // IERC20CamelOnly
+ fn totalSupply() -> u256;
+ fn balanceOf(account: ContractAddress) -> u256;
+ fn transferFrom(
+ sender: ContractAddress, recipient: ContractAddress, amount: u256,
+ ) -> bool;
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/erc721.mdx b/docs/content/contracts-cairo/2.x/erc721.mdx
new file mode 100644
index 00000000..cee0e614
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/erc721.mdx
@@ -0,0 +1,213 @@
+---
+title: ERC721
+---
+
+The ERC721 token standard is a specification for [non-fungible tokens](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens), or more colloquially: NFTs.
+`token::erc721::ERC721Component` provides an approximation of [EIP-721](https://eips.ethereum.org/EIPS/eip-721) in Cairo for Starknet.
+
+## Usage
+
+Using Contracts for Cairo, constructing an ERC721 contract requires integrating both `ERC721Component` and `SRC5Component`.
+The contract should also set up the constructor to initialize the token’s name, symbol, and interface support.
+Here’s an example of a basic contract:
+
+```rust
+#[starknet::contract]
+mod MyNFT {
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc721::{ERC721Component, ERC721HooksEmptyImpl};
+ use starknet::ContractAddress;
+
+ component!(path: ERC721Component, storage: erc721, event: ERC721Event);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // ERC721 Mixin
+ #[abi(embed_v0)]
+ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;
+ impl ERC721InternalImpl = ERC721Component::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc721: ERC721Component::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC721Event: ERC721Component::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ recipient: ContractAddress
+ ) {
+ let name = "MyNFT";
+ let symbol = "NFT";
+ let base_uri = "https://api.example.com/v1/";
+ let token_id = 1;
+
+ self.erc721.initializer(name, symbol, base_uri);
+ self.erc721.mint(recipient, token_id);
+ }
+}
+```
+
+## Interface
+
+The following interface represents the full ABI of the Contracts for Cairo [ERC721Component](/contracts-cairo/2.x/api/erc721#ERC721Component).
+The interface includes the [IERC721](/contracts-cairo/2.x/api/erc721#IERC721) standard interface and the optional [IERC721Metadata](/contracts-cairo/2.x/api/erc721#IERC721Metadata) interface.
+
+To support older token deployments, as mentioned in [Dual interfaces](./guides/interfaces-and-dispatchers#dual-interfaces), the component also includes implementations of the interface written in camelCase.
+
+```rust
+#[starknet::interface]
+pub trait ERC721ABI {
+ // IERC721
+ fn balance_of(account: ContractAddress) -> u256;
+ fn owner_of(token_id: u256) -> ContractAddress;
+ fn safe_transfer_from(
+ from: ContractAddress,
+ to: ContractAddress,
+ token_id: u256,
+ data: Span
+ );
+ fn transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256);
+ fn approve(to: ContractAddress, token_id: u256);
+ fn set_approval_for_all(operator: ContractAddress, approved: bool);
+ fn get_approved(token_id: u256) -> ContractAddress;
+ fn is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool;
+
+ // IERC721Metadata
+ fn name() -> ByteArray;
+ fn symbol() -> ByteArray;
+ fn token_uri(token_id: u256) -> ByteArray;
+
+ // IERC721CamelOnly
+ fn balanceOf(account: ContractAddress) -> u256;
+ fn ownerOf(tokenId: u256) -> ContractAddress;
+ fn safeTransferFrom(
+ from: ContractAddress,
+ to: ContractAddress,
+ tokenId: u256,
+ data: Span
+ );
+ fn transferFrom(from: ContractAddress, to: ContractAddress, tokenId: u256);
+ fn setApprovalForAll(operator: ContractAddress, approved: bool);
+ fn getApproved(tokenId: u256) -> ContractAddress;
+ fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool;
+
+ // IERC721MetadataCamelOnly
+ fn tokenURI(tokenId: u256) -> ByteArray;
+}
+```
+
+## ERC721 compatibility
+
+Although Starknet is not EVM compatible, this implementation aims to be as close as possible to the ERC721 standard.
+This implementation does, however, include a few notable differences such as:
+
+* ``interface_id``s are hardcoded and initialized by the constructor.
+The hardcoded values derive from Starknet’s selector calculations.
+See the [Introspection](./introspection) docs.
+* `safe_transfer_from` can only be expressed as a single function in Cairo as opposed to the two functions declared in EIP721, because function overloading is currently not possible in Cairo.
+The difference between both functions consists of accepting `data` as an argument.
+`safe_transfer_from` by default accepts the `data` argument which is interpreted as `Span`.
+If `data` is not used, simply pass an empty array.
+* ERC721 utilizes [SRC5](./introspection#src5) to declare and query interface support on Starknet as opposed to Ethereum’s [EIP165](https://eips.ethereum.org/EIPS/eip-165).
+The design for `SRC5` is similar to OpenZeppelin’s [ERC165Storage](https://docs.openzeppelin.com/contracts/4.xapi/utils#ERC165Storage).
+* `IERC721Receiver` compliant contracts return a hardcoded interface ID according to Starknet selectors (as opposed to selector calculation in Solidity).
+
+## Token transfers
+
+This library includes [transfer_from](/contracts-cairo/2.x/api/erc721#IERC721-transfer_from) and [safe_transfer_from](/contracts-cairo/2.x/api/erc721#IERC721-safe_transfer_from) to transfer NFTs.
+If using `transfer_from`, **the caller is responsible to confirm that the recipient is capable of receiving NFTs or else they may be permanently lost.**
+The `safe_transfer_from` method mitigates this risk by querying the recipient contract’s interface support.
+
+
+Usage of `safe_transfer_from` prevents loss, though the caller must understand this adds an external call which potentially creates a reentrancy vulnerability.
+
+
+## Receiving tokens
+
+In order to be sure a non-account contract can safely accept ERC721 tokens, said contract must implement the `IERC721Receiver` interface.
+The recipient contract must also implement the [SRC5](./introspection#src5) interface which, as described earlier, supports interface introspection.
+
+### IERC721Receiver
+
+```rust
+#[starknet::interface]
+pub trait IERC721Receiver {
+ fn on_erc721_received(
+ operator: ContractAddress,
+ from: ContractAddress,
+ token_id: u256,
+ data: Span
+ ) -> felt252;
+}
+```
+
+Implementing the `IERC721Receiver` interface exposes the [on_erc721_received](/contracts-cairo/2.x/api/erc721#IERC721Receiver-on_erc721_received) method.
+When safe methods such as [safe_transfer_from](/contracts-cairo/2.x/api/erc721#IERC721-safe_transfer_from) and [safe_mint](/contracts-cairo/2.x/api/erc721#ERC721-safe_mint) are called, they invoke the recipient contract’s `on_erc721_received` method which **must** return the [IERC721Receiver interface ID](/contracts-cairo/2.x/api/erc721#IERC721Receiver).
+Otherwise, the transaction will fail.
+
+
+For information on how to calculate interface IDs, see [Computing the interface ID](./introspection#computing-the-interface-id).
+
+
+### Creating a token receiver contract
+
+The Contracts for Cairo `IERC721ReceiverImpl` already returns the correct interface ID for safe token transfers.
+To integrate the `IERC721Receiver` interface into a contract, simply include the ABI embed directive to the implementation and add the `initializer` in the contract’s constructor.
+Here’s an example of a simple token receiver contract:
+
+```rust
+#[starknet::contract]
+mod MyTokenReceiver {
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc721::ERC721ReceiverComponent;
+ use starknet::ContractAddress;
+
+ component!(path: ERC721ReceiverComponent, storage: erc721_receiver, event: ERC721ReceiverEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // ERC721Receiver Mixin
+ #[abi(embed_v0)]
+ impl ERC721ReceiverMixinImpl = ERC721ReceiverComponent::ERC721ReceiverMixinImpl;
+ impl ERC721ReceiverInternalImpl = ERC721ReceiverComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ erc721_receiver: ERC721ReceiverComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC721ReceiverEvent: ERC721ReceiverComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ self.erc721_receiver.initializer();
+ }
+}
+```
+
+## Storing ERC721 URIs
+
+Token URIs were previously stored as single field elements prior to Cairo v0.2.5.
+ERC721Component now stores only the base URI as a `ByteArray` and the full token URI is returned as the `ByteArray` concatenation of the base URI and the token ID through the [token_uri](/contracts-cairo/2.x/api/erc721#IERC721Metadata-token_uri) method.
+This design mirrors OpenZeppelin’s default [Solidity implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/932fddf69a699a9a80fd2396fd1a2ab91cdda123/contracts/token/ERC721/ERC721.sol#L85-L93) for ERC721.
diff --git a/docs/content/contracts-cairo/2.x/finance.mdx b/docs/content/contracts-cairo/2.x/finance.mdx
new file mode 100644
index 00000000..50e91a4e
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/finance.mdx
@@ -0,0 +1,216 @@
+---
+title: Finance
+---
+
+This module includes primitives for financial systems.
+
+## Vesting component
+
+The [VestingComponent](/contracts-cairo/2.x/api/finance#VestingComponent) manages the gradual release of ERC-20 tokens to a designated beneficiary based on a predefined vesting schedule.
+The implementing contract must implement the [OwnableComponent](/contracts-cairo/2.x/api/access#OwnableComponent), where the contract owner is regarded as the vesting beneficiary.
+This structure allows ownership rights of both the contract and the vested tokens to be assigned and transferred.
+
+
+Any assets transferred to this contract will follow the vesting schedule as if they were locked from the beginning of the vesting period.
+As a result, if the vesting has already started, a portion of the newly transferred tokens may become immediately releasable.
+
+
+
+By setting the duration to 0, it’s possible to configure this contract to behave like an asset timelock that holds tokens
+for a beneficiary until a specified date.
+
+
+### Vesting schedule
+
+The [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) trait defines the logic for calculating the vested amount based on a given timestamp. This
+logic is not part of the [VestingComponent](/contracts-cairo/2.x/api/finance#VestingComponent), so any contract implementing the [VestingComponent](/contracts-cairo/2.x/api/finance#VestingComponent) must provide its own
+implementation of the [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) trait.
+
+
+There’s a ready-made implementation of the [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) trait available named [LinearVestingSchedule](/contracts-cairo/2.x/api/finance#LinearVestingSchedule).
+It incorporates a cliff period by returning 0 vested amount until the cliff ends. After the cliff, the vested amount
+is calculated as directly proportional to the time elapsed since the beginning of the vesting schedule.
+
+
+### Usage
+
+The contract must integrate [VestingComponent](/contracts-cairo/2.x/api/finance#VestingComponent) and [OwnableComponent](/contracts-cairo/2.x/api/access#OwnableComponent) as dependencies. The contract’s constructor
+should initialize both components. Core vesting parameters, such as `beneficiary`, `start`, `duration`
+and `cliff_duration`, are passed as arguments to the constructor and set at the time of deployment.
+
+The implementing contract must provide an implementation of the [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) trait. This can be achieved either by importing
+a ready-made [LinearVestingSchedule](/contracts-cairo/2.x/api/finance#LinearVestingSchedule) implementation or by defining a custom one.
+
+Here’s an example of a simple vesting wallet contract with a [LinearVestingSchedule](/contracts-cairo/2.x/api/finance#LinearVestingSchedule), where the vested amount
+is calculated as being directly proportional to the time elapsed since the start of the vesting period.
+
+```rust
+#[starknet::contract]
+mod LinearVestingWallet {
+ use openzeppelin_access::ownable::OwnableComponent;
+ use openzeppelin_finance::vesting::{VestingComponent, LinearVestingSchedule};
+ use starknet::ContractAddress;
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: VestingComponent, storage: vesting, event: VestingEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl VestingImpl = VestingComponent::VestingImpl;
+ impl VestingInternalImpl = VestingComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ vesting: VestingComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ VestingEvent: VestingComponent::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ beneficiary: ContractAddress,
+ start: u64,
+ duration: u64,
+ cliff_duration: u64
+ ) {
+ self.ownable.initializer(beneficiary);
+ self.vesting.initializer(start, duration, cliff_duration);
+ }
+}
+```
+
+A vesting schedule will often follow a custom formula. In such cases, the [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) trait is useful.
+To support a custom vesting schedule, the contract must provide an implementation of the
+[calculate_vested_amount](/contracts-cairo/2.x/api/finance#VestingComponent-calculate_vested_amount) function based on the desired formula.
+
+
+When using a custom [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) implementation, the [LinearVestingSchedule](/contracts-cairo/2.x/api/finance#LinearVestingSchedule) must be excluded from the imports.
+
+
+
+If there are additional parameters required for calculations, which are stored in the contract’s storage, you can access them using `self.get_contract()`.
+
+
+Here’s an example of a vesting wallet contract with a custom [VestingSchedule](/contracts-cairo/2.x/api/finance#VestingComponent-Vesting-Schedule) implementation, where tokens
+are vested in a number of steps.
+
+```rust
+#[starknet::contract]
+mod StepsVestingWallet {
+ use openzeppelin_access::ownable::OwnableComponent;
+ use openzeppelin_finance::vesting::VestingComponent::VestingScheduleTrait;
+ use openzeppelin_finance::vesting::VestingComponent;
+ use starknet::ContractAddress;
+ use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: VestingComponent, storage: vesting, event: VestingEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl VestingImpl = VestingComponent::VestingImpl;
+ impl VestingInternalImpl = VestingComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ total_steps: u64,
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ vesting: VestingComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ VestingEvent: VestingComponent::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ total_steps: u64,
+ beneficiary: ContractAddress,
+ start: u64,
+ duration: u64,
+ cliff: u64,
+ ) {
+ self.total_steps.write(total_steps);
+ self.ownable.initializer(beneficiary);
+ self.vesting.initializer(start, duration, cliff);
+ }
+
+ impl VestingSchedule of VestingScheduleTrait {
+ fn calculate_vested_amount(
+ self: @VestingComponent::ComponentState,
+ token: ContractAddress,
+ total_allocation: u256,
+ timestamp: u64,
+ start: u64,
+ duration: u64,
+ cliff: u64,
+ ) -> u256 {
+ if timestamp < cliff {
+ 0
+ } else if timestamp >= start + duration {
+ total_allocation
+ } else {
+ let total_steps = self.get_contract().total_steps.read();
+ let vested_per_step = total_allocation / total_steps.into();
+ let step_duration = duration / total_steps;
+ let current_step = (timestamp - start) / step_duration;
+ let vested_amount = vested_per_step * current_step.into();
+ vested_amount
+ }
+ }
+ }
+}
+```
+
+### Interface
+
+Here is the full interface of a standard contract implementing the vesting functionality:
+
+```rust
+#[starknet::interface]
+pub trait VestingABI {
+ // IVesting
+ fn start(self: @TState) -> u64;
+ fn cliff(self: @TState) -> u64;
+ fn duration(self: @TState) -> u64;
+ fn end(self: @TState) -> u64;
+ fn released(self: @TState, token: ContractAddress) -> u256;
+ fn releasable(self: @TState, token: ContractAddress) -> u256;
+ fn vested_amount(self: @TState, token: ContractAddress, timestamp: u64) -> u256;
+ fn release(ref self: TState, token: ContractAddress) -> u256;
+
+ // IOwnable
+ fn owner(self: @TState) -> ContractAddress;
+ fn transfer_ownership(ref self: TState, new_owner: ContractAddress);
+ fn renounce_ownership(ref self: TState);
+
+ // IOwnableCamelOnly
+ fn transferOwnership(ref self: TState, newOwner: ContractAddress);
+ fn renounceOwnership(ref self: TState);
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/governance/governor.mdx b/docs/content/contracts-cairo/2.x/governance/governor.mdx
new file mode 100644
index 00000000..cfad3946
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/governance/governor.mdx
@@ -0,0 +1,443 @@
+---
+title: Governor
+---
+
+Decentralized protocols are in constant evolution from the moment they are publicly released. Often,
+the initial team retains control of this evolution in the first stages, but eventually delegates it
+to a community of stakeholders. The process by which this community makes decisions is called
+on-chain governance, and it has become a central component of decentralized protocols, fueling
+varied decisions such as parameter tweaking, smart contract upgrades, integrations with other
+protocols, treasury management, grants, etc.
+
+This governance protocol is generally implemented in a special-purpose contract called “Governor”. In
+OpenZeppelin Contracts for Cairo, we set out to build a modular system of Governor components where different
+requirements can be accommodated by implementing specific traits. You will find the most common requirements out of the box,
+but writing additional ones is simple, and we will be adding new features as requested by the community in future releases.
+
+## Usage and setup
+
+### Token
+
+The voting power of each account in our governance setup will be determined by an ERC20 or an ERC721 token. The token has
+to implement the [VotesComponent](../api/governance#VotesComponent) extension. This extension will keep track of historical balances so that voting power
+is retrieved from past snapshots rather than current balance, which is an important protection that prevents double voting.
+
+If your project already has a live token that does not include Votes and is not upgradeable, you can wrap it in a
+governance token by using a wrapper. This will allow token holders to participate in governance by wrapping their tokens 1-to-1.
+
+
+The library currently does not include a wrapper for tokens, but it will be added in a future release.
+
+
+
+Currently, the clock mode is fixed to block timestamps, since the Votes component uses the block timestamp to track
+checkpoints. We plan to add support for more flexible clock modes in Votes in a future release, allowing to use, for example,
+block numbers instead.
+
+
+### Governor
+
+We will initially build a Governor without a timelock. The core logic is given by the [GovernorComponent](../api/governance#GovernorComponent), but we
+still need to choose:
+
+1) how voting power is determined,
+
+2) how many votes are needed for quorum,
+
+3) what options people have when casting a vote and how those votes are counted, and
+
+4) the execution mechanism that should be used.
+
+Each of these aspects is customizable by writing your own extensions,
+or more easily choosing one from the library.
+
+***For 1)*** we will use the GovernorVotes extension, which hooks to an [IVotes](../api/governance#IVotes) instance to determine the voting power
+of an account based on the token balance they hold when a proposal becomes active.
+This module requires the address of the token to be passed as an argument to the initializer.
+
+***For 2)*** we will use GovernorVotesQuorumFraction. This works together with the [IVotes](../api/governance#IVotes) instance to define the quorum as a
+percentage of the total supply at the block when a proposal’s voting power is retrieved. This requires an initializer
+parameter to set the percentage besides the votes token address. Most Governors nowadays use 4%. Since the quorum denominator
+is 1000 for precision, we initialize the module with a numerator of 40, resulting in a 4% quorum (40/1000 = 0.04 or 4%).
+
+***For 3)*** we will use GovernorCountingSimple, an extension that offers 3 options to voters: For, Against, and Abstain,
+and where only For and Abstain votes are counted towards quorum.
+
+***For 4)*** we will use GovernorCoreExecution, an extension that allows proposal execution directly through the governor.
+
+
+Another option is GovernorTimelockExecution. An example can be found in the next section.
+
+
+Besides these, we also need an implementation for the GovernorSettingsTrait defining the voting delay, voting period,
+and proposal threshold. While we can use the GovernorSettings extension which allows to set these parameters by the
+governor itself, we will implement the trait locally in the contract and set the voting delay, voting period,
+and proposal threshold as constant values.
+
+__voting_delay__: How long after a proposal is created should voting power be fixed. A large voting delay gives
+users time to unstake tokens if necessary.
+
+__voting_period__: How long does a proposal remain open to votes.
+
+
+These parameters are specified in the unit defined in the token’s clock, which is for now always timestamps.
+
+
+__proposal_threshold__: This restricts proposal creation to accounts who have enough voting power.
+
+An implementation of `GovernorComponent::ImmutableConfig` is also required. For the example below, we have used
+the `DefaultConfig`. Check the immutable-config guide for more details.
+
+The last missing step is to add an `SNIP12Metadata` implementation used to retrieve the name and version of the governor.
+
+```rust
+#[starknet::contract]
+mod MyGovernor {
+ use openzeppelin_governance::governor::GovernorComponent::InternalTrait as GovernorInternalTrait;
+ use openzeppelin_governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait;
+ use openzeppelin_governance::governor::extensions::{
+ GovernorVotesQuorumFractionComponent, GovernorCountingSimpleComponent,
+ GovernorCoreExecutionComponent,
+ };
+ use openzeppelin_governance::governor::{GovernorComponent, DefaultConfig};
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_utils::cryptography::snip12::SNIP12Metadata;
+ use starknet::ContractAddress;
+
+ pub const VOTING_DELAY: u64 = 86400; // 1 day
+ pub const VOTING_PERIOD: u64 = 604800; // 1 week
+ pub const PROPOSAL_THRESHOLD: u256 = 10;
+ pub const QUORUM_NUMERATOR: u256 = 40; // 4%
+
+ component!(path: GovernorComponent, storage: governor, event: GovernorEvent);
+ component!(
+ path: GovernorVotesQuorumFractionComponent,
+ storage: governor_votes,
+ event: GovernorVotesEvent
+ );
+ component!(
+ path: GovernorCountingSimpleComponent,
+ storage: governor_counting_simple,
+ event: GovernorCountingSimpleEvent
+ );
+ component!(
+ path: GovernorCoreExecutionComponent,
+ storage: governor_core_execution,
+ event: GovernorCoreExecutionEvent
+ );
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Governor
+ #[abi(embed_v0)]
+ impl GovernorImpl = GovernorComponent::GovernorImpl;
+
+ // Extensions external
+ #[abi(embed_v0)]
+ impl QuorumFractionImpl =
+ GovernorVotesQuorumFractionComponent::QuorumFractionImpl;
+
+ // Extensions internal
+ impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;
+ impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;
+ impl GovernorCountingSimpleImpl =
+ GovernorCountingSimpleComponent::GovernorCounting;
+ impl GovernorCoreExecutionImpl =
+ GovernorCoreExecutionComponent::GovernorExecution;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ pub governor: GovernorComponent::Storage,
+ #[substorage(v0)]
+ pub governor_votes: GovernorVotesQuorumFractionComponent::Storage,
+ #[substorage(v0)]
+ pub governor_counting_simple: GovernorCountingSimpleComponent::Storage,
+ #[substorage(v0)]
+ pub governor_core_execution: GovernorCoreExecutionComponent::Storage,
+ #[substorage(v0)]
+ pub src5: SRC5Component::Storage,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ GovernorEvent: GovernorComponent::Event,
+ #[flat]
+ GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,
+ #[flat]
+ GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,
+ #[flat]
+ GovernorCoreExecutionEvent: GovernorCoreExecutionComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, votes_token: ContractAddress) {
+ self.governor.initializer();
+ self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);
+ }
+
+ //
+ // SNIP12 Metadata
+ //
+
+ pub impl SNIP12MetadataImpl of SNIP12Metadata {
+ fn name() -> felt252 {
+ 'DAPP_NAME'
+ }
+
+ fn version() -> felt252 {
+ 'DAPP_VERSION'
+ }
+ }
+
+ //
+ // Locally implemented extensions
+ //
+
+ pub impl GovernorSettings of GovernorComponent::GovernorSettingsTrait {
+ /// See `GovernorComponent::GovernorSettingsTrait::voting_delay`.
+ fn voting_delay(self: @GovernorComponent::ComponentState) -> u64 {
+ VOTING_DELAY
+ }
+
+ /// See `GovernorComponent::GovernorSettingsTrait::voting_period`.
+ fn voting_period(self: @GovernorComponent::ComponentState) -> u64 {
+ VOTING_PERIOD
+ }
+
+ /// See `GovernorComponent::GovernorSettingsTrait::proposal_threshold`.
+ fn proposal_threshold(self: @GovernorComponent::ComponentState) -> u256 {
+ PROPOSAL_THRESHOLD
+ }
+ }
+}
+```
+
+### Timelock
+
+It is good practice to add a timelock to governance decisions. This allows users to exit the system if they disagree
+with a decision before it is executed. We will use OpenZeppelin’s [TimelockController](#timelock) in combination with the
+GovernorTimelockExecution extension.
+
+
+When using a timelock, it is the timelock that will execute proposals and thus the timelock that should
+hold any funds, ownership, and access control roles.
+
+
+TimelockController uses an [AccessControl](../access#role-based-accesscontrol) setup that we need to understand in order to set up roles.
+
+The Proposer role is in charge of queueing operations: this is the role the Governor instance must be granted,
+and it MUST be the only proposer (and canceller) in the system.
+
+The Executor role is in charge of executing already available operations: we can assign this role to the special
+zero address to allow anyone to execute (if operations can be particularly time sensitive, the Governor should be made Executor instead).
+
+The Canceller role is in charge of canceling operations: the Governor instance must be granted this role,
+and it MUST be the only canceller in the system.
+
+Lastly, there is the Admin role, which can grant and revoke the two previous roles: this is a very sensitive role that will be granted automatically to the timelock itself, and optionally to a second account, which can be used for ease of setup but should promptly renounce the role.
+
+The following example uses the GovernorTimelockExecution extension, together with GovernorSettings, and uses a
+fixed quorum value instead of a percentage:
+
+```rust
+#[starknet::contract]
+pub mod MyTimelockedGovernor {
+ use openzeppelin_governance::governor::GovernorComponent::InternalTrait as GovernorInternalTrait;
+ use openzeppelin_governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;
+ use openzeppelin_governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;
+ use openzeppelin_governance::governor::extensions::GovernorVotesComponent::InternalTrait as GovernorVotesInternalTrait;
+ use openzeppelin_governance::governor::extensions::{
+ GovernorVotesComponent, GovernorSettingsComponent, GovernorCountingSimpleComponent,
+ GovernorTimelockExecutionComponent
+ };
+ use openzeppelin_governance::governor::{GovernorComponent, DefaultConfig};
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_utils::cryptography::snip12::SNIP12Metadata;
+ use starknet::ContractAddress;
+
+ pub const VOTING_DELAY: u64 = 86400; // 1 day
+ pub const VOTING_PERIOD: u64 = 604800; // 1 week
+ pub const PROPOSAL_THRESHOLD: u256 = 10;
+ pub const QUORUM: u256 = 100_000_000;
+
+ component!(path: GovernorComponent, storage: governor, event: GovernorEvent);
+ component!(path: GovernorVotesComponent, storage: governor_votes, event: GovernorVotesEvent);
+ component!(
+ path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent
+ );
+ component!(
+ path: GovernorCountingSimpleComponent,
+ storage: governor_counting_simple,
+ event: GovernorCountingSimpleEvent
+ );
+ component!(
+ path: GovernorTimelockExecutionComponent,
+ storage: governor_timelock_execution,
+ event: GovernorTimelockExecutionEvent
+ );
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Governor
+ #[abi(embed_v0)]
+ impl GovernorImpl = GovernorComponent::GovernorImpl;
+
+ // Extensions external
+ #[abi(embed_v0)]
+ impl VotesTokenImpl = GovernorVotesComponent::VotesTokenImpl;
+ #[abi(embed_v0)]
+ impl GovernorSettingsAdminImpl =
+ GovernorSettingsComponent::GovernorSettingsAdminImpl;
+ #[abi(embed_v0)]
+ impl TimelockedImpl =
+ GovernorTimelockExecutionComponent::TimelockedImpl;
+
+ // Extensions internal
+ impl GovernorVotesImpl = GovernorVotesComponent::GovernorVotes;
+ impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;
+ impl GovernorCountingSimpleImpl =
+ GovernorCountingSimpleComponent::GovernorCounting;
+ impl GovernorTimelockExecutionImpl =
+ GovernorTimelockExecutionComponent::GovernorExecution;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ pub governor: GovernorComponent::Storage,
+ #[substorage(v0)]
+ pub governor_votes: GovernorVotesComponent::Storage,
+ #[substorage(v0)]
+ pub governor_settings: GovernorSettingsComponent::Storage,
+ #[substorage(v0)]
+ pub governor_counting_simple: GovernorCountingSimpleComponent::Storage,
+ #[substorage(v0)]
+ pub governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,
+ #[substorage(v0)]
+ pub src5: SRC5Component::Storage,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ GovernorEvent: GovernorComponent::Event,
+ #[flat]
+ GovernorVotesEvent: GovernorVotesComponent::Event,
+ #[flat]
+ GovernorSettingsEvent: GovernorSettingsComponent::Event,
+ #[flat]
+ GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,
+ #[flat]
+ GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState, votes_token: ContractAddress, timelock_controller: ContractAddress
+ ) {
+ self.governor.initializer();
+ self.governor_votes.initializer(votes_token);
+ self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);
+ self.governor_timelock_execution.initializer(timelock_controller);
+ }
+
+ //
+ // SNIP12 Metadata
+ //
+
+ pub impl SNIP12MetadataImpl of SNIP12Metadata {
+ fn name() -> felt252 {
+ 'DAPP_NAME'
+ }
+
+ fn version() -> felt252 {
+ 'DAPP_VERSION'
+ }
+ }
+
+ //
+ // Locally implemented extensions
+ //
+
+ impl GovernorQuorum of GovernorComponent::GovernorQuorumTrait {
+ /// See `GovernorComponent::GovernorQuorumTrait::quorum`.
+ fn quorum(self: @GovernorComponent::ComponentState, timepoint: u64) -> u256 {
+ QUORUM
+ }
+ }
+}
+```
+
+## Interface
+
+This is the full interface of the `Governor` implementation:
+```rust
+#[starknet::interface]
+pub trait IGovernor {
+ fn name(self: @TState) -> felt252;
+ fn version(self: @TState) -> felt252;
+ fn COUNTING_MODE(self: @TState) -> ByteArray;
+ fn hash_proposal(self: @TState, calls: Span, description_hash: felt252) -> felt252;
+ fn state(self: @TState, proposal_id: felt252) -> ProposalState;
+ fn proposal_threshold(self: @TState) -> u256;
+ fn proposal_snapshot(self: @TState, proposal_id: felt252) -> u64;
+ fn proposal_deadline(self: @TState, proposal_id: felt252) -> u64;
+ fn proposal_proposer(self: @TState, proposal_id: felt252) -> ContractAddress;
+ fn proposal_eta(self: @TState, proposal_id: felt252) -> u64;
+ fn proposal_needs_queuing(self: @TState, proposal_id: felt252) -> bool;
+ fn voting_delay(self: @TState) -> u64;
+ fn voting_period(self: @TState) -> u64;
+ fn quorum(self: @TState, timepoint: u64) -> u256;
+ fn get_votes(self: @TState, account: ContractAddress, timepoint: u64) -> u256;
+ fn get_votes_with_params(
+ self: @TState, account: ContractAddress, timepoint: u64, params: Span
+ ) -> u256;
+ fn has_voted(self: @TState, proposal_id: felt252, account: ContractAddress) -> bool;
+ fn propose(ref self: TState, calls: Span, description: ByteArray) -> felt252;
+ fn queue(ref self: TState, calls: Span, description_hash: felt252) -> felt252;
+ fn execute(ref self: TState, calls: Span, description_hash: felt252) -> felt252;
+ fn cancel(ref self: TState, calls: Span, description_hash: felt252) -> felt252;
+ fn cast_vote(ref self: TState, proposal_id: felt252, support: u8) -> u256;
+ fn cast_vote_with_reason(
+ ref self: TState, proposal_id: felt252, support: u8, reason: ByteArray
+ ) -> u256;
+ fn cast_vote_with_reason_and_params(
+ ref self: TState,
+ proposal_id: felt252,
+ support: u8,
+ reason: ByteArray,
+ params: Span
+ ) -> u256;
+ fn cast_vote_by_sig(
+ ref self: TState,
+ proposal_id: felt252,
+ support: u8,
+ voter: ContractAddress,
+ signature: Span
+ ) -> u256;
+ fn cast_vote_with_reason_and_params_by_sig(
+ ref self: TState,
+ proposal_id: felt252,
+ support: u8,
+ voter: ContractAddress,
+ reason: ByteArray,
+ params: Span,
+ signature: Span
+ ) -> u256;
+ fn nonces(self: @TState, voter: ContractAddress) -> felt252;
+ fn relay(ref self: TState, call: Call);
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/governance/multisig.mdx b/docs/content/contracts-cairo/2.x/governance/multisig.mdx
new file mode 100644
index 00000000..c98fdf9d
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/governance/multisig.mdx
@@ -0,0 +1,150 @@
+---
+title: Multisig
+---
+
+The Multisig component implements a multi-signature mechanism to enhance the security and
+governance of smart contract transactions. It ensures that no single signer can unilaterally
+execute critical actions, requiring multiple registered signers to approve and collectively
+execute transactions.
+
+This component is designed to secure operations such as fund management or protocol governance,
+where collective decision-making is essential. The Multisig Component is self-administered,
+meaning that changes to signers or quorum must be approved through the multisig process itself.
+
+## Key features
+
+* **Multi-Signature Security**: transactions must be approved by multiple signers, ensuring
+distributed governance.
+* **Quorum Enforcement**: defines the minimum number of approvals required for transaction execution.
+* **Self-Administration**: all modifications to the component (e.g., adding or removing signers)
+must pass through the multisig process.
+* **Event Logging**: provides comprehensive event logging for transparency and auditability.
+
+## Signer management
+
+The Multisig component introduces the concept of signers and quorum:
+
+* **Signers**: only registered signers can submit, confirm, revoke, or execute transactions. The Multisig
+Component supports adding, removing, or replacing signers.
+* **Quorum**: the quorum defines the minimum number of confirmations required to approve a transaction.
+
+
+To prevent unauthorized modifications, only the contract itself can add, remove, or replace signers or change the quorum.
+This ensures that all modifications pass through the multisig approval process.
+
+
+## Transaction lifecycle
+
+The state of a transaction is represented by the `TransactionState` enum and can be retrieved
+by calling the `get_transaction_state` function with the transaction’s identifier.
+
+The identifier of a multisig transaction is a `felt252` value, computed as the Pedersen hash
+of the transaction’s calls and salt. It can be computed by invoking the implementing contract’s
+`hash_transaction` method for single-call transactions or `hash_transaction_batch` for multi-call
+transactions. Submitting a transaction with identical calls and the same salt value a second time
+will fail, as transaction identifiers must be unique. To resolve this, use a different salt value
+to generate a unique identifier.
+
+A transaction in the Multisig component follows a specific lifecycle:
+
+`NotFound` → `Pending` → `Confirmed` → `Executed`
+
+* **NotFound**: the transaction does not exist.
+* **Pending**: the transaction exists but has not reached the required confirmations.
+* **Confirmed**: the transaction has reached the quorum but has not yet been executed.
+* **Executed**: the transaction has been successfully executed.
+
+## Usage
+
+Integrating the Multisig functionality into a contract requires implementing [MultisigComponent](../api/governance#MultisigComponent).
+The contract’s constructor should initialize the component with a quorum value and a list of initial signers.
+
+Here’s an example of a simple wallet contract featuring the Multisig functionality:
+
+```rust
+#[starknet::contract]
+mod MultisigWallet {
+ use openzeppelin_governance::multisig::MultisigComponent;
+ use starknet::ContractAddress;
+
+ component!(path: MultisigComponent, storage: multisig, event: MultisigEvent);
+
+ #[abi(embed_v0)]
+ impl MultisigImpl = MultisigComponent::MultisigImpl;
+ impl MultisigInternalImpl = MultisigComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ multisig: MultisigComponent::Storage,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ MultisigEvent: MultisigComponent::Event,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, quorum: u32, signers: Span) {
+ self.multisig.initializer(quorum, signers);
+ }
+}
+```
+
+## Interface
+
+This is the interface of a contract implementing the [MultisigComponent](../api/governance#MultisigComponent):
+
+```rust
+#[starknet::interface]
+pub trait MultisigABI {
+ // Read functions
+ fn get_quorum(self: @TState) -> u32;
+ fn is_signer(self: @TState, signer: ContractAddress) -> bool;
+ fn get_signers(self: @TState) -> Span;
+ fn is_confirmed(self: @TState, id: TransactionID) -> bool;
+ fn is_confirmed_by(self: @TState, id: TransactionID, signer: ContractAddress) -> bool;
+ fn is_executed(self: @TState, id: TransactionID) -> bool;
+ fn get_submitted_block(self: @TState, id: TransactionID) -> u64;
+ fn get_transaction_state(self: @TState, id: TransactionID) -> TransactionState;
+ fn get_transaction_confirmations(self: @TState, id: TransactionID) -> u32;
+ fn hash_transaction(
+ self: @TState,
+ to: ContractAddress,
+ selector: felt252,
+ calldata: Span,
+ salt: felt252,
+ ) -> TransactionID;
+ fn hash_transaction_batch(self: @TState, calls: Span, salt: felt252) -> TransactionID;
+
+ // Write functions
+ fn add_signers(ref self: TState, new_quorum: u32, signers_to_add: Span);
+ fn remove_signers(ref self: TState, new_quorum: u32, signers_to_remove: Span);
+ fn replace_signer(
+ ref self: TState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress,
+ );
+ fn change_quorum(ref self: TState, new_quorum: u32);
+ fn submit_transaction(
+ ref self: TState,
+ to: ContractAddress,
+ selector: felt252,
+ calldata: Span,
+ salt: felt252,
+ ) -> TransactionID;
+ fn submit_transaction_batch(
+ ref self: TState, calls: Span, salt: felt252,
+ ) -> TransactionID;
+ fn confirm_transaction(ref self: TState, id: TransactionID);
+ fn revoke_confirmation(ref self: TState, id: TransactionID);
+ fn execute_transaction(
+ ref self: TState,
+ to: ContractAddress,
+ selector: felt252,
+ calldata: Span,
+ salt: felt252,
+ );
+ fn execute_transaction_batch(ref self: TState, calls: Span, salt: felt252);
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/governance/timelock.mdx b/docs/content/contracts-cairo/2.x/governance/timelock.mdx
new file mode 100644
index 00000000..d3404511
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/governance/timelock.mdx
@@ -0,0 +1,198 @@
+---
+title: Timelock Controller
+---
+
+The Timelock Controller provides a means of enforcing time delays on the execution of transactions. This is considered good practice regarding governance systems because it allows users the opportunity to exit the system if they disagree with a decision before it is executed.
+
+
+The Timelock contract itself executes transactions, not the user. The Timelock should, therefore, hold associated funds, ownership, and access control roles.
+
+
+## Operation lifecycle
+
+The state of an operation is represented by the `OperationState` enum and can be retrieved
+by calling the `get_operation_state` function with the operation’s identifier.
+
+The identifier of an operation is a `felt252` value, computed as the Pedersen hash of the
+operation’s call or calls, its predecessor, and salt. It can be computed by invoking the
+implementing contract’s `hash_operation` function for single-call operations or
+`hash_operation_batch` for multi-call operations. Submitting an operation with identical calls,
+predecessor, and the same salt value a second time will fail, as operation identifiers must be
+unique. To resolve this, use a different salt value to generate a unique identifier.
+
+Timelocked operations follow a specific lifecycle:
+
+`Unset` → `Waiting` → `Ready` → `Done`
+
+* `Unset`: the operation has not been scheduled or has been canceled.
+* `Waiting`: the operation has been scheduled and is pending the scheduled delay.
+* `Ready`: the timer has expired, and the operation is eligible for execution.
+* `Done`: the operation has been executed.
+
+## Timelock flow
+
+### Schedule
+
+When a proposer calls [schedule](../api/governance#ITimelock-schedule), the `OperationState` moves from `Unset` to `Waiting`.
+This starts a timer that must be greater than or equal to the minimum delay.
+The timer expires at a timestamp accessible through [get_timestamp](../api/governance#ITimelock-get_timestamp).
+Once the timer expires, the `OperationState` automatically moves to the `Ready` state.
+At this point, it can be executed.
+
+### Execute
+
+By calling [execute](../api/governance#ITimelock-execute), an executor triggers the operation’s underlying transactions and moves it to the `Done` state. If the operation has a predecessor, the predecessor’s operation must be in the `Done` state for this transaction to succeed.
+
+### Cancel
+
+The [cancel](../api/governance#ITimelock-cancel) function allows cancellers to cancel any pending operations.
+This resets the operation to the `Unset` state.
+It is therefore possible for a proposer to re-schedule an operation that has been cancelled.
+In this case, the timer restarts when the operation is re-scheduled.
+
+## Roles
+
+[TimelockControllerComponent](../api/governance#TimelockControllerComponent) leverages an [AccessControlComponent](../api/access#AccessControlComponent) setup that we need to understand in order to set up roles.
+
+* `PROPOSER_ROLE` - in charge of queueing operations.
+* `CANCELLER_ROLE` - may cancel scheduled operations.
+During initialization, accounts granted with `PROPOSER_ROLE` will also be granted `CANCELLER_ROLE`.
+Therefore, the initial proposers may also cancel operations after they are scheduled.
+* `EXECUTOR_ROLE` - in charge of executing already available operations.
+* `DEFAULT_ADMIN_ROLE` - can grant and revoke the three previous roles.
+
+
+The `DEFAULT_ADMIN_ROLE` is a sensitive role that will be granted automatically to the timelock itself and optionally to a second account.
+The latter case may be required to ease a contract’s initial configuration; however, this role should promptly be renounced.
+
+
+Furthermore, the timelock component supports the concept of open roles for the `EXECUTOR_ROLE`.
+This allows anyone to execute an operation once it’s in the `Ready` OperationState.
+To enable the `EXECUTOR_ROLE` to be open, grant the zero address with the `EXECUTOR_ROLE`.
+
+
+Be very careful with enabling open roles as _anyone_ can call the function.
+
+
+## Minimum delay
+
+The minimum delay of the timelock acts as a buffer from when a proposer schedules an operation to the earliest point at which an executor may execute that operation.
+The idea is for users, should they disagree with a scheduled proposal, to have options such as exiting the system or making their case for cancellers to cancel the operation.
+
+After initialization, the only way to change the timelock’s minimum delay is to schedule it and execute it with the same flow as any other operation.
+
+The minimum delay of a contract is accessible through [get_min_delay](../api/governance#ITimelock-get_min_delay).
+
+## Usage
+
+Integrating the timelock into a contract requires integrating [TimelockControllerComponent](../api/governance#TimelockControllerComponent) as well as [SRC5Component](../api/introspection#SRC5Component) and [AccessControlComponent](../api/access#AccessControlComponent) as dependencies.
+The contract’s constructor should initialize the timelock which consists of setting the:
+
+* Proposers and executors.
+* Minimum delay between scheduling and executing an operation.
+* Optional admin if additional configuration is required.
+
+
+The optional admin should renounce their role once configuration is complete.
+
+
+Here’s an example of a simple timelock contract:
+
+```rust
+#[starknet::contract]
+mod TimelockControllerContract {
+ use openzeppelin_access::accesscontrol::AccessControlComponent;
+ use openzeppelin_governance::timelock::TimelockControllerComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use starknet::ContractAddress;
+
+ component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
+ component!(path: TimelockControllerComponent, storage: timelock, event: TimelockEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Timelock Mixin
+ #[abi(embed_v0)]
+ impl TimelockMixinImpl =
+ TimelockControllerComponent::TimelockMixinImpl;
+ impl TimelockInternalImpl = TimelockControllerComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ access_control: AccessControlComponent::Storage,
+ #[substorage(v0)]
+ timelock: TimelockControllerComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ #[flat]
+ TimelockEvent: TimelockControllerComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ min_delay: u64,
+ proposers: Span,
+ executors: Span,
+ admin: ContractAddress
+ ) {
+ self.timelock.initializer(min_delay, proposers, executors, admin);
+ }
+}
+```
+
+## Interface
+
+This is the full interface of the TimelockMixinImpl implementation:
+
+```rust
+#[starknet::interface]
+pub trait TimelockABI {
+ // ITimelock
+ fn is_operation(self: @TState, id: felt252) -> bool;
+ fn is_operation_pending(self: @TState, id: felt252) -> bool;
+ fn is_operation_ready(self: @TState, id: felt252) -> bool;
+ fn is_operation_done(self: @TState, id: felt252) -> bool;
+ fn get_timestamp(self: @TState, id: felt252) -> u64;
+ fn get_operation_state(self: @TState, id: felt252) -> OperationState;
+ fn get_min_delay(self: @TState) -> u64;
+ fn hash_operation(self: @TState, call: Call, predecessor: felt252, salt: felt252) -> felt252;
+ fn hash_operation_batch(
+ self: @TState, calls: Span, predecessor: felt252, salt: felt252
+ ) -> felt252;
+ fn schedule(ref self: TState, call: Call, predecessor: felt252, salt: felt252, delay: u64);
+ fn schedule_batch(
+ ref self: TState, calls: Span, predecessor: felt252, salt: felt252, delay: u64
+ );
+ fn cancel(ref self: TState, id: felt252);
+ fn execute(ref self: TState, call: Call, predecessor: felt252, salt: felt252);
+ fn execute_batch(ref self: TState, calls: Span, predecessor: felt252, salt: felt252);
+ fn update_delay(ref self: TState, new_delay: u64);
+
+ // ISRC5
+ fn supports_interface(self: @TState, interface_id: felt252) -> bool;
+
+ // IAccessControl
+ fn has_role(self: @TState, role: felt252, account: ContractAddress) -> bool;
+ fn get_role_admin(self: @TState, role: felt252) -> felt252;
+ fn grant_role(ref self: TState, role: felt252, account: ContractAddress);
+ fn revoke_role(ref self: TState, role: felt252, account: ContractAddress);
+ fn renounce_role(ref self: TState, role: felt252, account: ContractAddress);
+
+ // IAccessControlCamel
+ fn hasRole(self: @TState, role: felt252, account: ContractAddress) -> bool;
+ fn getRoleAdmin(self: @TState, role: felt252) -> felt252;
+ fn grantRole(ref self: TState, role: felt252, account: ContractAddress);
+ fn revokeRole(ref self: TState, role: felt252, account: ContractAddress);
+ fn renounceRole(ref self: TState, role: felt252, account: ContractAddress);
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/governance/votes.mdx b/docs/content/contracts-cairo/2.x/governance/votes.mdx
new file mode 100644
index 00000000..44d9e731
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/governance/votes.mdx
@@ -0,0 +1,222 @@
+---
+title: Votes
+---
+
+The [VotesComponent](../api/governance#VotesComponent) provides a flexible system for tracking and delegating voting power. This system allows users to delegate their voting power to other addresses, enabling more active participation in governance.
+
+
+By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
+
+
+
+The transferring of voting units must be handled by the implementing contract. In the case of `ERC20` and `ERC721` this is usually done via the hooks. You can check the [usage](#usage) section for examples of how to implement this.
+
+
+## Key features
+
+1. **Delegation**: Users can delegate their voting power to any address, including themselves. Vote power can be delegated either by calling the [delegate](../api/governance#VotesComponent-delegate) function directly, or by providing a signature to be used with [delegate_by_sig](../api/governance#VotesComponent-delegate_by_sig).
+2. **Historical lookups**: The system keeps track of historical snapshots for each account, which allows the voting power of an account to be queried at a specific timestamp.\
+This can be used for example to determine the voting power of an account when a proposal was created, rather than using the current balance.
+
+## Usage
+
+When integrating the `VotesComponent`, the [VotingUnitsTrait](../api/governance#VotingUnitsTrait) must be implemented to get the voting units for a given account as a function of the implementing contract.\
+For simplicity, this module already provides two implementations for `ERC20` and `ERC721` tokens, which will work out of the box if the respective components are integrated.\
+Additionally, you must implement the [NoncesComponent](../api/utilities#NoncesComponent) and the [SNIP12Metadata](../api/utilities#snip12) trait to enable delegation by signatures.
+
+Here’s an example of how to structure a simple ERC20Votes contract:
+
+```rust
+#[starknet::contract]
+mod ERC20VotesContract {
+ use openzeppelin_governance::votes::VotesComponent;
+ use openzeppelin_token::erc20::{ERC20Component, DefaultConfig};
+ use openzeppelin_utils::cryptography::nonces::NoncesComponent;
+ use openzeppelin_utils::cryptography::snip12::SNIP12Metadata;
+ use starknet::ContractAddress;
+
+ component!(path: VotesComponent, storage: erc20_votes, event: ERC20VotesEvent);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+ component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);
+
+ // Votes
+ #[abi(embed_v0)]
+ impl VotesImpl = VotesComponent::VotesImpl;
+ impl VotesInternalImpl = VotesComponent::InternalImpl;
+
+ // ERC20
+ #[abi(embed_v0)]
+ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ // Nonces
+ #[abi(embed_v0)]
+ impl NoncesImpl = NoncesComponent::NoncesImpl;
+
+ #[storage]
+ pub struct Storage {
+ #[substorage(v0)]
+ pub erc20_votes: VotesComponent::Storage,
+ #[substorage(v0)]
+ pub erc20: ERC20Component::Storage,
+ #[substorage(v0)]
+ pub nonces: NoncesComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC20VotesEvent: VotesComponent::Event,
+ #[flat]
+ ERC20Event: ERC20Component::Event,
+ #[flat]
+ NoncesEvent: NoncesComponent::Event
+ }
+
+ // Required for hash computation.
+ pub impl SNIP12MetadataImpl of SNIP12Metadata {
+ fn name() -> felt252 {
+ 'DAPP_NAME'
+ }
+ fn version() -> felt252 {
+ 'DAPP_VERSION'
+ }
+ }
+
+ // We need to call the `transfer_voting_units` function after
+ // every mint, burn and transfer.
+ // For this, we use the `after_update` hook of the `ERC20Component::ERC20HooksTrait`.
+ impl ERC20VotesHooksImpl of ERC20Component::ERC20HooksTrait {
+ fn after_update(
+ ref self: ERC20Component::ComponentState,
+ from: ContractAddress,
+ recipient: ContractAddress,
+ amount: u256
+ ) {
+ let mut contract_state = self.get_contract_mut();
+ contract_state.erc20_votes.transfer_voting_units(from, recipient, amount);
+ }
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ self.erc20.initializer("MyToken", "MTK");
+ }
+}
+```
+
+And here’s an example of how to structure a simple ERC721Votes contract:
+
+```rust
+#[starknet::contract]
+pub mod ERC721VotesContract {
+ use openzeppelin_governance::votes::VotesComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_token::erc721::ERC721Component;
+ use openzeppelin_utils::cryptography::nonces::NoncesComponent;
+ use openzeppelin_utils::cryptography::snip12::SNIP12Metadata;
+ use starknet::ContractAddress;
+
+ component!(path: VotesComponent, storage: erc721_votes, event: ERC721VotesEvent);
+ component!(path: ERC721Component, storage: erc721, event: ERC721Event);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+ component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);
+
+ // Votes
+ #[abi(embed_v0)]
+ impl VotesImpl = VotesComponent::VotesImpl;
+ impl VotesInternalImpl = VotesComponent::InternalImpl;
+
+ // ERC721
+ #[abi(embed_v0)]
+ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;
+ impl ERC721InternalImpl = ERC721Component::InternalImpl;
+
+ // Nonces
+ #[abi(embed_v0)]
+ impl NoncesImpl = NoncesComponent::NoncesImpl;
+
+ #[storage]
+ pub struct Storage {
+ #[substorage(v0)]
+ pub erc721_votes: VotesComponent::Storage,
+ #[substorage(v0)]
+ pub erc721: ERC721Component::Storage,
+ #[substorage(v0)]
+ pub src5: SRC5Component::Storage,
+ #[substorage(v0)]
+ pub nonces: NoncesComponent::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ ERC721VotesEvent: VotesComponent::Event,
+ #[flat]
+ ERC721Event: ERC721Component::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ #[flat]
+ NoncesEvent: NoncesComponent::Event
+ }
+
+ /// Required for hash computation.
+ pub impl SNIP12MetadataImpl of SNIP12Metadata {
+ fn name() -> felt252 {
+ 'DAPP_NAME'
+ }
+ fn version() -> felt252 {
+ 'DAPP_VERSION'
+ }
+ }
+
+ // We need to call the `transfer_voting_units` function after
+ // every mint, burn and transfer.
+ // For this, we use the `before_update` hook of the
+ //`ERC721Component::ERC721HooksTrait`.
+ // This hook is called before the transfer is executed.
+ // This gives us access to the previous owner.
+ impl ERC721VotesHooksImpl of ERC721Component::ERC721HooksTrait {
+ fn before_update(
+ ref self: ERC721Component::ComponentState,
+ to: ContractAddress,
+ token_id: u256,
+ auth: ContractAddress
+ ) {
+ let mut contract_state = self.get_contract_mut();
+
+ // We use the internal function here since it does not check if the token
+ // id exists which is necessary for mints
+ let previous_owner = self._owner_of(token_id);
+ contract_state.erc721_votes.transfer_voting_units(previous_owner, to, 1);
+ }
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {
+ self.erc721.initializer("MyToken", "MTK", "");
+ }
+}
+```
+
+## Interface
+
+This is the full interface of the `VotesImpl` implementation:
+
+```rust
+#[starknet::interface]
+pub trait VotesABI {
+ // IVotes
+ fn get_votes(self: @TState, account: ContractAddress) -> u256;
+ fn get_past_votes(self: @TState, account: ContractAddress, timepoint: u64) -> u256;
+ fn get_past_total_supply(self: @TState, timepoint: u64) -> u256;
+ fn delegates(self: @TState, account: ContractAddress) -> ContractAddress;
+ fn delegate(ref self: TState, delegatee: ContractAddress);
+ fn delegate_by_sig(ref self: TState, delegator: ContractAddress, delegatee: ContractAddress, nonce: felt252, expiry: u64, signature: Span);
+
+ // INonces
+ fn nonces(self: @TState, owner: ContractAddress) -> felt252;
+}
+```
diff --git a/docs/content/contracts-cairo/2.x/guides/deploy-udc.mdx b/docs/content/contracts-cairo/2.x/guides/deploy-udc.mdx
new file mode 100644
index 00000000..5e20ac1e
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/guides/deploy-udc.mdx
@@ -0,0 +1,273 @@
+---
+title: UDC Appchain Deployment
+---
+
+While the Universal Deployer Contract (UDC) is deployed on Starknet public networks, appchains may need to deploy
+their own instance of the UDC for their own use. This guide will walk you through this process while keeping the
+same final address on all networks.
+
+## Prerequisites
+
+This guide assumes you have:
+
+* Familiarity with [Scarb](https://docs.swmansion.com/scarb/docs.html) and Starknet development environment.
+* A functional account available on the network you’re deploying to.
+* Familiarity with the process of declaring contracts through the [declare transaction](https://docs.starknet.io/resources/transactions-reference/#declare_transaction).
+
+
+For declaring contracts on Starknet, you can use the [sncast](https://foundry-rs.github.io/starknet-foundry/starknet/declare.html) tool from the [starknet-foundry](https://foundry-rs.github.io/starknet-foundry/index.html) project.
+
+
+## Note on the UDC final address
+
+It is important that the Universal Deployer Contract (UDC) in Starknet maintains the same address across all
+networks because essential developer tools like **starkli** and **sncast** rely on this address by default when deploying contracts.
+These tools are widely used in the Starknet ecosystem to streamline and standardize contract deployment workflows.
+
+If the UDC address is consistent, developers can write deployment scripts, CI/CD pipelines, and integrations that work seamlessly
+across testnets, mainnet, and appchains without needing to update configuration files or handle special cases for each
+environment.
+
+In the following sections, we’ll walk you through the process of deploying the UDC on appchains while keeping the same address,
+under one important assumption: **the declared UDC class hash MUST be the same across all networks**.
+Different compiler versions may produce different class hashes for the same contract, so you need to make
+sure you are using the same compiler version to build the UDC class (and the release profile).
+
+The latest version of the UDC available in the `openzeppelin_presets` package was compiled with **Cairo v2.11.4** (release profile) and the resulting class hash is `0x01b2df6d8861670d4a8ca4670433b2418d78169c2947f46dc614e69f333745c8`.
+
+
+If you are using a different compiler version, you need to make sure the class hash is the same as the one above in order to keep the same address across all networks.
+
+
+
+To avoid potential issues by using a different compiler version, you can directly import the contract class deployed on Starknet mainnet and declare it on your appchain. At
+the time of writing, this is not easily achievable with the `sncast` tool, but you can leverage `[starkli](https://book.starkli.rs/declaring-classes)` to do it.
+
+Quick reference:
+
+```bash
+starkli class-by-hash --parse \
+ 0x01b2df6d8861670d4a8ca4670433b2418d78169c2947f46dc614e69f333745c8 \
+ --network mainnet \
+ > udc.json
+```
+
+This will output a `udc.json` file that you can use to declare the UDC on your appchain.
+
+```bash
+starkli declare udc.json --rpc
+```
+
+
+
+## Madara Appchains
+
+[Madara](https://github.com/madara-alliance/madara/blob/main/README.md) is a popular Starknet node implementation that has a friendly and robust interface for building appchains. If
+you are using it for this purpose, you are probably familiar with the [Madara Bootstrapper](https://github.com/madara-alliance/madara/tree/main/bootstrapper#readme), which already declares and
+deploys a few contracts for you when you create a new appchain, including accounts and the UDC.
+
+However, since the UDC was migrated to a new version in June 2025, it’s possible that the appchain was created before
+this change, meaning the UDC on the appchain is an older version. If that’s the case, you can follow the steps below to
+deploy the new UDC.
+
+### 1. Declare and deploy the Bootstrapper
+
+In the Starknet ecosystem, contracts need to be declared before they can be deployed, and deployments can only happen
+either via the `deploy_syscall`, or using a `deploy_account` transaction. The latter would require adding account
+functionality to the UDC, which is not optimal, so we’ll use the `deploy_syscall`, which requires having an account
+with this functionality enabled.
+
+
+Madara declares an account with this functionality enabled as part of the bootstrapping process. You may be able to
+use that implementation directly to skip this step.
+
+
+#### Bootstrapper Contract
+
+The bootstrapper contract is a simple contract that declares the UDC and allows for its deployment via the `deploy_syscall`.
+You can find a reference implementation below:
+
+
+This reference implementation targets Cairo v2.11.4. If you are using a different version of Cairo, you may need to update the code to match your compiler version.
+
+
+```rust
+#[starknet::contract(account)]
+mod UniversalDeployerBootstrapper {
+ use core::num::traits::Zero;
+ use openzeppelin_account::AccountComponent;
+ use openzeppelin_introspection::src5::SRC5Component;
+ use openzeppelin_utils::deployments::calculate_contract_address_from_deploy_syscall;
+ use starknet::{ClassHash, ContractAddress, SyscallResultTrait};
+
+ component!(path: AccountComponent, storage: account, event: AccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ //
+ // Account features (deployable, declarer, and invoker)
+ //
+
+ #[abi(embed_v0)]
+ pub(crate) impl DeployableImpl =
+ AccountComponent::DeployableImpl;
+ #[abi(embed_v0)]
+ impl DeclarerImpl = AccountComponent::DeclarerImpl;
+ #[abi(embed_v0)]
+ impl SRC6Impl = AccountComponent::SRC6Impl;
+ impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ pub account: AccountComponent::Storage,
+ #[substorage(v0)]
+ pub src5: SRC5Component::Storage,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ pub(crate) enum Event {
+ #[flat]
+ AccountEvent: AccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event,
+ }
+
+ #[constructor]
+ pub fn constructor(ref self: ContractState, public_key: felt252) {
+ self.account.initializer(public_key);
+ }
+
+ #[abi(per_item)]
+ #[generate_trait]
+ impl ExternalImpl of ExternalTrait {
+ #[external(v0)]
+ fn deploy_udc(ref self: ContractState, udc_class_hash: ClassHash) {
+ self.account.assert_only_self();
+ starknet::syscalls::deploy_syscall(udc_class_hash, 0, array![].span(), true)
+ .unwrap_syscall();
+ }
+
+ #[external(v0)]
+ fn get_udc_address(ref self: ContractState, udc_class_hash: ClassHash) -> ContractAddress {
+ calculate_contract_address_from_deploy_syscall(
+ 0, udc_class_hash, array![].span(), Zero::zero(),
+ )
+ }
+
+}
+```
+
+#### Deploying the Bootstrapper
+
+This guide assumes you have a functional account available on the network you’re deploying to, and familiarity
+with the process of declaring contracts through the `declare` transaction. To recap, the reason we are deploying
+this bootstrapper account contract is to be able to deploy the UDC via the `deploy_syscall`.
+
+
+sncast v0.45.0 was used in the examples below.
+
+
+As a quick example, if your account is configured for **sncast**, you can declare the bootstrapper contract with the following command:
+
+```bash
+sncast -p declare \
+ --contract-name UniversalDeployerBootstrapper
+```
+
+The bootstrapper implements the `IDeployable` trait, meaning it can be counterfactually deployed. Check out the
+[Counterfactual Deployments](./deployment) guide. Continuing with the **sncast** examples, you can create and deploy the bootstrapper with the following commands:
+
+##### Create the account
+
+```bash
+sncast account create --name bootstrapper \
+ --network \
+ --class-hash \
+ --type oz
+```
+
+##### Deploy it to the network
+
+
+You need to prefund the account with enough funds before you can deploy it.
+
+
+```bash
+sncast account deploy \
+ --network \
+ --name bootstrapper
+```
+
+### 2. Declare and deploy the UDC
+
+Once the bootstrapper is deployed, you can declare and deploy the UDC through it.
+
+#### Declaring the UDC
+
+The UDC source code is available in the `openzeppelin_presets` package. You can copy it to your project and declare it with the following command:
+
+```bash
+sncast -p declare \
+ --contract-name UniversalDeployer
+```
+
+
+If you followed the [Note on the UDC final address](#note-on-the-udc-final-address) section, your declared class hash should be
+`0x01b2df6d8861670d4a8ca4670433b2418d78169c2947f46dc614e69f333745c8`.
+
+
+#### Previewing the UDC address
+
+You can preview the UDC address with the following command:
+
+```bash
+sncast call \
+ --network \
+ --contract-address \
+ --function "get_udc_address" \
+ --arguments ''
+```
+
+If the UDC class hash is the same as the one in the [Note on the UDC final address](#note-on-the-udc-final-address) section,
+the output should be `0x2ceed65a4bd731034c01113685c831b01c15d7d432f71afb1cf1634b53a2125`.
+
+#### Deploying the UDC
+
+Now everything is set up to deploy the UDC. You can use the following command to deploy it:
+
+
+Note that the bootstrapper contract MUST call itself to successfully deploy the UDC, since the `deploy_udc` function is protected.
+
+
+```bash
+sncast \
+ --account bootstrapper \
+ invoke \
+ --network \
+ --contract-address \
+ --function "deploy_udc" \
+ --arguments ''
+```
+
+## Other Appchain providers
+
+If you are using an appchain provider different from Madara, you can follow the same steps to deploy the UDC
+as long as you have access to an account that can declare contracts.
+
+Summarizing, the steps to follow are:
+
+1. Declare the Bootstrapper
+2. Counterfactually deploy the Bootstrapper
+3. Declare the UDC
+4. Preview the UDC address
+5. Deploy the UDC from the Bootstrapper
+
+## Conclusion
+
+By following this guide, you have successfully deployed the Universal Deployer Contract on your appchain while ensuring consistency with
+Starknet’s public networks. Maintaining the same UDC address and class hash across all environments is crucial for seamless contract deployment
+and tooling compatibility, allowing developers to leverage tools like **sncast** and **starkli** without additional configuration. This process not only
+improves the reliability of your deployment workflows but also ensures that your appchain remains compatible with the broader Starknet ecosystem.
+With the UDC correctly deployed, you are now ready to take full advantage of streamlined contract
+deployments and robust developer tooling on your appchain.
diff --git a/docs/content/contracts-cairo/2.x/guides/deployment.mdx b/docs/content/contracts-cairo/2.x/guides/deployment.mdx
new file mode 100644
index 00000000..42a924db
--- /dev/null
+++ b/docs/content/contracts-cairo/2.x/guides/deployment.mdx
@@ -0,0 +1,40 @@
+---
+title: Counterfactual deployments
+---
+
+A counterfactual contract is a contract we can interact with even before actually deploying it on-chain.
+For example, we can send funds or assign privileges to a contract that doesn’t yet exist.
+Why? Because deployments in Starknet are deterministic, allowing us to predict the address where our contract will be deployed.
+We can leverage this property to make a contract pay for its own deployment by simply sending funds in advance. We call this a counterfactual deployment.
+
+This process can be described with the following steps:
+
+