# Table of Contents - [OpenZeppelin Contracts | OpenZeppelin Docs](#openzeppelin-contracts-openzeppelin-docs) - [Contracts Wizard | OpenZeppelin Docs](#contracts-wizard-openzeppelin-docs) - [Overview | OpenZeppelin Docs](#overview-openzeppelin-docs) - [Contracts Wizard | OpenZeppelin Docs](#contracts-wizard-openzeppelin-docs) - [Access Control | OpenZeppelin Docs](#access-control-openzeppelin-docs) - [Community Contracts | OpenZeppelin Docs](#community-contracts-openzeppelin-docs) - [Tokens | OpenZeppelin Docs](#tokens-openzeppelin-docs) - [OpenZeppelin Docs](#openzeppelin-docs) - [Upgrades Plugins | OpenZeppelin Docs](#upgrades-plugins-openzeppelin-docs) - [Using with Upgrades | OpenZeppelin Docs](#using-with-upgrades-openzeppelin-docs) - [ERC-1155 | OpenZeppelin Docs](#erc-1155-openzeppelin-docs) - [ERC-721 | OpenZeppelin Docs](#erc-721-openzeppelin-docs) - [Utilities | OpenZeppelin Docs](#utilities-openzeppelin-docs) - [How to set up on-chain governance | OpenZeppelin Docs](#how-to-set-up-on-chain-governance-openzeppelin-docs) - [ERC-20 | OpenZeppelin Docs](#erc-20-openzeppelin-docs) - [Quickstart | OpenZeppelin Docs](#quickstart-openzeppelin-docs) - [OpenZeppelin Relayer | OpenZeppelin Docs](#openzeppelin-relayer-openzeppelin-docs) - [ERC-4626 | OpenZeppelin Docs](#erc-4626-openzeppelin-docs) - [OpenZeppelin Monitor | OpenZeppelin Docs](#openzeppelin-monitor-openzeppelin-docs) - [Account Abstraction | OpenZeppelin Docs](#account-abstraction-openzeppelin-docs) - [API Reference | OpenZeppelin Docs](#api-reference-openzeppelin-docs) - [ERC721 | OpenZeppelin Docs](#erc721-openzeppelin-docs) - [ERC20 | OpenZeppelin Docs](#erc20-openzeppelin-docs) - [Access | OpenZeppelin Docs](#access-openzeppelin-docs) - [Extending Contracts | OpenZeppelin Docs](#extending-contracts-openzeppelin-docs) - [Cross-chain messaging | OpenZeppelin Docs](#cross-chain-messaging-openzeppelin-docs) - [OpenZeppelin Upgrades Core & CLI | OpenZeppelin Docs](#openzeppelin-upgrades-core-cli-openzeppelin-docs) - [Using with Hardhat | OpenZeppelin Docs](#using-with-hardhat-openzeppelin-docs) - [Backwards Compatibility | OpenZeppelin Docs](#backwards-compatibility-openzeppelin-docs) - [Defender | OpenZeppelin Docs](#defender-openzeppelin-docs) - [Utilities | OpenZeppelin Docs](#utilities-openzeppelin-docs) - [Learn | OpenZeppelin Docs](#learn-openzeppelin-docs) - [ERC-6909 | OpenZeppelin Docs](#erc-6909-openzeppelin-docs) - [Polkadot Parachain Runtimes | OpenZeppelin Docs](#polkadot-parachain-runtimes-openzeppelin-docs) - [Using with Foundry | OpenZeppelin Docs](#using-with-foundry-openzeppelin-docs) - [Networks | OpenZeppelin Docs](#networks-openzeppelin-docs) - [OpenZeppelin Foundry Upgrades API | OpenZeppelin Docs](#openzeppelin-foundry-upgrades-api-openzeppelin-docs) - [Confidential Contracts | OpenZeppelin Docs](#confidential-contracts-openzeppelin-docs) - [Loading Contracts | OpenZeppelin Docs](#loading-contracts-openzeppelin-docs) - [Upgrades | OpenZeppelin Docs](#upgrades-openzeppelin-docs) - [Quick Start Guide | OpenZeppelin Docs](#quick-start-guide-openzeppelin-docs) - [Creating ERC-20 Supply | OpenZeppelin Docs](#creating-erc-20-supply-openzeppelin-docs) - [Functions | OpenZeppelin Docs](#functions-openzeppelin-docs) - [Customization | OpenZeppelin Docs](#customization-openzeppelin-docs) - [Exporting and History | OpenZeppelin Docs](#exporting-and-history-openzeppelin-docs) - [Transaction Proposals | OpenZeppelin Docs](#transaction-proposals-openzeppelin-docs) - [Building New Adapters | OpenZeppelin Docs](#building-new-adapters-openzeppelin-docs) - [Solana Integration | OpenZeppelin Docs](#solana-integration-openzeppelin-docs) - [OpenZeppelin Relayer Roadmap | OpenZeppelin Docs](#openzeppelin-relayer-roadmap-openzeppelin-docs) - [Project Structure | OpenZeppelin Docs](#project-structure-openzeppelin-docs) - [Changelog | OpenZeppelin Docs](#changelog-openzeppelin-docs) - [Uniswap Hooks | OpenZeppelin Docs](#uniswap-hooks-openzeppelin-docs) - [EVM Integration | OpenZeppelin Docs](#evm-integration-openzeppelin-docs) - [OpenZeppelin Contracts for Stylus | OpenZeppelin Docs](#openzeppelin-contracts-for-stylus-openzeppelin-docs) - [API Reference | OpenZeppelin Docs](#api-reference-openzeppelin-docs) - [Frequently Asked Questions | OpenZeppelin Docs](#frequently-asked-questions-openzeppelin-docs) - [Subgraphs | OpenZeppelin Docs](#subgraphs-openzeppelin-docs) - [Stellar Smart Contracts Suite | OpenZeppelin Docs](#stellar-smart-contracts-suite-openzeppelin-docs) - [Contracts for Cairo | OpenZeppelin Docs](#contracts-for-cairo-openzeppelin-docs) - [Configuration | OpenZeppelin Docs](#configuration-openzeppelin-docs) - [Proxy Upgrade Pattern | OpenZeppelin Docs](#proxy-upgrade-pattern-openzeppelin-docs) - [Network Configuration | OpenZeppelin Docs](#network-configuration-openzeppelin-docs) - [Frequently Asked Questions | OpenZeppelin Docs](#frequently-asked-questions-openzeppelin-docs) - [Developing smart contracts | OpenZeppelin Docs](#developing-smart-contracts-openzeppelin-docs) - [Plugins | OpenZeppelin Docs](#plugins-openzeppelin-docs) - [Relayer API Reference | OpenZeppelin Docs](#relayer-api-reference-openzeppelin-docs) - [Writing Upgradeable Contracts | OpenZeppelin Docs](#writing-upgradeable-contracts-openzeppelin-docs) - [Account Modules | OpenZeppelin Docs](#account-modules-openzeppelin-docs) - [Utilities | OpenZeppelin Docs](#utilities-openzeppelin-docs) - [Changelog | OpenZeppelin Docs](#changelog-openzeppelin-docs) - [Contracts for Compact | OpenZeppelin Docs](#contracts-for-compact-openzeppelin-docs) - [Testing Guide | OpenZeppelin Docs](#testing-guide-openzeppelin-docs) - [Project Structure | OpenZeppelin Docs](#project-structure-openzeppelin-docs) - [Architecture Guide | OpenZeppelin Docs](#architecture-guide-openzeppelin-docs) - [Multisig Account | OpenZeppelin Docs](#multisig-account-openzeppelin-docs) - [Quick Start Guide | OpenZeppelin Docs](#quick-start-guide-openzeppelin-docs) - [Error Handling | OpenZeppelin Docs](#error-handling-openzeppelin-docs) - [RPC Client | OpenZeppelin Docs](#rpc-client-openzeppelin-docs) - [OpenZeppelin Hardhat Upgrades API | OpenZeppelin Docs](#openzeppelin-hardhat-upgrades-api-openzeppelin-docs) - [Custom Scripts | OpenZeppelin Docs](#custom-scripts-openzeppelin-docs) - [WebAuthn Smart Accounts | OpenZeppelin Docs](#webauthn-smart-accounts-openzeppelin-docs) - [Proxy | OpenZeppelin Docs](#proxy-openzeppelin-docs) - [Contribution Guidelines | OpenZeppelin Docs](#contribution-guidelines-openzeppelin-docs) - [Changelog | OpenZeppelin Docs](#changelog-openzeppelin-docs) --- # OpenZeppelin Contracts | OpenZeppelin Docs OpenZeppelin Contracts ====================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) OpenZeppelin Contracts is a library of modular, reusable, secure smart contracts for the Ethereum network, written in Solidity. [Getting Started](https://docs.openzeppelin.com/contracts#getting-started) --------------------------------------------------------------------------- [### Contracts Overview\ \ Start working with the OpenZeppelin Contracts Library.](https://docs.openzeppelin.com/contracts/5.x) [### Contracts Wizard\ \ Use the interactive Contracts Wizard to bootstrap your contract and learn about the components offered in OpenZeppelin Contracts.](https://docs.openzeppelin.com/contracts/5.x/wizard) [Core Features](https://docs.openzeppelin.com/contracts#core-features) ----------------------------------------------------------------------- [### Token Standards\ \ Implementations of ERC20, ERC721, ERC1155, and other token standards.](https://docs.openzeppelin.com/contracts/5.x/tokens) [### Access Control\ \ Manage permissions and roles in your smart contracts securely.](https://docs.openzeppelin.com/contracts/5.x/access-control) [### Governance\ \ Build decentralized governance systems for your protocols.](https://docs.openzeppelin.com/contracts/5.x/governance) [### Utilities\ \ Helper contracts and libraries for common blockchain development tasks.](https://docs.openzeppelin.com/contracts/5.x/utilities) [Token Standards](https://docs.openzeppelin.com/contracts#token-standards) --------------------------------------------------------------------------- [### ERC-20\ \ Fungible token standard implementation with extensions and utilities.](https://docs.openzeppelin.com/contracts/5.x/erc20) [### ERC-721\ \ Non-fungible token (NFT) standard with advanced features.](https://docs.openzeppelin.com/contracts/5.x/erc721) [### ERC-1155\ \ Multi-token standard for both fungible and non-fungible tokens.](https://docs.openzeppelin.com/contracts/5.x/erc1155) [### ERC-4626\ \ Tokenized vault standard for yield-bearing assets.](https://docs.openzeppelin.com/contracts/5.x/erc4626) [Advanced Features](https://docs.openzeppelin.com/contracts#advanced-features) ------------------------------------------------------------------------------- [### Account Abstraction\ \ Smart account implementations and account abstraction utilities.](https://docs.openzeppelin.com/contracts/5.x/account-abstraction) [### Upgradeable Contracts\ \ Learn how to build upgradeable smart contracts safely.](https://docs.openzeppelin.com/contracts/5.x/upgradeable) [### Contracts Wizard\ \ Interactive tool to generate smart contracts with custom features.](https://docs.openzeppelin.com/wizard) [### Upgrades Plugins\ \ Tools for deploying and upgrading smart contracts with Hardhat and Foundry.](https://docs.openzeppelin.com/upgrades-plugins) [API Reference](https://docs.openzeppelin.com/contracts#api-reference) ----------------------------------------------------------------------- [### API Overview\ \ Complete API reference for all OpenZeppelin Contracts.](https://docs.openzeppelin.com/contracts/5.x/api) [### ERC20 API\ \ Detailed API documentation for ERC20 tokens and extensions.](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) [### ERC721 API\ \ Complete API reference for ERC721 NFT contracts.](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721) [### Access Control API\ \ API documentation for access control and ownership patterns.](https://docs.openzeppelin.com/contracts/5.x/api/access) [Tools & Integrations](https://docs.openzeppelin.com/contracts#tools--integrations) ------------------------------------------------------------------------------------ [### Relayer\ \ Automate onchain transactions to schedule jobs, batch calls, and relay gasless meta transactions within your self-hosted infrastructure.](https://docs.openzeppelin.com/relayer) [### Monitor\ \ Monitor onchain activity in real time to watch critical events, detect anomalies, trigger alerts on your preferred channels, and set automated responses with Relayer.](https://docs.openzeppelin.com/monitor) [### UI Builder\ \ Spin up user interfaces for any deployed contract. Select the function, auto-generate a React UI with wallet-connect and multi-network support, and export a complete app.](https://docs.openzeppelin.com/ui-builder) [### Community Contracts\ \ Additional contracts and extensions contributed by the community.](https://docs.openzeppelin.com/community-contracts) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x) ### On this page [Getting Started](https://docs.openzeppelin.com/contracts#getting-started) [Core Features](https://docs.openzeppelin.com/contracts#core-features) [Token Standards](https://docs.openzeppelin.com/contracts#token-standards) [Advanced Features](https://docs.openzeppelin.com/contracts#advanced-features) [API Reference](https://docs.openzeppelin.com/contracts#api-reference) [Tools & Integrations](https://docs.openzeppelin.com/contracts#tools--integrations) --- # Contracts Wizard | OpenZeppelin Docs Contracts Wizard ================ A tool for building smart contracts Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Contracts Wizard is a web application to interactively build a contract out of components from OpenZeppelin Contracts. Select the kind of contract that you want, set your parameters and desired features, and the Wizard will generate all of the code necessary. The resulting code is ready to be compiled and deployed, or it can serve as a starting point and customized further with application specific logic. Loading OpenZeppelin Contracts Wizard... [Usage](https://docs.openzeppelin.com/wizard#usage) ---------------------------------------------------- Use the Contracts Wizard here in the docs or at [wizard.openzeppelin.com](https://wizard.openzeppelin.com/) [TypeScript API](https://docs.openzeppelin.com/wizard#typescript-api) ---------------------------------------------------------------------- You can use the programmatic TypeScript API to generate contracts from your own applications. View the API documentation for each smart contract language: * [Solidity](https://github.com/OpenZeppelin/contracts-wizard/blob/master/packages/core/solidity/README.md) * [Cairo](https://github.com/OpenZeppelin/contracts-wizard/blob/master/packages/core/cairo/README.md) * [Stellar](https://github.com/OpenZeppelin/contracts-wizard/blob/master/packages/core/stellar/README.md) * [Stylus](https://github.com/OpenZeppelin/contracts-wizard/blob/master/packages/core/stylus/README.md) [Embedding](https://docs.openzeppelin.com/wizard#embedding) ------------------------------------------------------------ To embed Contracts Wizard on your site, first include the script tag: Then place `` in the body where you want Contracts Wizard to load. Optionally focus on specific tab with the `data-tab` attribute as in ``. For languages other than Solidity, use the `data-lang` attribute, for example: ``. [Upgrades Core & CLI\ \ Previous Page](https://docs.openzeppelin.com/upgrades-plugins/api-core) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/learn) ### On this page [Usage](https://docs.openzeppelin.com/wizard#usage) [TypeScript API](https://docs.openzeppelin.com/wizard#typescript-api) [Embedding](https://docs.openzeppelin.com/wizard#embedding) --- # Overview | OpenZeppelin Docs OpenZeppelin Contracts Overview ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) **A library for secure smart contract development.** Build on a solid foundation of community-vetted code. * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/5.x/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/5.x/erc721) . * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/5.x/access-control) scheme. * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/5.x/utilities) to build custom contracts and complex decentralized systems. OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility) . [Overview](https://docs.openzeppelin.com/contracts/5.x#overview) ----------------------------------------------------------------- ### [Installation](https://docs.openzeppelin.com/contracts/5.x#installation) #### [Hardhat (npm)](https://docs.openzeppelin.com/contracts/5.x#hardhat-npm) $ npm install @openzeppelin/contracts #### [Foundry (git)](https://docs.openzeppelin.com/contracts/5.x#foundry-git) When installing via git, it is a common error to use the `master` branch. This is a development branch that should be avoided in favor of tagged releases. The release process involves security measures that the `master` branch does not guarantee. Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch. $ forge install OpenZeppelin/openzeppelin-contracts Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` ### [Usage](https://docs.openzeppelin.com/contracts/5.x#usage) Once installed, you can use the contracts in the library by importing them: // contracts/MyNFT.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract MyNFT is ERC721 { constructor() ERC721("MyNFT", "MNFT") {} } If you’re new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts) to learn about creating a new project and compiling your contracts. 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](https://docs.openzeppelin.com/contracts/5.x#security) ----------------------------------------------------------------- Please report any security issues you find via our [bug bounty program on Immunefi](https://www.immunefi.com/bounty/openzeppelin) or directly to [security@openzeppelin.org](mailto:security@openzeppelin.org) . The [Security Center](https://contracts.openzeppelin.com/security) contains more details about the secure development process. [Learn More](https://docs.openzeppelin.com/contracts/5.x#learn-more) --------------------------------------------------------------------- The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: * [Access Control](https://docs.openzeppelin.com/contracts/5.x/access-control) : decide who can perform each of the actions on your system. * [Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) : create tradable assets or collectibles, like the well known [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) and [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721) standards. * [Utilities](https://docs.openzeppelin.com/contracts/5.x/utilities) : generic useful tools, including non-overflowing math, signature verification, and trustless paying systems. The [full API](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts' development in the [community forum](https://forum.openzeppelin.com/) . The following articles provide great background reading, though please note, some of the referenced tools have changed as the tooling in the ecosystem continues to rapidly evolve. * [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. * [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. * For a more in-depth dive, you may read the guide [Designing the architecture for your Ethereum application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317) , which discusses how to better structure your application and its relationship to the real world. [Getting Started\ \ Previous Page](https://docs.openzeppelin.com/contracts) [Contracts Wizard\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/wizard) ### On this page [Overview](https://docs.openzeppelin.com/contracts/5.x#overview) [Installation](https://docs.openzeppelin.com/contracts/5.x#installation) [Hardhat (npm)](https://docs.openzeppelin.com/contracts/5.x#hardhat-npm) [Foundry (git)](https://docs.openzeppelin.com/contracts/5.x#foundry-git) [Usage](https://docs.openzeppelin.com/contracts/5.x#usage) [Security](https://docs.openzeppelin.com/contracts/5.x#security) [Learn More](https://docs.openzeppelin.com/contracts/5.x#learn-more) --- # Contracts Wizard | OpenZeppelin Docs OpenZeppelin Contracts Contracts Wizard ================ Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Not sure where to start? Use the interactive generator below to bootstrap your contract and learn about the components offered in OpenZeppelin Contracts. Place the resulting contract in your `contracts` or `src` directory in order to compile it with a tool like Hardhat or Foundry. Consider reading our guide on [Developing Smart Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts) for more guidance! Loading OpenZeppelin Contracts Wizard... [Overview\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x) [Extending Contracts\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/extending-contracts) --- # Access Control | OpenZeppelin Docs OpenZeppelin Contracts Access Control ============== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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`](https://docs.openzeppelin.com/contracts/5.x/access-control#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 provides [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) for implementing ownership in your contracts. // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; contract MyContract is Ownable { constructor(address initialOwner) Ownable(initialOwner) {} function normalThing() public { // anyone can call this normalThing() } function specialThing() public onlyOwner { // only the owner can call specialThing()! } } At deployment, the [`owner`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-owner--) of an `Ownable` contract is set to the provided `initialOwner` parameter. Ownable also lets you: * [`transferOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) from the owner account to a new one, and * [`renounceOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-renounceOwnership--) 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 `onlyOwner` will no longer be callable! Ownable is a simple and effective way to implement access control, but you should be mindful of the dangers associated with transferring the ownership to an incorrect account that can’t interact with this contract anymore. An alternative to this problem is using [`Ownable2Step`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step) ; a variant of Ownable that requires the new owner to explicitly accept the ownership transfer by calling [`acceptOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-acceptOwnership--) . Note that **a contract can also be the owner of another one**! This opens the door to using, for example, a [Gnosis Safe](https://safe.global/) , an [Aragon DAO](https://aragon.org/) , or a totally custom contract that _you_ create. In this way, you can use _composability_ to add additional layers of access control complexity to your contracts. Instead of having a single regular Ethereum account (Externally Owned Account, or EOA) as the owner, you could use a 2-of-3 multisig run by your project leads, for example. Prominent projects in the space, such as [MakerDAO](https://makerdao.com/) , use systems similar to this one. [Role-Based Access Control](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) ------------------------------------------------------------------------------------------------------------------ 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 `onlyOwner`. This check can be enforced through the `onlyRole` modifier. 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. ### [Using `AccessControl`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-accesscontrol) OpenZeppelin Contracts provides [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) for implementing role-based access control. Its usage is straightforward: 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. Here’s a simple example of using `AccessControl` in an [ERC-20 token](https://docs.openzeppelin.com/contracts/5.x/erc20) to define a 'minter' role, which allows accounts that have it create new tokens: // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract AccessControlERC20MintBase is ERC20, AccessControl { // Create a new role identifier for the minter role bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); error CallerNotMinter(address caller); constructor(address minter) ERC20("MyToken", "TKN") { // Grant the minter role to a specified account _grantRole(MINTER_ROLE, minter); } function mint(address to, uint256 amount) public { // Check that the calling account has the minter role if (!hasRole(MINTER_ROLE, msg.sender)) { revert CallerNotMinter(msg.sender); } _mint(to, amount); } } Make sure you fully understand how [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) 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`. Indeed, where `AccessControl` shines is in scenarios where granular permissions are required, which can be implemented by defining _multiple_ roles. Let’s augment our ERC-20 token example by also defining a 'burner' role, which lets accounts destroy tokens, and by using the `onlyRole` modifier: // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract AccessControlERC20Mint is ERC20, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); constructor(address minter, address burner) ERC20("MyToken", "TKN") { _grantRole(MINTER_ROLE, minter); _grantRole(BURNER_ROLE, burner); } function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { _mint(to, amount); } function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { _burn(from, 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](https://docs.openzeppelin.com/contracts/5.x/access-control#granting-and-revoking-roles) The ERC-20 token example above uses `_grantRole`, 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 `hasRole` 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 `grantRole` and `revokeRole` 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, 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 `_setRoleAdmin` is used to select a new admin role. Since it is the admin for all roles by default, and in fact it is also its own admin, this role carries significant risk. To mitigate this risk we provide [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules) , a recommended extension of `AccessControl` that adds a number of enforced security measures for this role: the admin is restricted to a single account, with a 2-step transfer procedure with a delay in between steps. Let’s take a look at the ERC-20 token example, this time taking advantage of the default admin role: // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract AccessControlERC20MintMissing is ERC20, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); constructor() ERC20("MyToken", "TKN") { // Grant the contract deployer the default admin role: it will be able // to grant and revoke any roles _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { _mint(to, amount); } function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { _burn(from, amount); } } 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 `msg.sender`, that same account can call `grantRole` to give minting or burning permission, and `revokeRole` 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. ### [Querying Privileged Accounts](https://docs.openzeppelin.com/contracts/5.x/access-control#querying-privileged-accounts) Because accounts might [grant and revoke roles](https://docs.openzeppelin.com/contracts/5.x/access-control#granting-and-revoking-roles) dynamically, it is not always possible to determine which accounts hold a particular role. This is important as it allows proving certain properties about a system, such as that an administrative account is a multisig or a DAO, or that a certain role has been removed from all users, effectively disabling any associated functionality. Under the hood, `AccessControl` uses `EnumerableSet`, a more powerful variant of Solidity’s `mapping` type, which allows for key enumeration. `getRoleMemberCount` can be used to retrieve the number of accounts that have a particular role, and `getRoleMember` can then be called to get the address of each of these accounts. const minterCount = await myToken.getRoleMemberCount(MINTER_ROLE); const members = []; for (let i = 0; i < minterCount; ++i) { members.push(await myToken.getRoleMember(MINTER_ROLE, i)); } [Delayed operation](https://docs.openzeppelin.com/contracts/5.x/access-control#delayed-operation) -------------------------------------------------------------------------------------------------- Access control is essential to prevent unauthorized access to critical functions. These functions may be used to mint tokens, freeze transfers or perform an upgrade that completely changes the smart contract logic. While [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) and [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) can prevent unauthorized access, they do not address the issue of a misbehaving administrator attacking their own system to the prejudice of their users. This is the issue the [`TimelockController`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController) is addressing. The [`TimelockController`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController) is a proxy that is governed by proposers and executors. When set as the owner/admin/controller of a smart contract, it ensures that whichever maintenance operation is ordered by the proposers is subject to a delay. This delay protects the users of the smart contract by giving them time to review the maintenance operation and exit the system if they consider it is in their best interest to do so. ### [Using `TimelockController`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-timelockcontroller) By default, the address that deployed the [`TimelockController`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController) gets administration privileges over the timelock. This role grants the right to assign proposers, executors, and other administrators. The first step in configuring the [`TimelockController`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController) is to assign at least one proposer and one executor. These can be assigned during construction or later by anyone with the administrator role. These roles are not exclusive, meaning an account can have both roles. Roles are managed using the [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) interface and the `bytes32` values for each role are accessible through the `ADMIN_ROLE`, `PROPOSER_ROLE` and `EXECUTOR_ROLE` constants. There is an additional feature built on top of `AccessControl`: giving the executor role to `address(0)` opens access to anyone to execute a proposal once the timelock has expired. This feature, while useful, should be used with caution. At this point, with both a proposer and an executor assigned, the timelock can perform operations. An optional next step is for the deployer to renounce its administrative privileges and leave the timelock self-administered. If the deployer decides to do so, all further maintenance, including assigning new proposers/schedulers or changing the timelock duration will have to follow the timelock workflow. This links the governance of the timelock to the governance of contracts attached to the timelock, and enforce a delay on timelock maintenance operations. If the deployer renounces administrative rights in favour of timelock itself, assigning new proposers or executors will require a timelocked operation. This means that if the accounts in charge of any of these two roles become unavailable, then the entire contract (and any contract it controls) becomes locked indefinitely. With both the proposer and executor roles assigned and the timelock in charge of its own administration, you can now transfer the ownership/control of any contract to the timelock. A recommended configuration is to grant both roles to a secure governance contract such as a DAO or a multisig, and to additionally grant the executor role to a few EOAs held by people in charge of helping with the maintenance operations. These wallets cannot take over control of the timelock but they can help smoothen the workflow. ### [Minimum delay](https://docs.openzeppelin.com/contracts/5.x/access-control#minimum-delay) Operations executed by the [`TimelockController`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController) are not subject to a fixed delay but rather a minimum delay. Some major updates might call for a longer delay. For example, if a delay of just a few days might be sufficient for users to audit a minting operation, it makes sense to use a delay of a few weeks, or even a few months, when scheduling a smart contract upgrade. The minimum delay (accessible through the [`getMinDelay`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController-getMinDelay--) method) can be updated by calling the [`updateDelay`](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController-updateDelay-uint256-) function. Bear in mind that access to this function is only accessible by the timelock itself, meaning this maintenance operation has to go through the timelock itself. [Access Management](https://docs.openzeppelin.com/contracts/5.x/access-control#access-management) -------------------------------------------------------------------------------------------------- For a system of contracts, better integrated role management can be achieved with an [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) instance. Instead of managing each contract’s permission separately, AccessManager stores all the permissions in a single contract, making your protocol easier to audit and maintain. Although [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) offers a more dynamic solution for adding permissions to your contracts than Ownable, decentralized protocols tend to become more complex after integrating new contract instances and requires you to keep track of permissions separately in each contract. This increases the complexity of permissions management and monitoring across the system. ![Access Control multiple](https://docs.openzeppelin.com/access-control-multiple.svg) Protocols managing permissions in production systems often require more integrated alternatives to fragmented permissions through multiple `AccessControl` instances. ![AccessManager](https://docs.openzeppelin.com/access-manager.svg) The AccessManager is designed around the concept of role and target functions: * Roles are granted to accounts (addresses) following a many-to-many approach for flexibility. This means that each user can have one or multiple roles and multiple users can have the same role. * Access to a restricted target function is limited to one role. A target function is defined by one [function selector](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html#function-selector) on one contract (called target). For a call to be authorized, the caller must bear the role that is assigned to the current target function (contract address + function selector). ![AccessManager functions](https://docs.openzeppelin.com/access-manager-functions.svg) ### [Using `AccessManager`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-accessmanager) OpenZeppelin Contracts provides [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) for managing roles across any number of contracts. The `AccessManager` itself is a contract that can be deployed and used out of the box. It sets an initial admin in the constructor who will be allowed to perform management operations. In order to restrict access to some functions of your contract, you should inherit from the [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged) contract provided along with the manager. This provides the `restricted` modifier that can be used to protect any externally facing function. Note that you will have to specify the address of the AccessManager instance ([`initialAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-constructor-address-) ) in the constructor so the `restricted` modifier knows which manager to use for checking permissions. Here’s a simple example of an [ERC-20 token](https://docs.openzeppelin.com/contracts/5.x/erc20) that defines a `mint` function that is restricted by an [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) : // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract AccessManagedERC20Mint is ERC20, AccessManaged { constructor(address manager) ERC20("MyToken", "TKN") AccessManaged(manager) {} // Minting is restricted according to the manager rules for this function. // The function is identified by its selector: 0x40c10f19. // Calculated with bytes4(keccak256('mint(address,uint256)')) function mint(address to, uint256 amount) public restricted { _mint(to, amount); } } Make sure you fully understand how [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) works before using it or copy-pasting the examples from this guide. Once the managed contract has been deployed, it is now under the manager’s control. The initial admin can then assign the minter role to an address and also allow the role to call the `mint` function. For example, this is demonstrated in the following Javascript code using Ethers.js: const MINTER = 42n; // Roles are uint64 (0 is reserved for the ADMIN_ROLE) await manager.grantRole(MINTER, user, 0); await manager.setTargetFunctionRole( target, ['0x40c10f19'], // bytes4(keccak256('mint(address,uint256)')) MINTER ); Even though each role has its own list of function permissions, each role member (`address`) has an execution delay that will dictate how long the account should wait to execute a function that requires its role. Delayed operations must have the [`schedule`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-schedule-address-bytes-uint48-) function called on them first in the AccessManager before they can be executed, either by calling to the target function or using the AccessManager’s [`execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) function. Additionally, roles can have a granting delay that prevents adding members immediately. The AccessManager admins can set this grant delay as follows: const HOUR = 60 * 60; const GRANT_DELAY = 24 * HOUR; const EXECUTION_DELAY = 5 * HOUR; const ACCOUNT = "0x..."; await manager.connect(initialAdmin).setGrantDelay(MINTER, GRANT_DELAY); await manager.connect(initialAdmin).grantRole(MINTER, ACCOUNT, EXECUTION_DELAY); Note that roles do not define a name. As opposed to the [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) case, roles are identified as numeric values instead of being hardcoded in the contract as `bytes32` values. It is still possible to allow for tooling discovery (e.g. for role exploration) using role labeling with the [`labelRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-labelRole-uint64-string-) function. await manager.labelRole(MINTER, "MINTER"); Given the admins of the `AccessManaged` can modify all of its permissions, it’s recommended to keep only a single admin address secured under a multisig or governance layer. To achieve this, it is possible for the initial admin to set up all the required permissions, targets, and functions, assign a new admin, and finally renounce its admin role. For improved incident response coordination, the manager includes a mode where administrators can completely close a target contract. When closed, all calls to restricted target functions in a target contract will revert. Closing and opening contracts don’t alter any of their settings, neither permissions nor delays. Particularly, the roles required for calling specific target functions are not modified. This mode is useful for incident response operations that require temporarily shutting down a contract in order to evaluate emergencies and reconfigure permissions. const target = await myToken.getAddress(); await manager.setTargetClosed(target, true); await manager.setTargetClosed(target, false); Even if an `AccessManager` defines permissions for a target function, these won’t be applied if the managed contract instance is not using the [`restricted`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-restricted--) modifier for that function, or if its manager is a different one. ### [Role Admins and Guardians](https://docs.openzeppelin.com/contracts/5.x/access-control#role-admins-and-guardians) An important aspect of the AccessControl contract is that roles aren’t granted nor revoked by role members. Instead, it relies on the concept of a role admin for granting and revoking. In the case of the `AccessManager`, the same rule applies and only the role’s admins are able to call [grant](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-grantRole-uint64-address-uint32-) and [revoke](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-revokeRole-uint64-address-) functions. Note that calling these functions will be subject to the execution delay that the executing role admin has. Additionally, the `AccessManager` stores a _guardian_ as an extra protection for each role. This guardian has the ability to cancel operations that have been scheduled by any role member with an execution delay. Consider that a role will have its initial admin and guardian default to the `ADMIN_ROLE` (`0`). Be careful with the members of `ADMIN_ROLE`, since it acts as the default admin and guardian for every role. A misbehaved guardian can cancel operations at will, affecting the AccessManager’s operation. ### [Manager configuration](https://docs.openzeppelin.com/contracts/5.x/access-control#manager-configuration) The `AccessManager` provides a built-in interface for configuring permission settings that can be accessed by its `ADMIN_ROLE` members. This configuration interface includes the following functions: * Add a label to a role using the [`labelRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-labelRole-uint64-string-) function. * Assign the admin and guardian of a role with [`setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleAdmin-uint64-uint64-) and [`setRoleGuardian`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleGuardian-uint64-uint64-) . * Set each role’s grant delay via [`setGrantDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) . As an admin, some actions will require a delay. Similar to each member’s execution delay, some admin operations require waiting for execution and should follow the [`schedule`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-schedule-address-bytes-uint48-) and [`execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) workflow. More specifically, these delayed functions are those for configuring the settings of a specific target contract. The delay applied to these functions can be adjusted by the manager admins with [`setTargetAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetAdminDelay-address-uint32-) . The delayed admin actions are: * Updating an `AccessManaged` contract [authority](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-authority--) using [`updateAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-updateAuthority-address-address-) . * Closing or opening a target via [`setTargetClosed`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetClosed-address-bool-) . * Changing permissions of whether a role can call a target function with [`setTargetFunctionRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetFunctionRole-address-bytes4---uint64-) . ### [Using with Ownable](https://docs.openzeppelin.com/contracts/5.x/access-control#using-with-ownable) Contracts already inheriting from [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) can migrate to AccessManager by transferring ownership to the manager. After that, all calls to functions with the `onlyOwner` modifier should be called through the manager’s [`execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) function, even if the caller doesn’t require a delay. await ownable.connect(owner).transferOwnership(accessManager); ### [Using with AccessControl](https://docs.openzeppelin.com/contracts/5.x/access-control#using-with-accesscontrol) For systems already using [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) , the `DEFAULT_ADMIN_ROLE` can be granted to the `AccessManager` after revoking every other role. Subsequent calls should be made through the manager’s [`execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) method, similar to the Ownable case. await accessControl.connect(admin).revokeRole(MINTER_ROLE, account); await accessControl.connect(admin).grantRole(DEFAULT_ADMIN_ROLE, accessManager); await accessControl.connect(admin).renounceRole(DEFAULT_ADMIN_ROLE, admin); [Backwards Compatibility\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/account-abstraction) ### On this page [Ownership and `Ownable`](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) [Role-Based Access Control](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) [Using `AccessControl`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-accesscontrol) [Granting and Revoking Roles](https://docs.openzeppelin.com/contracts/5.x/access-control#granting-and-revoking-roles) [Querying Privileged Accounts](https://docs.openzeppelin.com/contracts/5.x/access-control#querying-privileged-accounts) [Delayed operation](https://docs.openzeppelin.com/contracts/5.x/access-control#delayed-operation) [Using `TimelockController`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-timelockcontroller) [Minimum delay](https://docs.openzeppelin.com/contracts/5.x/access-control#minimum-delay) [Access Management](https://docs.openzeppelin.com/contracts/5.x/access-control#access-management) [Using `AccessManager`](https://docs.openzeppelin.com/contracts/5.x/access-control#using-accessmanager) [Role Admins and Guardians](https://docs.openzeppelin.com/contracts/5.x/access-control#role-admins-and-guardians) [Manager configuration](https://docs.openzeppelin.com/contracts/5.x/access-control#manager-configuration) [Using with Ownable](https://docs.openzeppelin.com/contracts/5.x/access-control#using-with-ownable) [Using with AccessControl](https://docs.openzeppelin.com/contracts/5.x/access-control#using-with-accesscontrol) --- # Community Contracts | OpenZeppelin Docs Community Contracts =================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) **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](https://docs.openzeppelin.com/community-contracts#overview) ----------------------------------------------------------------------- ### [Installation](https://docs.openzeppelin.com/community-contracts#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)](https://docs.openzeppelin.com/community-contracts#foundry-git) $ forge install OpenZeppelin/openzeppelin-community-contracts Make sure to add `@openzeppelin/community-contracts/=lib/openzeppelin-community-contracts/contracts/` in `remappings.txt.` ### [Usage](https://docs.openzeppelin.com/community-contracts#usage) Once installed, you can use the contracts in the library by importing them: // contracts/MyStablecoinAllowlist.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; import {ERC20Allowlist, ERC20} from "@openzeppelin/community-contracts/token/ERC20/extensions/ERC20Allowlist.sol"; contract MyStablecoinAllowlist is ERC20Allowlist, AccessManaged { constructor(address initialAuthority) ERC20("MyStablecoin", "MST") AccessManaged(initialAuthority) {} function allowUser(address user) public restricted { _allowUser(user); } function disallowUser(address user) public restricted { _disallowUser(user); } } 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](https://docs.openzeppelin.com/community-contracts#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. [Utilities\ \ Previous Page](https://docs.openzeppelin.com/contracts/3.x/utilities) [Modules\ \ Next Page](https://docs.openzeppelin.com/community-contracts/account-modules) ### On this page [Overview](https://docs.openzeppelin.com/community-contracts#overview) [Installation](https://docs.openzeppelin.com/community-contracts#installation) [Foundry (git)](https://docs.openzeppelin.com/community-contracts#foundry-git) [Usage](https://docs.openzeppelin.com/community-contracts#usage) [Security](https://docs.openzeppelin.com/community-contracts#security) --- # Tokens | OpenZeppelin Docs OpenZeppelin Contracts Tokens ====== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Ah, the "token": blockchain’s most powerful and most misunderstood tool. A token is a _representation of something in the blockchain_. This something can be money, time, services, shares in a company, a virtual pet, anything. By representing things as tokens, we can allow smart contracts to interact with them, exchange them, create or destroy them. [But First, ~Coffee~ a Primer on Token Contracts](https://docs.openzeppelin.com/contracts/5.x/tokens#but-first-coffee-a-primer-on-token-contracts) --------------------------------------------------------------------------------------------------------------------------------------------------- Much of the confusion surrounding tokens comes from two concepts getting mixed up: _token contracts_ and the actual _tokens_. A _token contract_ is simply an Ethereum smart contract. "Sending tokens" actually means "calling a method on a smart contract that someone wrote and deployed". At the end of the day, a token contract is not much more than a mapping of addresses to balances, plus some methods to add and subtract from those balances. It is these balances that represent the _tokens_ themselves. Someone "has tokens" when their balance in the token contract is non-zero. That’s it! These balances could be considered money, experience points in a game, deeds of ownership, or voting rights, and each of these tokens would be stored in different token contracts. [Different Kinds of Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) ---------------------------------------------------------------------------------------------------------- Note that there’s a big difference between having two voting rights and two deeds of ownership: each vote is equal to all others, but houses usually are not! This is called [fungibility](https://en.wikipedia.org/wiki/Fungibility) . _Fungible goods_ are equivalent and interchangeable, like Ether, fiat currencies, and voting rights. _Non-fungible_ goods are unique and distinct, like deeds of ownership, or collectibles. In a nutshell, when dealing with non-fungibles (like your house) you care about _which ones_ you have, while in fungible assets (like your bank account statement) what matters is _how much_ you have. [Standards](https://docs.openzeppelin.com/contracts/5.x/tokens#standards) -------------------------------------------------------------------------- Even though the concept of a token is simple, they have a variety of complexities in the implementation. Because everything in Ethereum is just a smart contract, and there are no rules about what smart contracts have to do, the community has developed a variety of **standards** (called EIPs or ERCs) for documenting how a contract can interoperate with other contracts. You’ve probably heard of the ERC-20 or ERC-721 token standards, and that’s why you’re here. Head to our specialized guides to learn more about these: * [ERC-20](https://docs.openzeppelin.com/contracts/5.x/erc20) : the most widespread token standard for fungible assets, albeit somewhat limited by its simplicity. * [ERC-721](https://docs.openzeppelin.com/contracts/5.x/erc721) : the de-facto solution for non-fungible tokens, often used for collectibles and games. * [ERC-1155](https://docs.openzeppelin.com/contracts/5.x/erc1155) : a novel standard for multi-tokens, allowing for a single contract to represent multiple fungible and non-fungible tokens, along with batched operations for increased gas efficiency. [Multisig\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/multisig) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc20) ### On this page [But First, ~Coffee~ a Primer on Token Contracts](https://docs.openzeppelin.com/contracts/5.x/tokens#but-first-coffee-a-primer-on-token-contracts) [Different Kinds of Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) [Standards](https://docs.openzeppelin.com/contracts/5.x/tokens#standards) --- # OpenZeppelin Docs OpenZeppelin Documentation ========================== Build secure blockchain applications with industry-standard smart contracts and developer tools Smart Contracts --------------- [Contracts Library Icon\ \ OpenZeppelin Solidity Contracts\ -------------------------------\ \ The world's most trusted library of Solidity smart contracts for Ethereum and EVM blockchains, powering nearly every onchain application.\ \ →](https://docs.openzeppelin.com/contracts) [Contracts Upgrades Icon\ \ ### Upgrades Plugins\ \ Deploy upgradeable contracts using Hardhat and Foundry plugins that automate proxy deployments, enforce safety checks, and more.](https://docs.openzeppelin.com/upgrades-plugins) [Contracts Wizard Icon\ \ ### Contracts Wizard\ \ Configure and generate smart contracts in seconds through an interactive interface.](https://docs.openzeppelin.com/wizard) [Contracts MCP Icon\ \ ### Contracts MCP\ \ Write secure smart contracts that follow OpenZeppelin standards with your favorite AI assistant.](https://mcp.openzeppelin.com/) [Ethereum Icon\ \ Starknet Icon\ \ Stellar Icon\ \ Zama Icon\ \ +4\ \ Contracts libraries are also available for Starknet, Stellar, Zama FHEVM, and more blockchains\ \ Explore all](https://docs.openzeppelin.com/#ecosystems) Open Source Tools ----------------- [Relayers Icon\ \ ### Relayer\ \ Automate onchain transactions to schedule jobs, batch calls, and relay gasless meta transactions within your self-hosted infrastructure.](https://docs.openzeppelin.com/relayer) [Monitor Icon\ \ ### Monitor\ \ Monitor onchain activity in real time to watch critical events, detect anomalies, trigger alerts on your preferred channels, and set automated responses with Relayer.](https://docs.openzeppelin.com/monitor) [Transaction Proposal Icon\ \ ### UI Builder\ \ Spin up user interfaces for any deployed contract. Select the function, auto-generate a React UI with wallet-connect and multi-network support, and export a complete app.](https://docs.openzeppelin.com/ui-builder) [Defender Icon\ \ ### Defender\ \ Code, audit, deploy, monitor, and operate blockchain applications with OpenZeppelin's legacy developer security platform (maintenance mode).](https://docs.openzeppelin.com/defender) Blockchains and Developer Ecosystems ------------------------------------ Choose your blockchain platform to explore available contracts and tools [Ethereum Icon\ \ ### Ethereum & EVM\ \ Build with Solidity smart contracts and developer tools for Ethereum and EVM chains](https://docs.openzeppelin.com/contracts) [Starknet Icon\ \ ### Starknet\ \ Develop Cairo smart contracts to build apps on Starknet zero-knowledge Layer 2](https://docs.openzeppelin.com/contracts-cairo) [Arbitrum Icon\ \ ### Arbitrum Stylus\ \ Write high-performance smart contracts in Rust on the EVM with Arbitrum Stylus](https://docs.openzeppelin.com/contracts-stylus) [Uniswap Icon\ \ ### Uniswap Hooks\ \ Customize Uniswap V4 hooks with advanced, audited modules](https://docs.openzeppelin.com/uniswap-hooks) [Stellar Icon\ \ ### Stellar\ \ Build with Soroban smart contracts and developer tools on Stellar](https://docs.openzeppelin.com/stellar-contracts) [Midnight Icon\ \ ### Midnight\ \ Build privacy-preserving smart contracts in Compact for the Midnight blockchain](https://docs.openzeppelin.com/contracts-compact) [Polkadot\ \ ### Polkadot\ \ Develop smart contracts and parachain runtimes for Polkadot and Substrate](https://docs.openzeppelin.com/substrate-runtimes) [Zama Icon\ \ ### Zama FHEVM\ \ Implement fully homomorphic encryption for confidential smart contracts in Solidity](https://docs.openzeppelin.com/confidential-contracts) Learn & Play ------------ Master smart contract security through interactive challenges [Ethernaut Icon\ \ ### Ethernaut CTF\ \ Learn smart contract security by hacking. Ethernaut is a capture-the-flag game where each level is a vulnerable contract to exploit. Master real-world attack vectors and defense strategies through hands-on challenges.\ \ →](https://ethernaut.openzeppelin.com/) Community & Support ------------------- Connect with the community for technical discussions and support [Annotation Dots Icon\ \ ### Forum\ \ Engage in technical deep-dives and architectural discussions. Get detailed answers, share your implementations, and learn from experienced developers building in production.](https://forum.openzeppelin.com/) [### Telegram\ \ Get quick help and connect with the community in real-time. Ask questions, share updates, and stay informed about the latest OpenZeppelin developments and announcements.](https://t.me/openzeppelin_tg) --- # Upgrades Plugins | OpenZeppelin Docs Upgrades Plugins ================ Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) _**Integrate upgrades into your existing workflow.**_ Plugins for [Hardhat](https://hardhat.org/) and [Foundry](https://book.getfoundry.sh/) to deploy and manage upgradeable contracts on Ethereum. * Deploy upgradeable contracts. * Upgrade deployed contracts. * Manage proxy admin rights. * Easily use in tests. Upgrades Plugins are only a part of a comprehensive set of OpenZeppelin tools for deploying and securing upgradeable smart contracts. [Check out the full list of resources](https://docs.openzeppelin.com/upgrades) . [Overview](https://docs.openzeppelin.com/upgrades-plugins#overview) -------------------------------------------------------------------- ### [Installation and Usage](https://docs.openzeppelin.com/upgrades-plugins#installation-and-usage) See the documentation for [Hardhat Upgrades](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades) or [Foundry Upgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades) . [How the plugins work](https://docs.openzeppelin.com/upgrades-plugins#how-the-plugins-work) -------------------------------------------------------------------------------------------- The plugins provide functions which take care of managing upgradeable deployments of your contracts. For example, `deployProxy` does the following: 1. Validates that the implementation is [upgrade safe](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-a-contract-to-be-upgrade-safe) . 2. Deploys the [implementation contract](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-an-implementation-contract) . Note that the Hardhat plugin first checks if there is an implementation contract deployed with the same bytecode, and skips this step if one is already deployed. 3. Creates and initializes the proxy contract, along with a [proxy admin](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy-admin) (if needed). And when you call `upgradeProxy`: 1. Validates that the new implementation is [upgrade safe](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-a-contract-to-be-upgrade-safe) and is [compatible](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-an-implementation-to-be-compatible) with the previous one. 2. Deploys the new [implementation contract](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-an-implementation-contract) . Note that the Hardhat plugin first checks if there is an implementation contract deployed with the same bytecode, and skips this step if one is already deployed. 3. Upgrades the proxy to use the new implementation contract. The Hardhat plugin keeps track of all the implementation contracts you have deployed in an `.openzeppelin` folder in the project root, as well as the proxy admin. You will find one file per network there. It is advised that you commit to source control the files for all networks except the development ones (you may see them as `.openzeppelin/unknown-*.json`). The Foundry plugin does not keep track of implementation contracts, but requires you to [define reference contracts](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades?tab=readme-ov-file#before-running) in order to validate new versions of implementations for upgrade safety. [Proxy patterns](https://docs.openzeppelin.com/upgrades-plugins#proxy-patterns) -------------------------------------------------------------------------------- The plugins support the UUPS, transparent, and beacon proxy patterns. UUPS and transparent proxies are upgraded individually, whereas any number of beacon proxies can be upgraded atomically at the same time by upgrading the beacon that they point to. For more details on the different proxy patterns available, see the documentation for [Proxies](https://docs.openzeppelin.com/contracts/5.x/api/proxy) . For UUPS and transparent proxies, use `deployProxy` and `upgradeProxy`. For beacon proxies, use `deployBeacon`, `deployBeaconProxy`, and `upgradeBeacon`. See the documentation for [Hardhat Upgrades](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades) and [Foundry Upgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades) for examples. [Managing ownership](https://docs.openzeppelin.com/upgrades-plugins#managing-ownership) ---------------------------------------------------------------------------------------- Transparent proxies define an _admin_ address which has the rights to upgrade them. By default, the admin is a [proxy admin contract](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy-admin) deployed behind the scenes. Keep in mind that the _admin_ of a proxy can only upgrade it, but not interact with the implementation contract. Read [Transparent Proxies and Function Clashes](https://docs.openzeppelin.com/upgrades-plugins/proxies#transparent-proxies-and-function-clashes) for more info on this restriction. The proxy admin contract also defines an _owner_ address which has the rights to operate it. By default, the proxy admin’s owner is the `initialOwner` address used during deployment of the transparent proxy if provided, otherwise it is the externally owned account used during deployment. You can change the proxy admin owner by calling the `admin.transferProxyAdminOwnership` function in the Hardhat plugin, or the `transferOwnership` function of the proxy admin contract if using Foundry. Do not reuse an already deployed `ProxyAdmin`. Before `@openzeppelin/contracts` version 5.x, the address provided to transparent proxies was an `initialAdmin` as opposed to an `initialOwner` of a newly deployed `ProxyAdmin`. Reusing a `ProxyAdmin` will disable upgradeability in your contract. UUPS and beacon proxies do not use admin addresses. UUPS proxies rely on an [`_authorizeUpgrade`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address-) function to be overridden to include access restriction to the upgrade mechanism, whereas beacon proxies are upgradable only by the owner of their corresponding beacon. Once you have transferred the rights to upgrade a proxy or beacon to another address, you can still use your local setup to validate and deploy the implementation contract. The plugins include a `prepareUpgrade` function that will validate that the new implementation is upgrade-safe and compatible with the previous one, and deploy it using your local Ethereum account. You can then execute the upgrade itself from the admin or owner address. You can also use the `defender.proposeUpgrade` or `defender.proposeUpgradeWithApproval` functions to automatically set up the upgrade in [OpenZeppelin Defender](https://docs.openzeppelin.com/defender) . ### On this page [Overview](https://docs.openzeppelin.com/upgrades-plugins#overview) [Installation and Usage](https://docs.openzeppelin.com/upgrades-plugins#installation-and-usage) [How the plugins work](https://docs.openzeppelin.com/upgrades-plugins#how-the-plugins-work) [Proxy patterns](https://docs.openzeppelin.com/upgrades-plugins#proxy-patterns) [Managing ownership](https://docs.openzeppelin.com/upgrades-plugins#managing-ownership) --- # Using with Upgrades | OpenZeppelin Docs OpenZeppelin Contracts Using with Upgrades =================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) If your contract is going to be deployed with upgradeability, such as using the [OpenZeppelin Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) , you will need to use the Upgradeable variant of OpenZeppelin Contracts. This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository [OpenZeppelin/openzeppelin-contracts-upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) . It uses `@openzeppelin/contracts` as a peer dependency. It follows all of the rules for [Writing Upgradeable Contracts](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable) : constructors are replaced by initializer functions, state variables are initialized in initializer functions, and we additionally check for storage incompatibilities across minor versions. OpenZeppelin provides a full suite of tools for deploying and securing upgradeable smart contracts. [Check out the full list of resources](https://docs.openzeppelin.com/upgrades) . [Overview](https://docs.openzeppelin.com/contracts/5.x/upgradeable#overview) ----------------------------------------------------------------------------- ### [Installation](https://docs.openzeppelin.com/contracts/5.x/upgradeable#installation) $ npm install @openzeppelin/contracts-upgradeable @openzeppelin/contracts ### [Usage](https://docs.openzeppelin.com/contracts/5.x/upgradeable#usage) The Upgradeable package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`. -import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -contract MyCollectible is ERC721 { +contract MyCollectible is ERC721Upgradeable { Interfaces and libraries are not included in the Upgradeable package, but are instead imported from the main OpenZeppelin Contracts package. Constructors are replaced by internal initializer functions following the naming convention `__ContractName_init`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend. - constructor() ERC721("MyCollectible", "MCO") public { + function initialize() initializer public { + __ERC721_init("MyCollectible", "MCO"); } Use with multiple inheritance requires special attention. See the section below titled [Multiple Inheritance](https://docs.openzeppelin.com/contracts/5.x/upgradeable#multiple-inheritance) . Once this contract is set up and compiled, you can deploy it using the [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) . The following snippet shows an example deployment script using Hardhat. const { ethers, upgrades } = require("hardhat"); async function main() { const MyCollectible = await ethers.getContractFactory("MyCollectible"); const mc = await upgrades.deployProxy(MyCollectible); await mc.waitForDeployment(); console.log("MyCollectible deployed to:", await mc.getAddress()); } main(); [Further Notes](https://docs.openzeppelin.com/contracts/5.x/upgradeable#further-notes) --------------------------------------------------------------------------------------- ### [Multiple Inheritance](https://docs.openzeppelin.com/contracts/5.x/upgradeable#multiple-inheritance) Initializer functions are not linearized by the compiler like constructors. Because of this, each `__ContractName_init` function embeds the linearized calls to all parent initializers. As a consequence, calling two of these `init` functions can potentially initialize the same contract twice. The function `__ContractName_init_unchained` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins. ### [Namespaced Storage](https://docs.openzeppelin.com/contracts/5.x/upgradeable#namespaced-storage) You may notice that contracts use a struct with the `@custom:storage-location erc7201:` annotation to store the contract’s state variables. This follows the [ERC-7201: Namespaced Storage Layout](https://eips.ethereum.org/EIPS/eip-7201) pattern, where each contract has its own storage layout in a namespace that is separate from other contracts in the inheritance chain. Without namespaced storage, it isn’t safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in [Writing Upgradeable Contracts](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts) . The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage. [Extending Contracts\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/extending-contracts) [Backwards Compatibility\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility) ### On this page [Overview](https://docs.openzeppelin.com/contracts/5.x/upgradeable#overview) [Installation](https://docs.openzeppelin.com/contracts/5.x/upgradeable#installation) [Usage](https://docs.openzeppelin.com/contracts/5.x/upgradeable#usage) [Further Notes](https://docs.openzeppelin.com/contracts/5.x/upgradeable#further-notes) [Multiple Inheritance](https://docs.openzeppelin.com/contracts/5.x/upgradeable#multiple-inheritance) [Namespaced Storage](https://docs.openzeppelin.com/contracts/5.x/upgradeable#namespaced-storage) --- # ERC-1155 | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) ERC-1155 ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) ERC-1155 is a novel token standard that aims to take the best from previous standards to create a [**fungibility-agnostic**](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) and **gas-efficient** [token contract](https://docs.openzeppelin.com/contracts/5.x/tokens#but-first-coffee-a-primer-on-token-contracts) . ERC-1155 draws ideas from all of [ERC-20](https://docs.openzeppelin.com/contracts/5.x/erc20) , [ERC-721](https://docs.openzeppelin.com/contracts/5.x/erc721) , and [ERC-777](https://eips.ethereum.org/EIPS/eip-777) . If you’re unfamiliar with those standards, head to their guides before moving on. [Multi Token Standard](https://docs.openzeppelin.com/contracts/5.x/erc1155#multi-token-standard) ------------------------------------------------------------------------------------------------- The distinctive feature of ERC-1155 is that it uses a single smart contract to represent multiple tokens at once. This is why its [`balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-balanceOf-address-uint256-) function differs from ERC-20’s and ERC-777’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 ERC-721 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 ERC-721 [`balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#IERC721-balanceOf-address-) function refers to _how many different tokens_ an account has, not how many of each. On the other hand, in ERC-1155 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 ERC-1155 token contract can hold the entire system state, reducing deployment costs and complexity. [Batch Operations](https://docs.openzeppelin.com/contracts/5.x/erc1155#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, [`balanceOfBatch`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-balanceOfBatch-address---uint256---) and [`safeBatchTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-safeBatchTransferFrom-address-address-uint256---uint256---bytes-) , that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive. In the spirit of the standard, we’ve also included batch operations in the non-standard functions, such as [`_mintBatch`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_mintBatch-address-uint256---uint256---bytes-) . [Constructing an ERC-1155 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc1155#constructing-an-erc-1155-token-contract) --------------------------------------------------------------------------------------------------------------------------------------- We’ll use ERC-1155 to track multiple items in our game, which will each have their own unique attributes. We mint all items to the deployer of the contract, which we can later transfer to players. Players are free to keep their tokens or trade them with other people as they see fit, as they would any other asset on the blockchain! For simplicity, we will mint all items in the constructor, but you could add minting functionality to the contract to mint on demand to players. For an overview of minting mechanisms, check out [Creating ERC-20 Supply](https://docs.openzeppelin.com/contracts/5.x/erc20-supply) . Here’s what a contract for tokenized items might look like: // contracts/GameItems.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; contract GameItems is ERC1155 { uint256 public constant GOLD = 0; uint256 public constant SILVER = 1; uint256 public constant THORS_HAMMER = 2; uint256 public constant SWORD = 3; uint256 public constant SHIELD = 4; constructor() ERC1155("https://game.example/api/item/{id}.json") { _mint(msg.sender, GOLD, 10 ** 18, ""); _mint(msg.sender, SILVER, 10 ** 27, ""); _mint(msg.sender, THORS_HAMMER, 1, ""); _mint(msg.sender, SWORD, 10 ** 9, ""); _mint(msg.sender, SHIELD, 10 ** 9, ""); } } Note that for our Game Items, Gold is a fungible token whilst Thor’s Hammer is a non-fungible token as we minted only one. The [`ERC1155`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155) contract includes the optional extension [`IERC1155MetadataURI`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155MetadataURI) . That’s where the [`uri`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155MetadataURI-uri-uint256-) function comes from: we use it to retrieve the metadata uri. Also note that, unlike ERC-20, ERC-1155 lacks a `decimals` field, since each token is distinct and cannot be partitioned. Once deployed, we will be able to query the deployer’s balance: > gameItems.balanceOf(deployerAddress,3) 1000000000 We can transfer items to player accounts: > gameItems.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0") > gameItems.balanceOf(playerAddress, 2) 1 > gameItems.balanceOf(deployerAddress, 2) 0 We can also batch transfer items to player accounts and get the balance of batches: > gameItems.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0") > gameItems.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4]) [50,100,1,1,1] The metadata uri can be obtained: > gameItems.uri(2) "https://game.example/api/item/{id}.json" The `uri` can include the string `+id+` which clients must replace with the actual token ID, in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters. For token ID `2` and uri `+https://game.example/api/item/id.json+` clients would replace `+id+` with `0000000000000000000000000000000000000000000000000000000000000002` to retrieve JSON at `https://game.example/api/item/0000000000000000000000000000000000000000000000000000000000000002.json`. The JSON document for token ID 2 might look something like: { "name": "Thor's hammer", "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", "image": "https://game.example/item-id-8u5h2m.png", "strength": 20 } For more information about the metadata JSON Schema, check out the [ERC-1155 Metadata URI JSON Schema](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema) . You’ll notice that the item’s information is included in the metadata, but that information isn’t on-chain! So a game developer could change the underlying metadata, changing the rules of the game! If you’d like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a [`Base64`](https://docs.openzeppelin.com/contracts/5.x/utilities#base64) Data URI with the JSON schema encoded. You could also leverage IPFS to store the URI information, but these techniques are out of the scope of this overview guide [Sending Tokens to Contracts](https://docs.openzeppelin.com/contracts/5.x/erc1155#sending-tokens-to-contracts) --------------------------------------------------------------------------------------------------------------- A key difference when using [`safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) is that token transfers to other contracts may revert with the following custom error: ERC1155InvalidReceiver("
") This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC-1155 protocol, so transfers to it are disabled to **prevent tokens from being locked forever**. As an example, [the Golem contract currently holds over 350k `GNT` tokens](https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d) , and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error. In order for our contract to receive ERC-1155 tokens we can inherit from the convenience contract [`ERC1155Holder`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155Holder) which handles the registering for us. However, we need to remember to implement functionality to allow tokens to be transferred out of our contract: // contracts/MyERC115HolderContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; contract MyERC115HolderContract is ERC1155Holder {} We can also implement more complex scenarios using the [`onERC1155Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-) and [`onERC1155BatchReceived`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-) functions. [ERC-721\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc721) [ERC-4626\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc4626) ### On this page [Multi Token Standard](https://docs.openzeppelin.com/contracts/5.x/erc1155#multi-token-standard) [Batch Operations](https://docs.openzeppelin.com/contracts/5.x/erc1155#batch-operations) [Constructing an ERC-1155 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc1155#constructing-an-erc-1155-token-contract) [Sending Tokens to Contracts](https://docs.openzeppelin.com/contracts/5.x/erc1155#sending-tokens-to-contracts) --- # ERC-721 | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) ERC-721 ======= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) We’ve discussed how you can make a _fungible_ token using [ERC-20](https://docs.openzeppelin.com/contracts/5.x/erc20) , but what if not all tokens are alike? This comes up in situations like **real estate**, **voting rights**, or **collectibles**, where some items are valued more than others, due to their usefulness, rarity, etc. ERC-721 is a standard for representing ownership of [_non-fungible_ tokens](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) , that is, where each token is unique. ERC-721 is a more complex standard than ERC-20, with multiple optional extensions, and is split across a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the [API Reference](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721) to learn more about these. [Constructing an ERC-721 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc721#constructing-an-erc-721-token-contract) ------------------------------------------------------------------------------------------------------------------------------------ We’ll use ERC-721 to track items in our game, which will each have their own unique attributes. Whenever one is to be awarded to a player, it will be minted and sent to them. Players are free to keep their token or trade it with other people as they see fit, as they would any other asset on the blockchain! Please note any account can call `awardItem` to mint items. To restrict what accounts can mint items we can add [Access Control](https://docs.openzeppelin.com/contracts/5.x/access-control) . Here’s what a contract for tokenized items might look like: // contracts/GameItem.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC721URIStorage, ERC721} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; contract GameItem is ERC721URIStorage { uint256 private _nextTokenId; constructor() ERC721("GameItem", "ITM") {} function awardItem(address player, string memory tokenURI) public returns (uint256) { uint256 tokenId = _nextTokenId++; _mint(player, tokenId); _setTokenURI(tokenId, tokenURI); return tokenId; } } The [`ERC721URIStorage`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721URIStorage) contract is an implementation of ERC-721 that includes the metadata standard extensions ([`IERC721Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#IERC721Metadata) ) as well as a mechanism for per-token metadata. That’s where the [`_setTokenURI`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721-_setTokenURI-uint256-string-) method comes from: we use it to store an item’s metadata. Also note that, unlike ERC-20, ERC-721 lacks a `decimals` field, since each token is distinct and cannot be partitioned. New items can be created: > gameItem.awardItem(playerAddress, "https://game.example/item-id-8u5h2m.json") Transaction successful. Transaction hash: 0x... Events emitted: - Transfer(0x0000000000000000000000000000000000000000, playerAddress, 7) And the owner and metadata of each item queried: > gameItem.ownerOf(7) playerAddress > gameItem.tokenURI(7) "https://game.example/item-id-8u5h2m.json" This `tokenURI` should resolve to a JSON document that might look something like: { "name": "Thor's hammer", "description": "Mjölnir, the legendary hammer of the Norse god of thunder.", "image": "https://game.example/item-id-8u5h2m.png", "strength": 20 } For more information about the `tokenURI` metadata JSON Schema, check out the [ERC-721 specification](https://eips.ethereum.org/EIPS/eip-721) . You’ll notice that the item’s information is included in the metadata, but that information isn’t on-chain! So a game developer could change the underlying metadata, changing the rules of the game! If you’d like to put all item information on-chain, you can extend ERC-721 to do so (though it will be rather costly) by providing a [`Base64`](https://docs.openzeppelin.com/contracts/5.x/utilities#base64) Data URI with the JSON schema encoded. You could also leverage IPFS to store the tokenURI information, but these techniques are out of the scope of this overview guide. [Creating Supply\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc20-supply) [ERC-1155\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc1155) ### On this page [Constructing an ERC-721 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc721#constructing-an-erc-721-token-contract) --- # Utilities | OpenZeppelin Docs OpenZeppelin Contracts Utilities ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. For a complete list, check out the [API Reference](https://docs.openzeppelin.com/contracts/5.x/api/utils) . Here are some of the more popular ones. [Cryptography](https://docs.openzeppelin.com/contracts/5.x/utilities#cryptography) ----------------------------------------------------------------------------------- ### [Checking Signatures On-Chain](https://docs.openzeppelin.com/contracts/5.x/utilities#checking-signatures-on-chain) At a high level, signatures are a set of cryptographic algorithms that allow for a _signer_ to prove himself owner of a _private key_ used to authorize a piece of information (generally a transaction or `UserOperation`). Natively, the EVM supports the Elliptic Curve Digital Signature Algorithm ([ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) ) using the secp256k1 curve, however other signature algorithms such as P256 and RSA are supported. #### [Ethereum Signatures (secp256k1)](https://docs.openzeppelin.com/contracts/5.x/utilities#ethereum-signatures-secp256k1) [`ECDSA`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#ECDSA) provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via [`web3.eth.sign`](https://web3js.readthedocs.io/en/v1.7.3/web3-eth.html#sign) , and form a 65-byte array (of type `bytes` in Solidity) arranged the following way: `[[v (1)], [r (32)], [s (32)]]`. The data signer can be recovered with [`ECDSA.recover`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#ECDSA-recover-bytes32-bytes-) , and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix `\x19Ethereum Signed Message:\n`, so when attempting to recover the signer of an Ethereum signed message hash, you’ll want to use [`toEthSignedMessageHash`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MessageHashUtils-toEthSignedMessageHash-bytes32-) . using ECDSA for bytes32; using MessageHashUtils for bytes32; function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) { return data .toEthSignedMessageHash() .recover(signature) == account; } Getting signature verification right is not trivial: make sure you fully read and understand [`MessageHashUtils`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MessageHashUtils) 's and [`ECDSA`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#ECDSA) 's documentation. #### [P256 Signatures (secp256r1)](https://docs.openzeppelin.com/contracts/5.x/utilities#p256-signatures-secp256r1) P256, also known as secp256r1, is one of the most used signature schemes. P256 signatures are standardized by the National Institute of Standards and Technology (NIST) and they are widely available in consumer hardware and software. These signatures are different from regular Ethereum Signatures (secp256k1) in that they use a different elliptic curve to perform operations but have similar security guarantees. using P256 for bytes32; function _verify( bytes32 data, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy ) internal pure returns (bool) { return data.verify(data, r, s, qx, qy); } By default, the `verify` function will try calling the [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md) precompile at address `0x100` and will fallback to an implementation in Solidity if not available. We encourage you to use `verifyNative` if you know the precompile is available on the chain you’re working on and on any other chain on which you intend to use the same bytecode in the future. In case of any doubts regarding the implementation roadmap of the native precompile `P256` of potential future target chains, please consider using `verifySolidity`. using P256 for bytes32; function _verify( bytes32 data, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy ) internal pure returns (bool) { // Will only call the precompile at address(0x100) return data.verifyNative(data, r, s, qx, qy); } The P256 library only allows for `s` values in the lower order of the curve (i.e. `s <= N/2`) to prevent malleability. In case your tooling produces signatures in both sides of the curve, consider flipping the `s` value to keep compatibility. #### [RSA](https://docs.openzeppelin.com/contracts/5.x/utilities#rsa) RSA is a public-key cryptosystem that was popularized by corporate and governmental public key infrastructures ([PKIs](https://en.wikipedia.org/wiki/Public_key_infrastructure) ) and [DNSSEC](https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions) . This cryptosystem consists of using a private key that’s the product of 2 large prime numbers. The message is signed by applying a modular exponentiation to its hash (commonly SHA256), where both the exponent and modulus compose the public key of the signer. RSA signatures are known for being less efficient than elliptic curve signatures given the size of the keys, which are big compared to ECDSA keys with the same security level. Using plain RSA is considered unsafe, this is why the implementation uses the `EMSA-PKCS1-v1_5` encoding method from [RFC8017](https://datatracker.ietf.org/doc/html/rfc8017) to include padding to the signature. To verify a signature using RSA, you can leverage the [`RSA`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#RSA) library that exposes a method for verifying RSA with the PKCS 1.5 standard: using RSA for bytes32; function _verify( bytes32 data, bytes memory signature, bytes memory e, bytes memory n ) internal pure returns (bool) { return data.pkcs1Sha256(signature, e, n); } Always use keys of at least 2048 bits. Additionally, be aware that PKCS#1 v1.5 allows for replayability due to the possibility of arbitrary optional parameters. To prevent replay attacks, consider including an onchain nonce or unique identifier in the message. ### [Signature Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#signature-verification) The [`SignatureChecker`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#SignatureChecker) library provides a unified interface for verifying signatures from different sources. It seamlessly supports: * ECDSA signatures from externally owned accounts (EOAs) * ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet * ERC-7913 signatures from keys that don’t have their own Ethereum address This allows developers to write signature verification code once and have it work across all these different signature types. #### [Basic Signature Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#basic-signature-verification) For standard signature verification that supports both EOAs and ERC-1271 contracts: using SignatureChecker for address; function _verifySignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { return SignatureChecker.isValidSignatureNow(signer, hash, signature); } The library automatically detects whether the signer is an EOA or a contract and uses the appropriate verification method. #### [ERC-1271 Contract Signatures](https://docs.openzeppelin.com/contracts/5.x/utilities#erc-1271-contract-signatures) For smart contract wallets that implement ERC-1271, you can explicitly use: function _verifyContractSignature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { return SignatureChecker.isValidERC1271SignatureNow(signer, hash, signature); } #### [ERC-7913 Extended Signatures](https://docs.openzeppelin.com/contracts/5.x/utilities#erc-7913-extended-signatures) ERC-7913 extends signature verification to support keys that don’t have their own Ethereum address. This is useful for integrating non-Ethereum cryptographic curves, hardware devices, or other identity systems. A signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. function _verifyERC7913Signature(bytes memory signer, bytes32 hash, bytes memory signature) internal view returns (bool) { return SignatureChecker.isValidSignatureNow(signer, hash, signature); } The verification process works as follows: * If `signer.length < 20`: verification fails * If `signer.length == 20`: verification is done using standard signature checking * Otherwise: verification is done using an ERC-7913 verifier #### [Batch Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#batch-verification) For verifying multiple ERC-7913 signatures at once: function _verifyMultipleSignatures( bytes32 hash, bytes[] memory signers, bytes[] memory signatures ) internal view returns (bool) { return SignatureChecker.areValidSignaturesNow(hash, signers, signatures); } This function will reject inputs that contain duplicated signers. Sorting the signers by their `keccak256` hash is recommended to minimize the gas cost. This unified approach allows smart contracts to accept signatures from any supported source without needing to implement different verification logic for each type. ### [Verifying Merkle Proofs](https://docs.openzeppelin.com/contracts/5.x/utilities#verifying-merkle-proofs) Developers can build a Merkle Tree off-chain, which allows for verifying that an element (leaf) is part of a set by using a Merkle Proof. This technique is widely used for creating whitelists (e.g., for airdrops) and other advanced use cases. OpenZeppelin Contracts provides a [JavaScript library](https://github.com/OpenZeppelin/merkle-tree) for building trees off-chain and generating proofs. [`MerkleProof`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MerkleProof) provides: * [`verify`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MerkleProof-verify-bytes32---bytes32-bytes32-) - can prove that some value is part of a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) . * [`multiProofVerify`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MerkleProof-multiProofVerify-bytes32-bytes32---bytes32---bool---) - can prove multiple values are part of a Merkle tree. For an on-chain Merkle Tree, see the [`MerkleTree`](https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleTree) library. [Introspection](https://docs.openzeppelin.com/contracts/5.x/utilities#introspection) ------------------------------------------------------------------------------------- In Solidity, it’s frequently helpful to know whether or not a contract supports an interface you’d like to use. ERC-165 is a standard that helps do runtime interface detection. Contracts provide helpers both for implementing ERC-165 in your contracts and querying other contracts: * [`IERC165`](https://docs.openzeppelin.com/contracts/5.x/api/utils#IERC165) — this is the ERC-165 interface that defines [`supportsInterface`](https://docs.openzeppelin.com/contracts/5.x/api/utils#IERC165-supportsInterface-bytes4-) . When implementing ERC-165, you’ll conform to this interface. * [`ERC165`](https://docs.openzeppelin.com/contracts/5.x/api/utils#ERC165) — inherit this contract if you’d like to support interface detection using a lookup table in contract storage. You can register interfaces using [`_registerInterface(bytes4)`](https://docs.openzeppelin.com/contracts/5.x/api/utils#ERC165-_registerInterface-bytes4-) : check out example usage as part of the ERC-721 implementation. * [`ERC165Checker`](https://docs.openzeppelin.com/contracts/5.x/api/utils#ERC165Checker) — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about. * include with `using ERC165Checker for address;` * [`myAddress._supportsInterface(bytes4)`](https://docs.openzeppelin.com/contracts/5.x/api/utils#ERC165Checker-_supportsInterface-address-bytes4-) * [`myAddress._supportsAllInterfaces(bytes4[\])`](https://docs.openzeppelin.com/contracts/5.x/api/utils#ERC165Checker-_supportsAllInterfaces-address-bytes4---) contract MyContract { using ERC165Checker for address; bytes4 private InterfaceId_ERC721 = 0x80ac58cd; /** * @dev transfer an ERC-721 token from this contract to someone else */ function transferERC721( address token, address to, uint256 tokenId ) public { require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN"); IERC721(token).transferFrom(address(this), to, tokenId); } } [Math](https://docs.openzeppelin.com/contracts/5.x/utilities#math) ------------------------------------------------------------------- Although Solidity already provides math operators (i.e. `+`, `-`, etc.), Contracts includes [`Math`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Math) ; a set of utilities for dealing with mathematical operators, with support for extra operations (e.g., [`average`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Math-average-uint256-uint256-) ) and [`SignedMath`](https://docs.openzeppelin.com/contracts/5.x/api/utils#SignedMath) ; a library specialized in signed math operations. Include these contracts with `using Math for uint256` or `using SignedMath for int256` and then use their functions in your code: contract MyContract { using Math for uint256; using SignedMath for int256; function tryOperations(uint256 a, uint256 b) internal pure { (bool succeededAdd, uint256 resultAdd) = x.tryAdd(y); (bool succeededSub, uint256 resultSub) = x.trySub(y); (bool succeededMul, uint256 resultMul) = x.tryMul(y); (bool succeededDiv, uint256 resultDiv) = x.tryDiv(y); // ... } function unsignedAverage(int256 a, int256 b) { int256 avg = a.average(b); // ... } } Easy! While working with different data types that might require casting, you can use [`SafeCast`](https://docs.openzeppelin.com/contracts/5.x/api/utils#SafeCast) for type casting with added overflow checks. [Structures](https://docs.openzeppelin.com/contracts/5.x/utilities#structures) ------------------------------------------------------------------------------- Some use cases require more powerful data structures than arrays and mappings offered natively in Solidity. Contracts provides these libraries for enhanced data structure management: * [`BitMaps`](https://docs.openzeppelin.com/contracts/5.x/api/utils#BitMaps) : Store packed booleans in storage. * [`Checkpoints`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Checkpoints) : Checkpoint values with built-in lookups. * [`DoubleEndedQueue`](https://docs.openzeppelin.com/contracts/5.x/api/utils#DoubleEndedQueue) : Store items in a queue with `pop()` and `queue()` constant time operations. * [`EnumerableSet`](https://docs.openzeppelin.com/contracts/5.x/api/utils#EnumerableSet) : A [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) with enumeration capabilities. * [`EnumerableMap`](https://docs.openzeppelin.com/contracts/5.x/api/utils#EnumerableMap) : A `mapping` variant with enumeration capabilities. * [`MerkleTree`](https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleTree) : An on-chain [Merkle Tree](https://wikipedia.org/wiki/Merkle_Tree) with helper functions. * [`Heap`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Heap.sol) : A [binary heap](https://en.wikipedia.org/wiki/Binary_heap) to store elements with priority defined by a compartor function. The `Enumerable*` structures are similar to mappings in that they store and remove elements in constant time and don’t allow for repeated entries, but they also support _enumeration_, which means you can easily query all stored entries both on and off-chain. ### [Building a Merkle Tree](https://docs.openzeppelin.com/contracts/5.x/utilities#building-a-merkle-tree) Building an on-chain Merkle Tree allows developers to keep track of the history of roots in a decentralized manner. For these cases, the [`MerkleTree`](https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleTree) includes a predefined structure with functions to manipulate the tree (e.g. pushing values or resetting the tree). The Merkle Tree does not keep track of the roots intentionally, so that developers can choose their tracking mechanism. Setting up and using a Merkle Tree in Solidity is as simple as follows: Functions are exposed without access control for demonstration purposes using MerkleTree for MerkleTree.Bytes32PushTree; MerkleTree.Bytes32PushTree private _tree; function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { root = _tree.setup(_depth, _zero); } function push(bytes32 leaf) public /* onlyOwner */ { (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf); // Store the new root. } The library also supports custom hashing functions, which can be passed as an extra parameter to the [`push`](https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleTree-push-struct-MerkleTree-Bytes32PushTree-bytes32-) and [`setup`](https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleTree-setup-struct-MerkleTree-Bytes32PushTree-uint8-bytes32-) functions. Using custom hashing functions is a sensitive operation. After setup, it requires to keep using the same hashing function for every new value pushed to the tree to avoid corrupting the tree. For this reason, it’s a good practice to keep your hashing function static in your implementation contract as follows: using MerkleTree for MerkleTree.Bytes32PushTree; MerkleTree.Bytes32PushTree private _tree; function setup(uint8 _depth, bytes32 _zero) public /* onlyOwner */ { root = _tree.setup(_depth, _zero, _hashFn); } function push(bytes32 leaf) public /* onlyOwner */ { (uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf, _hashFn); // Store the new root. } function _hashFn(bytes32 a, bytes32 b) internal view returns(bytes32) { // Custom hash function implementation // Kept as an internal implementation detail to // guarantee the same function is always used } ### [Using a Heap](https://docs.openzeppelin.com/contracts/5.x/utilities#using-a-heap) A [binary heap](https://en.wikipedia.org/wiki/Binary_heap) is a data structure that always stores the most important element at its peak and it can be used as a priority queue. To define what is most important in a heap, these frequently take comparator functions that tell the binary heap whether a value has more relevance than another. OpenZeppelin Contracts implements a Heap data structure with the properties of a binary heap. The heap uses the [`lt`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#Comparators-lt-uint256-uint256-) function by default but allows to customize its comparator. When using a custom comparator, it's recommended to wrap your function to avoid the possibility of mistakenly using a different comparator function: function pop(Uint256Heap storage self) internal returns (uint256) { return pop(self, Comparators.gt); } function insert(Uint256Heap storage self, uint256 value) internal { insert(self, value, Comparators.gt); } function replace(Uint256Heap storage self, uint256 newValue) internal returns (uint256) { return replace(self, newValue, Comparators.gt); } [Misc](https://docs.openzeppelin.com/contracts/5.x/utilities#misc) ------------------------------------------------------------------- ### [Packing](https://docs.openzeppelin.com/contracts/5.x/utilities#packing) The storage in the EVM is shaped in chunks of 32 bytes, each of this chunks is known as a _slot_, and can hold multiple values together as long as these values don't exceed its size. These properties of the storage allow for a technique known as _packing_, that consists of placing values together on a single storage slot to reduce the costs associated to reading and writing to multiple slots instead of just one. Commonly, developers pack values using structs that place values together so they fit better in storage. However, this approach requires to load such struct from either calldata or memory. Although sometimes necessary, it may be useful to pack values in a single slot and treat it as a packed value without involving calldata or memory. The [`Packing`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Packing) library is a set of utilities for packing values that fit in 32 bytes. The library includes 3 main functionalities: * Packing 2 `bytesXX` values * Extracting a packed `bytesXX` value from a `bytesYY` * Replacing a packed `bytesXX` value from a `bytesYY` With these primitives, one can build custom functions to create custom packed types. For example, suppose you need to pack an `address` of 20 bytes with a `bytes4` selector and an `uint64` time period: function _pack(address account, bytes4 selector, uint64 period) external pure returns (bytes32) { bytes12 subpack = Packing.pack_4_8(selector, bytes8(period)); return Packing.pack_20_12(bytes20(account), subpack); } function _unpack(bytes32 pack) external pure returns (address, bytes4, uint64) { return ( address(Packing.extract_32_20(pack, 0)), Packing.extract_32_4(pack, 20), uint64(Packing.extract_32_8(pack, 24)) ); } ### [Storage Slots](https://docs.openzeppelin.com/contracts/5.x/utilities#storage-slots) Solidity allocates a storage pointer for each variable declared in a contract. However, there are cases when it's required to access storage pointers that can't be derived by using regular Solidity. For those cases, the [`StorageSlot`](https://docs.openzeppelin.com/contracts/5.x/api/utils#StorageSlot) library allows for manipulating storage slots directly. bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } function _setImplementation(address newImplementation) internal { require(newImplementation.code.length > 0); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } The [`TransientSlot`](https://docs.openzeppelin.com/contracts/5.x/api/utils#TransientSlot) library supports transient storage through user defined value types ([UDVTs](https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types) ), which enables the same value types as in Solidity. bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; function _getTransientLock() internal view returns (bool) { return _LOCK_SLOT.asBoolean().tload(); } function _setTransientLock(bool lock) internal { _LOCK_SLOT.asBoolean().tstore(lock); } Manipulating storage slots directly is an advanced practice. Developers MUST make sure that the storage pointer is not colliding with other variables. One of the most common use cases for writing directly to storage slots is ERC-7201 for namespaced storage, which is guaranteed to not collide with other storage slots derived by Solidity. Users can leverage this standard using the [`SlotDerivation`](https://docs.openzeppelin.com/contracts/5.x/api/utils#SlotDerivation) library. using SlotDerivation for bytes32; string private constant _NAMESPACE = "" // eg. example.main function erc7201Pointer() internal view returns (bytes32) { return _NAMESPACE.erc7201Slot(); } ### [Base64](https://docs.openzeppelin.com/contracts/5.x/utilities#base64) [`Base64`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Base64) util allows you to transform `bytes32` data into its Base64 `string` representation. This is especially useful for building URL-safe tokenURIs for both [`ERC-721`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#IERC721Metadata-tokenURI-uint256-) or [`ERC-1155`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155MetadataURI-uri-uint256-) . This library provides a clever way to serve URL-safe [Data URI](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs/) compliant strings to serve on-chain data structures. Here is an example to send JSON Metadata through a Base64 Data URI using an ERC-721: // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; contract Base64NFT is ERC721 { using Strings for uint256; constructor() ERC721("Base64NFT", "MTK") {} // ... function tokenURI(uint256 tokenId) public pure override returns (string memory) { // Equivalent to: // { // "name": "Base64NFT #1", // // Replace with extra ERC-721 Metadata properties // } // prettier-ignore string memory dataURI = string.concat("{\"name\": \"Base64NFT #", tokenId.toString(), "\"}"); return string.concat("data:application/json;base64,", Base64.encode(bytes(dataURI))); } } ### [Multicall](https://docs.openzeppelin.com/contracts/5.x/utilities#multicall) The `Multicall` abstract contract comes with a `multicall` function that bundles together multiple calls in a single external call. With it, external accounts may perform atomic operations comprising several function calls. This is not only useful for EOAs to make multiple calls in a single transaction, it's also a way to revert a previous call if a later one fails. Consider this dummy contract: // contracts/Box.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; contract Box is Multicall { function foo() public { // ... } function bar() public { // ... } } This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction: const instance = await ethers.deployContract("Box"); await instance.multicall([\ instance.interface.encodeFunctionData("foo"),\ instance.interface.encodeFunctionData("bar")\ ]); ### [Memory](https://docs.openzeppelin.com/contracts/5.x/utilities#memory) The [`Memory`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Memory) library provides functions for advanced use cases that require granular memory management. A common use case is to avoid unnecessary memory expansion costs when performing repeated operations that allocate memory in a loop. Consider the following example: function processMultipleItems(uint256[] memory items) internal { for (uint256 i = 0; i < items.length; i++) { bytes memory tempData = abi.encode(items[i], block.timestamp); // Process tempData... } } Note that each iteration allocates new memory for `tempData`, causing the memory to expand continuously. This can be optimized by resetting the memory pointer between iterations: function processMultipleItems(uint256[] memory items) internal { Memory.Pointer ptr = Memory.getFreeMemoryPointer(); // Cache pointer for (uint256 i = 0; i < items.length; i++) { bytes memory tempData = abi.encode(items[i], block.timestamp); // Process tempData... Memory.setFreeMemoryPointer(ptr); // Reset pointer for reuse } } This way, memory allocated for `tempData` in each iteration is reused, significantly reducing memory expansion costs when processing many items. Only use these functions after carefully confirming they're necessary. By default, Solidity handles memory safely. Using this library without understanding memory layout and safety may be dangerous. See the [memory layout](https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_memory.html) and [memory safety](https://docs.soliditylang.org/en/v0.8.20/assembly.html#memory-safety) documentation for details. ### [Historical Block Hashes](https://docs.openzeppelin.com/contracts/5.x/utilities#historical-block-hashes) [`Blockhash`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Blockhash) provides L2 protocol developers with extended access to historical block hashes beyond Ethereum's native 256-block limit. By leveraging [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) 's history storage contract, the library enables access to block hashes up to 8,191 blocks in the past, making it invaluable for L2 fraud proofs and state verification systems. The library seamlessly combines native `BLOCKHASH` opcode access for recent blocks (≤256) with EIP-2935 history storage queries for older blocks (257-8,191). It handles edge cases gracefully by returning zero for future blocks or those beyond the history window, matching the EVM's behavior. The implementation uses gas-efficient assembly for static calls to the history storage contract. contract L1Inbox { using Blockhash for uint256; function verifyBlockHash(uint256 blockNumber, bytes32 expectedHash) public view returns (bool) { return blockNumber.blockHash() == expectedHash; } } After EIP-2935 activation, it takes 8,191 blocks to completely fill the history storage. Before that, only block hashes since the fork block will be available. ### [Time](https://docs.openzeppelin.com/contracts/5.x/utilities#time) The [`Time`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Time) library provides helpers for manipulating time-related objects in a type-safe manner. It uses `uint48` for timepoints and `uint32` for durations, helping to reduce gas costs while providing adequate precision. One of its key features is the `Delay` type, which represents a duration that can automatically change its value at a specified point in the future while maintaining delay guarantees. For example, when reducing a delay value (e.g., from 7 days to 1 day), the change only takes effect after the difference between the old and new delay (i.e. a 6 days) or a minimum setback period, preventing an attacker who gains admin access from immediately reducing security timeouts and executing sensitive operations. This is particularly useful for governance and security mechanisms where timelock periods need to be enforced. Consider this example for using and safely updating Delays: pragma solidity ^0.8.27; import Time from "contracts/utils/types/Time.sol"; contract MyDelayedContract { using Time for *; Time.Delay private _delay; constructor() { _delay = Time.toDelay(3 days); } function schedule(bytes32 operationId) external { // Get the current `_delay` value, respecting any pending delay changes if they've taken effect uint32 currentDelay = _delay.get(); uint48 executionTime = Time.timestamp() + currentDelay; // ... schedule the operation at `executionTime` } function execute(bytes32 operationId) external { uint48 executionTime = getExecutionTime(operationId); require(executionTime > 0, "Operation not scheduled"); require(Time.timestamp() >= executionTime, "Delay not elapsed yet"); // ... execute the operation } // Update the delay with `Time`'s safety mechanism function updateDelay(uint32 newDelay) external { (Time.Delay updatedDelay, uint48 effect) = _delay.withUpdate( newDelay, // The new delay value 5 days // Minimum setback if reducing the delay ); _delay = updatedDelay; // ... emit events } // Get complete delay details including pending changes function getDelayDetails() external view returns ( uint32 currentValue, // The current delay value uint32 pendingValue, // The pending delay value uint48 effectTime // The timepoint when the pending delay change takes effect ) { return _delay.getFull(); } } This pattern is used extensively in OpenZeppelin's [AccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) for implementing secure time-based access control. For example, when changing an admin delay: function _setTargetAdminDelay(address target, uint32 newDelay) internal virtual { uint48 effect; (_targets[target].adminDelay, effect) = _targets[target].adminDelay.withUpdate( newDelay, minSetback() ); emit TargetAdminDelayUpdated(target, newDelay, effect); } [Governance\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/governance) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/subgraphs) ### On this page [Cryptography](https://docs.openzeppelin.com/contracts/5.x/utilities#cryptography) [Checking Signatures On-Chain](https://docs.openzeppelin.com/contracts/5.x/utilities#checking-signatures-on-chain) [Ethereum Signatures (secp256k1)](https://docs.openzeppelin.com/contracts/5.x/utilities#ethereum-signatures-secp256k1) [P256 Signatures (secp256r1)](https://docs.openzeppelin.com/contracts/5.x/utilities#p256-signatures-secp256r1) [RSA](https://docs.openzeppelin.com/contracts/5.x/utilities#rsa) [Signature Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#signature-verification) [Basic Signature Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#basic-signature-verification) [ERC-1271 Contract Signatures](https://docs.openzeppelin.com/contracts/5.x/utilities#erc-1271-contract-signatures) [ERC-7913 Extended Signatures](https://docs.openzeppelin.com/contracts/5.x/utilities#erc-7913-extended-signatures) [Batch Verification](https://docs.openzeppelin.com/contracts/5.x/utilities#batch-verification) [Verifying Merkle Proofs](https://docs.openzeppelin.com/contracts/5.x/utilities#verifying-merkle-proofs) [Introspection](https://docs.openzeppelin.com/contracts/5.x/utilities#introspection) [Math](https://docs.openzeppelin.com/contracts/5.x/utilities#math) [Structures](https://docs.openzeppelin.com/contracts/5.x/utilities#structures) [Building a Merkle Tree](https://docs.openzeppelin.com/contracts/5.x/utilities#building-a-merkle-tree) [Using a Heap](https://docs.openzeppelin.com/contracts/5.x/utilities#using-a-heap) [Misc](https://docs.openzeppelin.com/contracts/5.x/utilities#misc) [Packing](https://docs.openzeppelin.com/contracts/5.x/utilities#packing) [Storage Slots](https://docs.openzeppelin.com/contracts/5.x/utilities#storage-slots) [Base64](https://docs.openzeppelin.com/contracts/5.x/utilities#base64) [Multicall](https://docs.openzeppelin.com/contracts/5.x/utilities#multicall) [Memory](https://docs.openzeppelin.com/contracts/5.x/utilities#memory) [Historical Block Hashes](https://docs.openzeppelin.com/contracts/5.x/utilities#historical-block-hashes) [Time](https://docs.openzeppelin.com/contracts/5.x/utilities#time) --- # How to set up on-chain governance | OpenZeppelin Docs OpenZeppelin Contracts How to set up on-chain governance ================================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) In this guide we will learn how OpenZeppelin’s Governor contract works, how to set it up, and how to use it to create proposals, vote for them, and execute them, using tools provided by Ethers.js and Tally. Find detailed contract documentation at [Governance API](https://docs.openzeppelin.com/contracts/5.x/api/governance) . [Introduction](https://docs.openzeppelin.com/contracts/5.x/governance#introduction) ------------------------------------------------------------------------------------ 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”. The GovernorAlpha and GovernorBravo contracts designed by Compound have been very successful and popular so far, with the downside that projects with different requirements have had to fork the code to customize it for their needs, which can pose a high risk of introducing security issues. For OpenZeppelin Contracts, we set out to build a modular system of Governor contracts so that forking is not needed, and different requirements can be accommodated by writing small modules using Solidity inheritance. You will find the most common requirements out of the box in OpenZeppelin Contracts, but writing additional ones is simple, and we will be adding new features as requested by the community in future releases. Additionally, the design of OpenZeppelin Governor requires minimal use of storage and results in more gas efficient operation. [Compatibility](https://docs.openzeppelin.com/contracts/5.x/governance#compatibility) -------------------------------------------------------------------------------------- OpenZeppelin’s Governor system was designed with a concern for compatibility with existing systems that were based on Compound’s GovernorAlpha and GovernorBravo. Because of this, you will find that many modules are presented in two variants, one of which is built for compatibility with those systems. ### [ERC20Votes & ERC20VotesComp](https://docs.openzeppelin.com/contracts/5.x/governance#erc20votes--erc20votescomp) The ERC-20 extension to keep track of votes and vote delegation is one such case. The shorter one is the more generic version because it can support token supplies greater than 2^96, while the “Comp” variant is limited in that regard, but exactly fits the interface of the COMP token that is used by GovernorAlpha and Bravo. Both contract variants share the same events, so they are fully compatible when looking at events only. ### [Governor & GovernorStorage](https://docs.openzeppelin.com/contracts/5.x/governance#governor--governorstorage) An OpenZeppelin Governor contract is not interface-compatible with Compound’s GovernorAlpha or Bravo. Even though events are fully compatible, proposal lifecycle functions (creation, execution, etc.) have different signatures that are meant to optimize storage use. Other functions from GovernorAlpha and Bravo are likewise not available. It’s possible to opt in some Bravo-like behavior by inheriting from the GovernorStorage module. This module provides proposal enumerability and alternate versions of the `queue`, `execute` and `cancel` function that only take the proposal id. This module reduces the calldata needed by some operations in exchange for an increased storage footprint. This might be a good trade-off for some L2 chains. It also provides primitives for indexer-free frontends. Note that even with the use of this module, one important difference with Compound’s GovernorBravo is the way that `proposalId`s are calculated. Governor uses the hash of the proposal parameters with the purpose of keeping its data off-chain by event indexing, while the original Bravo implementation uses sequential `proposalId`s. ### [GovernorTimelockControl & GovernorTimelockCompound](https://docs.openzeppelin.com/contracts/5.x/governance#governortimelockcontrol--governortimelockcompound) When using a timelock with your Governor contract, you can use either OpenZeppelin’s TimelockController or Compound’s Timelock. Based on the choice of timelock, you should choose the corresponding Governor module: GovernorTimelockControl or GovernorTimelockCompound respectively. This allows you to migrate an existing GovernorAlpha instance to an OpenZeppelin-based Governor without changing the timelock in use. ### [Tally](https://docs.openzeppelin.com/contracts/5.x/governance#tally) [Tally](https://www.tally.xyz/) is a full-fledged application for user owned on-chain governance. It comprises a voting dashboard, proposal creation wizard, real time research and analysis, and educational content. For all of these options, the Governor will be compatible with Tally: users will be able to create proposals, see voting periods and delays following [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6372) , visualize voting power and advocates, navigate proposals, and cast votes. For proposal creation in particular, projects can also use [Defender Transaction Proposals](https://docs.openzeppelin.com/defender/module/transaction-proposals) as an alternative interface. In the rest of this guide, we will focus on a fresh deploy of the vanilla OpenZeppelin Governor features without concern for compatibility with GovernorAlpha or Bravo. [Setup](https://docs.openzeppelin.com/contracts/5.x/governance#setup) ---------------------------------------------------------------------- ### [Token](https://docs.openzeppelin.com/contracts/5.x/governance#token) The voting power of each account in our governance setup will be determined by an ERC-20 token. The token has to implement the ERC20Votes 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. // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; contract MyToken is ERC20, ERC20Permit, ERC20Votes { constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} // The functions below are overrides required by Solidity. function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._update(from, to, amount); } function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } } If your project already has a live token that does not include ERC20Votes and is not upgradeable, you can wrap it in a governance token by using ERC20Wrapper. This will allow token holders to participate in governance by wrapping their tokens 1-to-1. // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20, ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {ERC20Wrapper} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol"; import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; contract MyTokenWrapped is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { constructor( IERC20 wrappedToken ) ERC20("MyTokenWrapped", "MTK") ERC20Permit("MyTokenWrapped") ERC20Wrapper(wrappedToken) {} // The functions below are overrides required by Solidity. function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8) { return super.decimals(); } function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._update(from, to, amount); } function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } } The only other source of voting power available in OpenZeppelin Contracts currently is [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721Votes) . ERC-721 tokens that don’t provide this functionality can be wrapped into a voting tokens using a combination of [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721Votes) and [`ERC721Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721Wrapper) . The internal clock used by the token to store voting balances will dictate the operating mode of the Governor contract attached to it. By default, block numbers are used. Since v4.9, developers can override the [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6372) clock to use timestamps instead of block numbers. ### [Governor](https://docs.openzeppelin.com/contracts/5.x/governance#governor) Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, 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) what type of token should be used to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts. For 1) we will use the GovernorVotes module, which hooks to an 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 as a constructor parameter the address of the token. This module also discovers the clock mode (ERC-6372) used by the token and applies it to the Governor. For 2) we will use GovernorVotesQuorumFraction which works together with ERC20Votes to define quorum as a percentage of the total supply at the block a proposal’s voting power is retrieved. This requires a constructor parameter to set the percentage. Most Governors nowadays use 4%, so we will initialize the module with parameter 4 (this indicates the percentage, resulting in 4%). For 3) we will use GovernorCountingSimple, a module that offers 3 options to voters: For, Against, and Abstain, and where only For and Abstain votes are counted towards quorum. Besides these modules, Governor itself has some parameters we must set. votingDelay: How long after a proposal is created should voting power be fixed. A large voting delay gives users time to unstake tokens if necessary. votingPeriod: How long does a proposal remain open to votes. These parameters are specified in the unit defined in the token’s clock. Assuming the token uses block numbers, and assuming block time of around 12 seconds, we will have set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. We can optionally set a proposal threshold as well. This restricts proposal creation to accounts that have enough voting power. // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol"; import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { constructor( IVotes _token, TimelockController _timelock ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} function votingDelay() public pure override returns (uint256) { return 7200; // 1 day } function votingPeriod() public pure override returns (uint256) { return 50400; // 1 week } function proposalThreshold() public pure override returns (uint256) { return 0; } // The functions below are overrides required by Solidity. function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { return super.state(proposalId); } function proposalNeedsQueuing( uint256 proposalId ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { return super.proposalNeedsQueuing(proposalId); } function _queueOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) returns (uint48) { return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); } function _executeOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) { super._executeOperations(proposalId, targets, values, calldatas, descriptionHash); } function _cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) returns (uint256) { return super._cancel(targets, values, calldatas, descriptionHash); } function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { return super._executor(); } } ### [Timelock](https://docs.openzeppelin.com/contracts/5.x/governance#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 in combination with the GovernorTimelockControl module. 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. Before version 4.5 there was no way to recover funds in the Governor contract when using a timelock! Before version 4.3, when using the Compound Timelock, ETH in the timelock was not easily accessible. TimelockController uses an 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 should be granted, and it should likely be the only proposer 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). * 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. [Proposal Lifecycle](https://docs.openzeppelin.com/contracts/5.x/governance#proposal-lifecycle) ------------------------------------------------------------------------------------------------ Let’s walk through how to create and execute a proposal on our newly deployed Governor. A proposal is a sequence of actions that the Governor contract will perform if it passes. Each action consists of a target address, calldata encoding a function call, and an amount of ETH to include. Additionally, a proposal includes a human-readable description. ### [Create a Proposal](https://docs.openzeppelin.com/contracts/5.x/governance#create-a-proposal) Let’s say we want to create a proposal to give a team a grant, in the form of ERC-20 tokens from the governance treasury. This proposal will consist of a single action where the target is the ERC-20 token, calldata is the encoded function call `transfer(, )`, and with 0 ETH attached. Generally a proposal will be created with the help of an interface such as Tally or [Defender Proposals](https://docs.openzeppelin.com/defender/module/transaction-proposals) . Here we will show how to create the proposal using Ethers.js. First we get all the parameters necessary for the proposal action. const tokenAddress = ...; const token = await ethers.getContractAt(‘ERC20’, tokenAddress); const teamAddress = ...; const grantAmount = ...; const transferCalldata = token.interface.encodeFunctionData(‘transfer’, [teamAddress, grantAmount]); Now we are ready to call the propose function of the Governor. Note that we don’t pass in one array of actions, but instead three arrays corresponding to the list of targets, the list of values, and the list of calldatas. In this case it’s a single action, so it’s simple: await governor.propose( [tokenAddress], [0], [transferCalldata], “Proposal #1: Give grant to team”, ); This will create a new proposal, with a proposal id that is obtained by hashing together the proposal data, and which will also be found in an event in the logs of the transaction. ### [Cast a Vote](https://docs.openzeppelin.com/contracts/5.x/governance#cast-a-vote) Once a proposal is active, delegates can cast their vote. Note that it is delegates who carry voting power: if a token holder wants to participate, they can set a trusted representative as their delegate, or they can become a delegate themselves by self-delegating their voting power. Votes are cast by interacting with the Governor contract through the `castVote` family of functions. Voters would generally invoke this from a governance UI such as Tally. ![Voting in Tally](https://docs.openzeppelin.com/tally-vote.png) ### [Execute the Proposal](https://docs.openzeppelin.com/contracts/5.x/governance#execute-the-proposal) Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. Once a proposal passes, it can be queued and executed from the same place you voted. ![Administration Panel in Tally](https://docs.openzeppelin.com/tally-exec.png) We will see now how to do this manually using Ethers.js. If a timelock was set up, the first step to execution is queueing. You will notice that both the queue and execute functions require passing in the entire proposal parameters, as opposed to just the proposal id. This is necessary because this data is not stored on chain, as a measure to save gas. Note that these parameters can always be found in the events emitted by the contract. The only parameter that is not sent in its entirety is the description, since this is only needed in its hashed form to compute the proposal id. To queue, we call the queue function: const descriptionHash = ethers.utils.id(“Proposal #1: Give grant to team”); await governor.queue( [tokenAddress], [0], [transferCalldata], descriptionHash, ); This will cause the Governor to interact with the timelock contract and queue the actions for execution after the required delay. After enough time has passed (according to the timelock parameters), the proposal can be executed. If there was no timelock to begin with, this step can be ran immediately after the proposal succeeds. await governor.execute( [tokenAddress], [0], [transferCalldata], descriptionHash, ); Executing the proposal will transfer the ERC-20 tokens to the chosen recipient. To wrap up: we set up a system where a treasury is controlled by the collective decision of the token holders of a project, and all actions are executed via proposals enforced by on-chain votes. [Timestamp based governance](https://docs.openzeppelin.com/contracts/5.x/governance#timestamp-based-governance) ---------------------------------------------------------------------------------------------------------------- ### [Motivation](https://docs.openzeppelin.com/contracts/5.x/governance#motivation) It is sometimes difficult to deal with durations expressed in number of blocks because of inconsistent or unpredictable time between blocks. This is particularly true of some L2 networks where blocks are produced based on blockchain usage. Using number of blocks can also lead to the governance rules being affected by network upgrades that modify the expected time between blocks. The difficulty of replacing block numbers with timestamps is that the Governor and the token must both use the same format when querying past votes. If a token is designed around block numbers, it is not possible for a Governor to reliably do timestamp based lookups. Therefore, designing a timestamp based voting system starts with the token. ### [Token](https://docs.openzeppelin.com/contracts/5.x/governance#token-1) Since v4.9, all voting contracts (including [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20Votes) and [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721Votes) ) rely on [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6372) for clock management. In order to change from operating with block numbers to operating with timestamps, all that is required is to override the `clock()` and `CLOCK_MODE()` functions. // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; contract MyTokenTimestampBased is ERC20, ERC20Permit, ERC20Votes { constructor() ERC20("MyTokenTimestampBased", "MTK") ERC20Permit("MyTokenTimestampBased") {} // Overrides IERC6372 functions to make the token & governor timestamp-based function clock() public view override returns (uint48) { return uint48(block.timestamp); } // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public pure override returns (string memory) { return "mode=timestamp"; } // The functions below are overrides required by Solidity. function _update(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._update(from, to, amount); } function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } } ### [Governor](https://docs.openzeppelin.com/contracts/5.x/governance#governor-1) The Governor will automatically detect the clock mode used by the token and adapt to it. There is no need to override anything in the Governor contract. However, the clock mode does affect how some values are interpreted. It is therefore necessary to set the `votingDelay()` and `votingPeriod()` accordingly. pragma solidity ^0.8.20; import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/compatibility/GovernorCountingSimple.sol"; import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { constructor(IVotes _token, TimelockController _timelock) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} function votingDelay() public pure virtual override returns (uint256) { return 1 days; } function votingPeriod() public pure virtual override returns (uint256) { return 1 weeks; } function proposalThreshold() public pure virtual override returns (uint256) { return 0; } // ... } ### [Disclaimer](https://docs.openzeppelin.com/contracts/5.x/governance#disclaimer) Timestamp based voting is a recent feature that was formalized in ERC-6372 and ERC-5805, and introduced in v4.9. At the time this feature is released, some governance tooling may not support it yet. Users can expect invalid reporting of deadlines & durations if the tool is not able to interpret the ERC6372 clock. This invalid reporting by offchain tools does not affect the onchain security and functionality of the governance contract. Governors with timestamp support (v4.9 and above) are compatible with old tokens (before v4.9) and will operate in "block number" mode (which is the mode all old tokens operate on). On the other hand, old Governor instances (before v4.9) are not compatible with new tokens operating using timestamps. If you update your token code to use timestamps, make sure to also update your Governor code. [ERC-6909\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc6909) [Utilities\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/utilities) ### On this page [Introduction](https://docs.openzeppelin.com/contracts/5.x/governance#introduction) [Compatibility](https://docs.openzeppelin.com/contracts/5.x/governance#compatibility) [ERC20Votes & ERC20VotesComp](https://docs.openzeppelin.com/contracts/5.x/governance#erc20votes--erc20votescomp) [Governor & GovernorStorage](https://docs.openzeppelin.com/contracts/5.x/governance#governor--governorstorage) [GovernorTimelockControl & GovernorTimelockCompound](https://docs.openzeppelin.com/contracts/5.x/governance#governortimelockcontrol--governortimelockcompound) [Tally](https://docs.openzeppelin.com/contracts/5.x/governance#tally) [Setup](https://docs.openzeppelin.com/contracts/5.x/governance#setup) [Token](https://docs.openzeppelin.com/contracts/5.x/governance#token) [Governor](https://docs.openzeppelin.com/contracts/5.x/governance#governor) [Timelock](https://docs.openzeppelin.com/contracts/5.x/governance#timelock) [Proposal Lifecycle](https://docs.openzeppelin.com/contracts/5.x/governance#proposal-lifecycle) [Create a Proposal](https://docs.openzeppelin.com/contracts/5.x/governance#create-a-proposal) [Cast a Vote](https://docs.openzeppelin.com/contracts/5.x/governance#cast-a-vote) [Execute the Proposal](https://docs.openzeppelin.com/contracts/5.x/governance#execute-the-proposal) [Timestamp based governance](https://docs.openzeppelin.com/contracts/5.x/governance#timestamp-based-governance) [Motivation](https://docs.openzeppelin.com/contracts/5.x/governance#motivation) [Token](https://docs.openzeppelin.com/contracts/5.x/governance#token-1) [Governor](https://docs.openzeppelin.com/contracts/5.x/governance#governor-1) [Disclaimer](https://docs.openzeppelin.com/contracts/5.x/governance#disclaimer) --- # ERC-20 | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) ERC-20 ====== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) An ERC-20 token contract keeps track of [_fungible_ tokens](https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens) : any one token is exactly equal to any other token; no tokens have special rights or behavior associated with them. This makes ERC-20 tokens useful for things like a **medium of exchange currency**, **voting rights**, **staking**, and more. OpenZeppelin Contracts provides many ERC20-related contracts. On the [`API reference`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) you’ll find detailed information on their properties and usage. [Constructing an ERC-20 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc20#constructing-an-erc-20-token-contract) --------------------------------------------------------------------------------------------------------------------------------- Using Contracts, we can easily create our own ERC-20 token contract, which will be used to track _Gold_ (GLD), an internal currency in a hypothetical game. Here’s what our GLD token might look like. // contracts/GLDToken.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract GLDToken is ERC20 { constructor(uint256 initialSupply) ERC20("Gold", "GLD") { _mint(msg.sender, initialSupply); } } Our contracts are often used via [inheritance](https://solidity.readthedocs.io/en/latest/contracts.html#inheritance) , and here we’re reusing [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#erc20) for both the basic standard implementation and the [`name`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-name--) , [`symbol`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-symbol--) , and [`decimals`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-decimals--) optional extensions. Additionally, we’re creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract. For a more complete discussion of ERC-20 supply mechanisms, see [Creating ERC-20 Supply](https://docs.openzeppelin.com/contracts/5.x/erc20-supply) . That’s it! Once deployed, we will be able to query the deployer’s balance: > GLDToken.balanceOf(deployerAddress) 1000000000000000000000 We can also [transfer](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#IERC20-transfer-address-uint256-) these tokens to other accounts: > GLDToken.transfer(otherAddress, 300000000000000000000) > GLDToken.balanceOf(otherAddress) 300000000000000000000 > GLDToken.balanceOf(deployerAddress) 700000000000000000000 [A Note on `decimals`](https://docs.openzeppelin.com/contracts/5.x/erc20#a-note-on-decimals) --------------------------------------------------------------------------------------------- Often, you’ll want to be able to divide your tokens into arbitrary amounts: say, if you own `5 GLD`, you may want to send `1.5 GLD` to a friend, and keep `3.5 GLD` to yourself. Unfortunately, Solidity and the EVM do not support this behavior: only integer (whole) numbers can be used, which poses an issue. You may send `1` or `2` tokens, but not `1.5`. To work around this, [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20) provides a [`decimals`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-decimals--) field, which is used to specify how many decimal places a token has. To be able to transfer `1.5 GLD`, `decimals` must be at least `1`, since that number has a single decimal place. How can this be achieved? It’s actually very simple: a token contract can use larger integer values, so that a balance of `50` will represent `5 GLD`, a transfer of `15` will correspond to `1.5 GLD` being sent, and so on. It is important to understand that `decimals` is _only used for display purposes_. All arithmetic inside the contract is still performed on integers, and it is the different user interfaces (wallets, exchanges, etc.) that must adjust the displayed values according to `decimals`. The total token supply and balance of each account are not specified in `GLD`: you need to divide by `10 ** decimals` to get the actual `GLD` amount. You’ll probably want to use a `decimals` value of `18`, just like Ether and most ERC-20 token contracts in use, unless you have a very special reason not to. When minting tokens or transferring them around, you will be actually sending the number `num GLD * (10 ** decimals)`. By default, `ERC20` uses a value of `18` for `decimals`. To use a different value, you will need to override the `decimals()` function in your contract. function decimals() public view virtual override returns (uint8) { return 16; } So if you want to send `5` tokens using a token contract with 18 decimals, the method to call will actually be: transfer(recipient, 5 * (10 ** 18)); [Overview\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/tokens) [Creating Supply\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc20-supply) ### On this page [Constructing an ERC-20 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc20#constructing-an-erc-20-token-contract) [A Note on `decimals`](https://docs.openzeppelin.com/contracts/5.x/erc20#a-note-on-decimals) --- # Quickstart | OpenZeppelin Docs UI Builder Quickstart ========== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) The Contracts UI Builder is an open source tool you can quickly create online forms to interact with your smart contracts for testing or for administration purposes. It includes a vast amount of features including: * Configurable EVM Networks * Automatic contract state and ABI scraping * Custom forms to handle different types of contract inputs and functions * Execution restriction options * OpenZeppelin Wallet UI or Rainbow Kit * Export as React App project [Getting Started](https://docs.openzeppelin.com/ui-builder#getting-started) ---------------------------------------------------------------------------- Visit [builder.openzeppelin.com](https://builder.openzeppelin.com/) to get started ### [1\. Select Network](https://docs.openzeppelin.com/ui-builder#1-select-network) First select the network your contract is deployed to ![Quickstart select network](https://docs.openzeppelin.com/ui-builder/quickstart-select-network.png) ### [2\. Provide Contract Address](https://docs.openzeppelin.com/ui-builder#2-provide-contract-address) Paste in the contract address and the UI Builder will fetch the ABI if the contract is verified. If it is not verified then provide the ABI in the form. ![Quickstart contract address](https://docs.openzeppelin.com/ui-builder/quickstart-contract-address.png) ### [3\. Select Function](https://docs.openzeppelin.com/ui-builder#3-select-function) Choose which write function you would like to build a form for. ![Quickstart select function](https://docs.openzeppelin.com/ui-builder/quickstart-select-function.png) ### [4\. Customize](https://docs.openzeppelin.com/ui-builder#4-customize) Setup the form for your function and customize any applicable fields, execution method restrictions, or wallet UI kit. Check out the [Customization](https://docs.openzeppelin.com/ui-builder/customization) section for more details ![Quickstart customize form](https://docs.openzeppelin.com/ui-builder/quickstart-customize-form.png) ### [5\. Export](https://docs.openzeppelin.com/ui-builder#5-export) Once complete you can click the "Export" button which will download the form as a React app you can deploy or customize further. ![Quickstart export form](https://docs.openzeppelin.com/ui-builder/quickstart-export-form.png) [Next Steps](https://docs.openzeppelin.com/ui-builder#next-steps) ------------------------------------------------------------------ Learn how you can customize [networks](https://docs.openzeppelin.com/ui-builder/networks) or customize the [forms](https://docs.openzeppelin.com/ui-builder/functions) for your project. Visit the GitHub repo with the link below and open an issue if you have any problems! [GitHub Repo](https://github.com/OpenZeppelin/ui-builder) ### On this page [Getting Started](https://docs.openzeppelin.com/ui-builder#getting-started) [1\. Select Network](https://docs.openzeppelin.com/ui-builder#1-select-network) [2\. Provide Contract Address](https://docs.openzeppelin.com/ui-builder#2-provide-contract-address) [3\. Select Function](https://docs.openzeppelin.com/ui-builder#3-select-function) [4\. Customize](https://docs.openzeppelin.com/ui-builder#4-customize) [5\. Export](https://docs.openzeppelin.com/ui-builder#5-export) [Next Steps](https://docs.openzeppelin.com/ui-builder#next-steps) --- # OpenZeppelin Relayer | OpenZeppelin Docs Relayer OpenZeppelin Relayer ==================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/relayer#overview) ----------------------------------------------------------- OpenZeppelin Relayer is a service that provides infrastructure to relay transactions to the EVM & Non-EVM networks. It is designed to be used as a backend for dApps that need to interact with these networks. [Features](https://docs.openzeppelin.com/relayer#features) ----------------------------------------------------------- * _**Multi-Chain Support**_: Interact with multiple blockchain networks, including Solana and EVM-based chains. * _**Transaction Relaying**_: Submit transactions to supported blockchain networks efficiently. * _**Transaction Signing**_: Securely sign transactions using configurable key management. * _**Transaction Fee Estimation**_: Estimate transaction fees for better cost management. * _**Solana Gasless Transactions**_: Support for gasless transactions on Solana, enabling users to interact without transaction fees. * _**Transaction Nonce Management**_: Handle nonce management to ensure transaction order. * _**Transaction Status Monitoring**_: Track the status of submitted transactions. * _**SDK Integration**_: Easily interact with the relayer through our companion JavaScript/TypeScript SDK. * _**Extensible Architecture**_: Easily add support for new blockchain networks. * _**Configurable Network Policies**_: Define and enforce network-specific policies for transaction processing. * _**Metrics and Observability**_: Monitor application performance using Prometheus and Grafana. * _**Docker Support**_: Deploy the relayer using Docker for both development and production environments. * _**Plugins**_: Extend the functionality of the relayer with custom logic using TypeScript functions. [Supported Networks](https://docs.openzeppelin.com/relayer#supported-networks) ------------------------------------------------------------------------------- OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. Networks are defined in configuration files, allowing you to configure: * _**Any EVM-compatible network**_ (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) * _**Solana networks**_ (mainnet-beta, devnet, testnet, custom RPC endpoints) * _**Stellar networks**_ (Pubnet, Testnet, custom networks) * _**Create custom network configurations**_ with specific RPC endpoints, chain IDs, and network parameters * _**Use inheritance**_ to create network variants that inherit from base configurations ### [Network Types](https://docs.openzeppelin.com/relayer#network-types) | Network Type | Description | | --- | --- | | `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | | `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | | `stellar` | Stellar blockchain networks (Partial support). Supports Stellar Public Network and Testnet. | Networks can be loaded from: * _**JSON arrays**_: Direct network definitions in configuration files * _**Directory of files**_: Multiple JSON files each containing network definitions For detailed network configuration options and examples, see the [Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration) page. For information about our development plans and upcoming features, see [Project Roadmap](https://docs.openzeppelin.com/relayer/roadmap) . To get started immediately, see [Quickstart](https://docs.openzeppelin.com/relayer/quickstart) . [Technical Overview](https://docs.openzeppelin.com/relayer#technical-overview) ------------------------------------------------------------------------------- [Project Structure](https://docs.openzeppelin.com/relayer#project-structure) ----------------------------------------------------------------------------- The project follows a standard Rust project layout: openzeppelin-relayer/ ├── src/ │ ├── api/ # Route and controllers logic │ ├── bootstrap/ # Service initialization logic │ ├── config/ # Configuration logic │ ├── constants/ # Constant values used in the system │ ├── domain/ # Domain logic │ ├── jobs/ # Asynchronous processing logic (queueing) │ ├── logging/ # Logs File rotation logic │ ├── metrics/ # Metrics logic │ ├── models/ # Data structures and types │ ├── repositories/ # Configuration storage │ ├── services/ # Services logic │ └── utils/ # Helper functions │ ├── config/ # Configuration files ├── tests/ # Integration tests ├── docs/ # Documentation ├── scripts/ # Utility scripts ├── examples/ # Configuration examples ├── helpers/ # Rust helper scripts ├── plugins/ # Plugins directory └── ... other root files (Cargo.toml, README.md, etc.) For detailed information about each directory and its contents, see [Project Structure Details](https://docs.openzeppelin.com/relayer/structure) . [Getting Started](https://docs.openzeppelin.com/relayer#getting-started) ------------------------------------------------------------------------- ### [Prerequisites](https://docs.openzeppelin.com/relayer#prerequisites) * Rust 2021 edition, version `1.86` or later * Docker (optional, for containerized deployment) * Node.js, typescript and ts-node (optional, for plugins) **Ready-to-Use Example Configurations** For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: * `basic-example`: Simple setup with Redis * `basic-example-logging`: Configuration with file-based logging * `basic-example-metrics`: Setup with Prometheus and Grafana metrics * `vault-secret-signer`: Using HashiCorp Vault for key management * `vault-transit-signer`: Using Vault Transit for secure signing * `evm-gcp-kms-signer`: Using Google Cloud KMS for EVM secure signing * `evm-turnkey-signer`: Using Turnkey for EVM secure signing * `solana-turnkey-signer`: Using Turnkey for Solana secure signing * `redis-storage`: Using Redis for Storage * `network-configuration-config-file`: Using Custom network configuration via config file * `network-configuration-json-file`: Using Custom network configuration via JSON file Each example includes a README with step-by-step instructions and Docker Compose configuration. ### [Install Locally](https://docs.openzeppelin.com/relayer#install-locally) 1. Clone the repository: git clone https://github.com/openzeppelin/openzeppelin-relayer cd openzeppelin-relayer 2. Verify you have sodium libs installed. If not, follow these instructions: * Install a stable libsodium version from [here](https://download.libsodium.org/libsodium/releases/) . * Follow the steps in the [libsodium installation guide](https://doc.libsodium.org/installation) . 3. Install dependencies: cargo build [Running the Relayer](https://docs.openzeppelin.com/relayer#running-the-relayer) --------------------------------------------------------------------------------- ### [Option 1: Run Locally](https://docs.openzeppelin.com/relayer#option-1-run-locally) cargo run Before executing the command, ensure that the `.env` and `config.json` files are configured as detailed in the [Configuration References](https://docs.openzeppelin.com/relayer/configuration) section. ### [Option 2: Run with Docker](https://docs.openzeppelin.com/relayer#option-2-run-with-docker) The Relayer can be run as either a development or production container using the corresponding Dockerfile (`Dockerfile.development` or `Dockerfile.production`). #### [Step 1: Configure Environment](https://docs.openzeppelin.com/relayer#step-1-configure-environment) * Edit `.env` at the root of the repository to adjust environment variables * The appropriate .env file will be included during image build #### [Step 2: Build the Image](https://docs.openzeppelin.com/relayer#step-2-build-the-image) You can build using Docker Compose (v2). # Default build docker compose build # Or, for a leaner image (and using Dockerfile.production) DOCKERFILE=Dockerfile.production docker compose build #### [Step 3: Run the Container](https://docs.openzeppelin.com/relayer#step-3-run-the-container) Use Docker Compose to run the container: docker compose up -d For production runs, you can use: DOCKERFILE=Dockerfile.production docker compose up -d [Configuration](https://docs.openzeppelin.com/relayer#configuration) --------------------------------------------------------------------- OpenZeppelin Relayer supports two configuration approaches: _**File-based Configuration:**_ * _**`config.json`**_: Contains relayer definitions, signer configurations, and network policies * _**`.env`**_: Contains environment variables like API keys and connection strings _**API-based Configuration:**_ * Runtime configuration management via REST API * No service restarts required for configuration changes * Full CRUD operations for relayers, signers, and notifications Both approaches can be used together. File-based configuration is loaded on startup, while API changes provide runtime flexibility. Changes to environment variables (`.env`) always require restarting the container. When used together, API changes are not synced to file-based configuration. File-based configuration is loaded only once when using persistent storage mode. For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. For comprehensive configuration details, including: * Environment variables and their settings * Main configuration file structure * Signer configurations (local, vault, cloud KMS, etc.) * Notification setup * Relayer policies and network settings * Plugin configuration * Complete configuration examples See the dedicated [Configuration Guide](https://docs.openzeppelin.com/relayer/configuration) . [Important Considerations](https://docs.openzeppelin.com/relayer#important-considerations) ------------------------------------------------------------------------------------------- [Deployment Considerations](https://docs.openzeppelin.com/relayer#deployment-considerations) --------------------------------------------------------------------------------------------- The OpenZeppelin Relayer is designed to function as a backend service and is not meant to be directly exposed to the public internet. To protect the service from unauthorized access, deploy it behind your own secure backend infrastructure—such as a reverse proxy or firewall—and restrict access to trusted internal components only. Direct exposure can increase the risk of exploitation and security breaches. [Support](https://docs.openzeppelin.com/relayer#support) --------------------------------------------------------- For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/2) . [License](https://docs.openzeppelin.com/relayer#license) --------------------------------------------------------- This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. [Security](https://docs.openzeppelin.com/relayer#security) ----------------------------------------------------------- For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-relayer/blob/main/SECURITY.md) . [WebAuthn Smart Accounts\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts) [Quickstart\ \ Next Page](https://docs.openzeppelin.com/relayer/quickstart) ### On this page [Overview](https://docs.openzeppelin.com/relayer#overview) [Features](https://docs.openzeppelin.com/relayer#features) [Supported Networks](https://docs.openzeppelin.com/relayer#supported-networks) [Network Types](https://docs.openzeppelin.com/relayer#network-types) [Technical Overview](https://docs.openzeppelin.com/relayer#technical-overview) [Project Structure](https://docs.openzeppelin.com/relayer#project-structure) [Getting Started](https://docs.openzeppelin.com/relayer#getting-started) [Prerequisites](https://docs.openzeppelin.com/relayer#prerequisites) [Install Locally](https://docs.openzeppelin.com/relayer#install-locally) [Running the Relayer](https://docs.openzeppelin.com/relayer#running-the-relayer) [Option 1: Run Locally](https://docs.openzeppelin.com/relayer#option-1-run-locally) [Option 2: Run with Docker](https://docs.openzeppelin.com/relayer#option-2-run-with-docker) [Step 1: Configure Environment](https://docs.openzeppelin.com/relayer#step-1-configure-environment) [Step 2: Build the Image](https://docs.openzeppelin.com/relayer#step-2-build-the-image) [Step 3: Run the Container](https://docs.openzeppelin.com/relayer#step-3-run-the-container) [Configuration](https://docs.openzeppelin.com/relayer#configuration) [Important Considerations](https://docs.openzeppelin.com/relayer#important-considerations) [Deployment Considerations](https://docs.openzeppelin.com/relayer#deployment-considerations) [Support](https://docs.openzeppelin.com/relayer#support) [License](https://docs.openzeppelin.com/relayer#license) [Security](https://docs.openzeppelin.com/relayer#security) --- # ERC-4626 | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) ERC-4626 ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) is an extension of [ERC-20](https://docs.openzeppelin.com/contracts/5.x/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 implementation of ERC-4626 that includes a simple vault. This contract is designed in a way that allows developers to easily re-configure the vault’s behavior, with minimal overrides, while staying compliant. In this guide, we will discuss some security considerations that affect ERC-4626. We will also discuss common customizations of the vault. [Security concern: Inflation attack](https://docs.openzeppelin.com/contracts/5.x/erc4626#security-concern-inflation-attack) ---------------------------------------------------------------------------------------------------------------------------- ### [Visualizing the vault](https://docs.openzeppelin.com/contracts/5.x/erc4626#visualizing-the-vault) In exchange for the assets deposited into an ERC-4626 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. ![Exchange rates in linear scale](https://docs.openzeppelin.com/erc4626-rate-linear.png) 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. ![Exchange rates in logarithmic scale](https://docs.openzeppelin.com/erc4626-rate-loglog.png) In such a representation, widely different rates can be clearly visible in the same graph. This wouldn’t be the case in linear scale. ![More exchange rates in logarithmic scale](https://docs.openzeppelin.com/erc4626-rate-loglogext.png) ### [The attack](https://docs.openzeppelin.com/contracts/5.x/erc4626#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 < 1 share worth of tokens, then you get 0 shares, and you basically made 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. ![Depositing assets](https://docs.openzeppelin.com/erc4626-deposit.png) 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%. ![Minting shares](https://docs.openzeppelin.com/erc4626-mint.png) 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. ![Inflation attack without protection](https://docs.openzeppelin.com/erc4626-attack.png) 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: * a0a\_0a0​ the attacker deposit * a1a\_1a1​ the attacker donation * uuu the user deposit | | Assets | Shares | Rate | | --- | --- | --- | --- | | initial | 000 | 000 | \- | | after attacker's deposit | a0a\_0a0​ | a0a\_0a0​ | 111 | | after attacker's donation | a0+a1a\_0 + a\_1a0​+a1​ | a0a\_0a0​ | \\fraca0+a1a0\\fraca\_0 + a\_1a\_0\\fraca0​+a1​a0​ | This means a deposit of uuu will give \\fracu×a0a0+a1\\fracu \\times a\_0a\_0 + a\_1\\fracu×a0​a0​+a1​ shares. For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that u×a0a0+a1<1  ⟺  u<1+a1a0\\frac{u \\times a\_0}{a\_0+a\_1} < 1 \\iff u < 1 + \\frac{a\_1}{a\_0} a0​+a1​u×a0​​<1⟺u<1+a0​a1​​ Using a0\=1a\_0 = 1a0​\=1 and a1\=ua\_1 = ua1​\=u is enough. So the attacker only needs u+1u+1u+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 \\fracun\\fracun\\fracun, the user needs to suffer rounding of a similar fraction, which means the user must receive at most nnn shares. This results in: u×a0a0+a1 0 && recipient != address(this)) { SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); } } /// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}. function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual override { uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints()); address recipient = _exitFeeRecipient(); super._withdraw(caller, receiver, owner, assets, shares); if (fee > 0 && recipient != address(this)) { SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); } } // === Fee configuration === function _entryFeeBasisPoints() internal view virtual returns (uint256) { return 0; // replace with e.g. 100 for 1% } function _exitFeeBasisPoints() internal view virtual returns (uint256) { return 0; // replace with e.g. 100 for 1% } function _entryFeeRecipient() internal view virtual returns (address) { return address(0); // replace with e.g. a treasury address } function _exitFeeRecipient() internal view virtual returns (address) { return address(0); // replace with e.g. a treasury address } // === Fee operations === /// @dev 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. function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Ceil); } /// @dev Calculates the fee part of an amount `assets` that already includes fees. /// Used in {IERC4626-deposit} and {IERC4626-redeem} operations. function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) { return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil); } } [ERC-1155\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc1155) [ERC-6909\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc6909) ### On this page [Security concern: Inflation attack](https://docs.openzeppelin.com/contracts/5.x/erc4626#security-concern-inflation-attack) [Visualizing the vault](https://docs.openzeppelin.com/contracts/5.x/erc4626#visualizing-the-vault) [The attack](https://docs.openzeppelin.com/contracts/5.x/erc4626#the-attack) [Defending with a virtual offset](https://docs.openzeppelin.com/contracts/5.x/erc4626#defending-with-a-virtual-offset) [Custom behavior: Adding fees to the vault](https://docs.openzeppelin.com/contracts/5.x/erc4626#custom-behavior-adding-fees-to-the-vault) --- # OpenZeppelin Monitor | OpenZeppelin Docs OpenZeppelin Monitor ==================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/monitor#overview) ----------------------------------------------------------- In the rapidly evolving world of blockchain technology, effective monitoring is crucial for ensuring security and performance. OpenZeppelin Monitor is a blockchain monitoring service that watches for specific on-chain activities and triggers notifications based on configurable conditions. The service offers multi-chain support with configurable monitoring schedules, flexible trigger conditions, and an extensible architecture for adding new chains. ### [Key Capabilities](https://docs.openzeppelin.com/monitor#key-capabilities) * _**Real-time Monitoring**_: Watch blockchain networks in real-time for specific events and transactions * _**Smart Filtering**_: Use flexible expressions to define exactly what you want to monitor * _**Multi-notification Support**_: Send alerts via Slack, Discord, Email, Telegram, Webhooks, or custom scripts * _**Configurable Scheduling**_: Set custom monitoring schedules using cron expressions * _**Data Persistence**_: Store monitoring data and resume from checkpoints * _**Extensible Architecture**_: Easy to add support for new blockchains and notification types ### [Supported Networks](https://docs.openzeppelin.com/monitor#supported-networks) * _**EVM-Compatible Networks**_ * _**Stellar**_ ### [Notification Channels](https://docs.openzeppelin.com/monitor#notification-channels) * _**Slack**_ - Send formatted messages to Slack channels * _**Discord**_ - Post alerts to Discord channels via webhooks * _**Email**_ - Send email notifications with SMTP support * _**Telegram**_ - Send messages to Telegram chats via bot API * _**Webhooks**_ - Send HTTP requests to custom endpoints * _**Custom Scripts**_ - Execute Python, JavaScript, or Bash scripts To get started immediately, see [Quickstart](https://docs.openzeppelin.com/monitor/quickstart) . [Installation](https://docs.openzeppelin.com/monitor#installation) ------------------------------------------------------------------- ### [Prerequisites](https://docs.openzeppelin.com/monitor#prerequisites) * Use _**Rust 2021 edition**_, version `1.86` or later. * _**Docker**_ (optional, for containerized deployment) ### [Local Installation](https://docs.openzeppelin.com/monitor#local-installation) 1. _**Clone the repository:**_ git clone https://github.com/openzeppelin/openzeppelin-monitor cd openzeppelin-monitor 2. _**Build the application:**_ cargo build --release 3. _**Move binary to project root:**_ mv ./target/release/openzeppelin-monitor . 4. _**Verify installation:**_ ./openzeppelin-monitor --help 5. _**View available options:**_ ./openzeppelin-monitor --help # Enable logging to file ./openzeppelin-monitor --log-file # Enable metrics server ./openzeppelin-monitor --metrics # Validate configuration files without starting the service ./openzeppelin-monitor --check ### [Docker Installation](https://docs.openzeppelin.com/monitor#docker-installation) 1. _**Clone the repository:**_ git clone https://github.com/openzeppelin/openzeppelin-monitor cd openzeppelin-monitor 2. _**Set up environment:**_ cp .env.example .env # Edit .env file with your configuration 3. _**Start with Docker Compose:**_ cargo make docker-compose-up #### [Metrics Configuration](https://docs.openzeppelin.com/monitor#metrics-configuration) The metrics server, Prometheus, and Grafana can be enabled by setting `METRICS_ENABLED=true` in your `.env` file. You can start services directly with Docker Compose: # without metrics profile ( METRICS_ENABLED=false by default ) docker compose up -d # With metrics enabled docker compose --profile metrics up -d To view prometheus metrics in a UI, you can use `http://localhost:9090` on your browser. To view grafana dashboard, you can use `http://localhost:3000` on your browser. By default, predefined metrics within a dashboard is populated in grafana. ### [Configuration Guidelines](https://docs.openzeppelin.com/monitor#configuration-guidelines) #### [Recommended File Naming Conventions](https://docs.openzeppelin.com/monitor#recommended-file-naming-conventions) * Network configurations: `_.json` * Example: `ethereum_mainnet.json`, `stellar_testnet.json` * Should match the `slug` property inside the file * Monitor configurations: `__monitor.json` * Example: `usdc_transfer_monitor.json`, `dai_liquidation_monitor.json` * Referenced by monitors using their `name` property * Trigger configurations: `_.json` * Example: `slack_notifications.json`, `email_alerts.json` * Individual triggers referenced by their configuration key #### [Configuration References](https://docs.openzeppelin.com/monitor#configuration-references) * Monitor, network, and trigger names _**must be unique**_ across all configurations files * Monitor’s `networks` array must contain valid network `slug` values from network configuration files * Monitor’s `triggers` array must contain valid trigger configuration keys * Example valid references: // networks/ethereum_mainnet.json { "slug": "ethereum_mainnet", ... } // triggers/slack_notifications.json { "large_transfer_slack": { ... } } // monitors/usdc_transfer_monitor.json { "networks": ["ethereum_mainnet"], "triggers": ["large_transfer_slack"], ... } Ensure all referenced slugs and trigger keys exist in their respective configuration files. The monitor will fail to start if it cannot resolve these references. #### [Safe Protocol Guidelines](https://docs.openzeppelin.com/monitor#safe-protocol-guidelines) The monitor implements protocol security validations across different components and will issue warnings when potentially insecure configurations are detected. While insecure protocols are not blocked, we strongly recommend following these security guidelines: ##### [Network Protocols](https://docs.openzeppelin.com/monitor#network-protocols) ###### [RPC URLs](https://docs.openzeppelin.com/monitor#rpc-urls) * **HTTPS Recommended**: Using `https://` for RPC endpoints is strongly recommended * **WSS Recommended**: For WebSocket connections, `wss://` (secure WebSocket) is strongly recommended * **Warning**: Using `http://` or `ws://` will trigger security warnings as they transmit data unencrypted ##### [Notification Protocols](https://docs.openzeppelin.com/monitor#notification-protocols) ###### [Webhook Notifications](https://docs.openzeppelin.com/monitor#webhook-notifications) * **HTTPS Recommended**: URLs should use HTTPS protocol * **Authentication Recommended**: Including either: * `X-API-Key` header * `Authorization` header * **Optional Secret**: Can include a secret for HMAC authentication * When a secret is provided, the monitor will: * Generate a timestamp in milliseconds * Create an HMAC-SHA256 signature of the payload and timestamp * Add the signature in the `X-Signature` header * Add the timestamp in the `X-Timestamp` header * The signature is computed as: `HMAC-SHA256(secret, payload + timestamp)` * **Warning**: Non-HTTPS URLs or missing authentication headers will trigger security warnings ###### [Slack Notifications](https://docs.openzeppelin.com/monitor#slack-notifications) * **HTTPS Recommended**: Webhook URLs should start with `https://hooks.slack.com/` * **Warning**: Non-HTTPS URLs will trigger security warnings ###### [Discord Notifications](https://docs.openzeppelin.com/monitor#discord-notifications) * **HTTPS Recommended**: Webhook URLs should start with `https://discord.com/api/webhooks/` * **Warning**: Non-HTTPS URLs will trigger security warnings ###### [Telegram Notifications](https://docs.openzeppelin.com/monitor#telegram-notifications) * _**Protocol:**_ `POST` request with a `application/json` payload to the `sendMessage` method. * _**Endpoint:**_ `https://api.telegram.org/bot/sendMessage` * _**Security:**_ * _**HTTPS Required:**_ The API endpoint uses HTTPS. * Authentication is handled via the _**Bot Token**_ in the URL. Keep this token secure. * _**Formatting:**_ Messages are sent with `parse_mode` set to `MarkdownV2`. Special characters in the message title and body are automatically escaped to prevent formatting errors. ###### [Email Notifications](https://docs.openzeppelin.com/monitor#email-notifications) * **Secure Ports Recommended**: The following ports are considered secure: * 465: SMTPS (SMTP over SSL) * 587: SMTP with STARTTLS * 993: IMAPS (IMAP over SSL) * **Warning**: Using other ports will trigger security warnings * **Valid Format**: Email addresses must follow RFC 5322 format ###### [Notifications Retry Policy](https://docs.openzeppelin.com/monitor#notifications-retry-policy) Following notification protocols support retry policies: * Slack * Discord * Telegram * Webhook * Email Default retry policy is using exponential backoff with the following parameters: | | | | | --- | --- | --- | | Parameter | Default Value | Description | | `max_retries` | `3` | Maximum number of retries before giving up | | `base_for_backoff` | `2` | Base duration for exponential backoff calculations in seconds | | `initial_backoff` | `250` | Initial backoff duration in milliseconds | | `max_backoff` | `10` | Maximum backoff duration in seconds | | `jitter` | `Full` | Jitter strategy to apply to the backoff duration, currently supports `Full` and `None` | These parameters can be overridden by providing custom `RetryConfig` struct in `retry_policy` field in trigger configuration. ##### [Script Security](https://docs.openzeppelin.com/monitor#script-security) ###### [File Permissions (Unix Systems)](https://docs.openzeppelin.com/monitor#file-permissions-unix-systems) * **Restricted Write Access**: Script files should not have overly permissive write permissions * **Recommended Permissions**: Use `644` (`rw-r--r--`) for script files * **Warning**: Files with mode `022` or more permissive will trigger security warnings **Example Setting Recommended Permissions** chmod 644 ./config/filters/my_script.sh #### [Secret Management](https://docs.openzeppelin.com/monitor#secret-management) The monitor implements a secure secret management system with support for multiple secret sources and automatic memory zeroization. ##### [Secret Sources](https://docs.openzeppelin.com/monitor#secret-sources) The monitor supports three types of secret sources: * **Plain Text**: Direct secret values (wrapped in `SecretString` for secure memory handling) * **Environment Variables**: Secrets stored in environment variables * **Hashicorp Cloud Vault**: Secrets stored in Hashicorp Cloud Vault ##### [Security Features](https://docs.openzeppelin.com/monitor#security-features) * **Automatic Zeroization**: Secrets are automatically zeroized from memory when no longer needed * **Type-Safe Resolution**: Secure handling of secret resolution with proper error handling * **Configuration Support**: Serde support for configuration files ##### [Configuration](https://docs.openzeppelin.com/monitor#configuration) Secrets can be configured in the JSON files using the following format: { "type": "Plain", "value": "my-secret-value" } { "type": "Environment", "value": "MY_SECRET_ENV_VAR" } { "type": "HashicorpCloudVault", "value": "my-secret-name" } ##### [Hashicorp Cloud Vault Integration](https://docs.openzeppelin.com/monitor#hashicorp-cloud-vault-integration) To use Hashicorp Cloud Vault, configure the following environment variables: | Environment Variable | Description | | --- | --- | | `HCP_CLIENT_ID` | Hashicorp Cloud Vault client ID | | `HCP_CLIENT_SECRET` | Hashicorp Cloud Vault client secret | | `HCP_ORG_ID` | Hashicorp Cloud Vault organization ID | | `HCP_PROJECT_ID` | Hashicorp Cloud Vault project ID | | `HCP_APP_NAME` | Hashicorp Cloud Vault application name | ##### [Best Practices](https://docs.openzeppelin.com/monitor#best-practices) * Use environment variables or vault for production secrets * Avoid storing plain text secrets in configuration files * Use appropriate access controls for vault secrets * Monitor vault access patterns for suspicious activity #### [Basic Configuration](https://docs.openzeppelin.com/monitor#basic-configuration) * Set up environment variables: Copy the example environment file and update values according to your needs cp .env.example .env This table lists the environment variables and their default values. | Environment Variable | Default Value | Accepted Values | Description | | --- | --- | --- | --- | | `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | | `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | | `LOG_DATA_DIR` | `logs/` | `` | Directory to write log files on host. | | `MONITOR_DATA_DIR` | `null` | `` | Persist monitor data between container restarts. | | `LOG_MAX_SIZE` | `1073741824` | `` | Size after which logs needs to be rolled. Accepts both raw bytes (e.g., "1073741824") or human-readable formats (e.g., "1GB", "500MB"). | | `METRICS_ENABLED` | `false` | `true`, `false` | Enable metrics server for external tools to scrape metrics. | | `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | | `HCP_CLIENT_ID` | \- | `` | Hashicorp Cloud Vault client ID for secret management. | | `HCP_CLIENT_SECRET` | \- | `` | Hashicorp Cloud Vault client secret for secret management. | | `HCP_ORG_ID` | \- | `` | Hashicorp Cloud Vault organization ID for secret management. | | `HCP_PROJECT_ID` | \- | `` | Hashicorp Cloud Vault project ID for secret management. | | `HCP_APP_NAME` | \- | `` | Hashicorp Cloud Vault application name for secret management. | * Copy and configure some example files: # EVM Configuration cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json # Stellar Configuration cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json # Notification Configuration cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json # Filter Configuration cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh ### [Command Line Options](https://docs.openzeppelin.com/monitor#command-line-options) The monitor supports several command-line options for configuration and control: | **Option** | **Default** | **Description** | | --- | --- | --- | | `**--log-file**` | `false` | Write logs to file instead of stdout | | `**--log-level**` | `info` | Set log level (trace, debug, info, warn, error) | | `**--log-path**` | `logs/` | Path to store log files | | `**--log-max-size**` | `1GB` | Maximum log file size before rolling | | `**--metrics-address**` | `127.0.0.1:8081` | Address to start the metrics server on | | `**--metrics**` | `false` | Enable metrics server | | `**--monitor-path**` | \- | Path to the monitor to execute (for testing) | | `**--network**` | \- | Network to execute the monitor for (for testing) | | `**--block**` | \- | Block number to execute the monitor for (for testing) | | `**--check**` | `false` | Validate configuration files without starting the service | [Data Storage Configuration](https://docs.openzeppelin.com/monitor#data-storage-configuration) ----------------------------------------------------------------------------------------------- The monitor uses file-based storage by default. ### [File Storage](https://docs.openzeppelin.com/monitor#file-storage) When `store_blocks` is enabled in the network configuration, the monitor stores: * Processed blocks: `./data/_blocks_.json` * Missed blocks: `./data/_missed_blocks.txt` (used to store missed blocks) The content of the `missed_blocks.txt` file may help to determine the right `max_past_blocks` value based on the network’s block time and the monitor’s cron schedule. Additionally, the monitor will always store: * Last processed block: `./data/_last_block.txt` (enables resuming from last checkpoint) [Configuration Files](https://docs.openzeppelin.com/monitor#configuration-files) --------------------------------------------------------------------------------- ### [Network Configuration](https://docs.openzeppelin.com/monitor#network-configuration) A Network configuration defines connection details and operational parameters for a specific blockchain network, supporting both EVM and Stellar-based chains. **Example Network Configuration** { "network_type": "Stellar", "slug": "stellar_mainnet", "name": "Stellar Mainnet", "rpc_urls": [\ {\ "type_": "rpc",\ "url": {\ "type": "plain",\ "value": "https://soroban.stellar.org"\ },\ "weight": 100\ }\ ], "network_passphrase": "Public Global Stellar Network ; September 2015", "block_time_ms": 5000, "confirmation_blocks": 2, "cron_schedule": "0 */1 * * * *", "max_past_blocks": 20, "store_blocks": true } #### [Available Fields](https://docs.openzeppelin.com/monitor#available-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**network_type**` | `String` | Type of blockchain (**"EVM"** or **"Stellar"**) | | `**slug**` | `String` | **Required** - **_Unique_** identifier for the network | | `**name**` | `String` | **Required** - **_Unique_** Human-readable network name | | `**rpc_urls**` | `Array[Object]` | List of RPC endpoints with weights for load balancing | | `**chain_id**` | `Number` | Network chain ID (**EVM only**) | | `**network_passphrase**` | `String` | Network identifier (**Stellar only**) | | `**block_time_ms**` | `Number` | Average block time in milliseconds | | `**confirmation_blocks**` | `Number` | Number of blocks to wait for confirmation | | `**cron_schedule**` | `String` | Monitor scheduling in cron format | | `**max_past_blocks**` | `Number` | Maximum number of past blocks to process | | `**store_blocks**` | `Boolean` | Whether to store processed blocks (defaults output to `./data/` directory) | #### [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations) * We strongly recommend using private RPC providers for improved reliability. ### [Trigger Configuration](https://docs.openzeppelin.com/monitor#trigger-configuration) A Trigger defines actions to take when monitored conditions are met. Triggers can send notifications, make HTTP requests, or execute scripts. **Example Trigger Configuration** { "evm_large_transfer_usdc_slack": { "name": "Large Transfer Slack Notification", "trigger_type": "slack", "config": { "slack_url": { "type": "plain", "value": "https://hooks.slack.com/services/A/B/C" }, "message": { "title": "large_transfer_slack triggered", "body": "Large transfer of ${events.0.args.value} USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" } } }, "stellar_large_transfer_usdc_slack": { "name": "Large Transfer Slack Notification", "trigger_type": "slack", "config": { "slack_url": { "type": "environment", "value": "SLACK_WEBHOOK_URL" }, "message": { "title": "large_transfer_usdc_slack triggered", "body": "${monitor.name} triggered because of a large transfer of $functions.0.args.amount USDC to $functions.0.args.to | https://stellar.expert/explorer/testnet/tx/$transaction.hash" } } } } #### [Trigger Types](https://docs.openzeppelin.com/monitor#trigger-types) ##### [Slack Notifications](https://docs.openzeppelin.com/monitor#slack-notifications-1) { "slack_url": { "type": "HashicorpCloudVault", "value": "slack-webhook-url" }, "message": { "title": "Alert Title", "body": "Alert message for ${transaction.hash}" } } ##### [Slack Notification Fields](https://docs.openzeppelin.com/monitor#slack-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"slack"** for Slack notifications | | `**config.slack_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.slack_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | | `**config.message.title**` | `String` | Title that appears in the Slack message | | `**config.message.body**` | `String` | Message template with variable substitution | ##### [Email Notifications](https://docs.openzeppelin.com/monitor#email-notifications-1) { "host": "smtp.gmail.com", "port": 465, "username": { "type": "plain", "value": "sender@example.com" }, "password": { "type": "environment", "value": "SMTP_PASSWORD" }, "message": { "title": "Alert Subject", "body": "Alert message for ${transaction.hash}" }, "sender": "sender@example.com", "recipients": ["recipient@example.com"] } ##### [Email Notification Fields](https://docs.openzeppelin.com/monitor#email-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"email"** for email notifications | | `**config.host**` | `String` | SMTP server hostname | | `**config.port**` | `Number` | SMTP port (defaults to **465**) | | `**config.username.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.username.value**` | `String` | Secret value (username, environment variable name, or vault secret name) | | `**config.password.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.password.value**` | `String` | Secret value (password, environment variable name, or vault secret name) | | `**config.message.title**` | `String` | Email subject line | | `**config.message.body**` | `String` | Email body template with variable substitution | | `**config.sender**` | `String` | Sender email address | | `**config.recipients**` | `Array[String]` | List of recipient email addresses | ##### [Webhook Notifications](https://docs.openzeppelin.com/monitor#webhook-notifications-1) { "url": { "type": "HashicorpCloudVault", "value": "webhook-url" }, "method": "POST", "secret": { "type": "environment", "value": "WEBHOOK_SECRET" }, "headers": { "Content-Type": "application/json" }, "message": { "title": "Alert Title", "body": "Alert message for ${transaction.hash}" } } ##### [Webhook Notification Fields](https://docs.openzeppelin.com/monitor#webhook-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"webhook"** for webhook notifications | | `**config.url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | | `**config.method**` | `String` | HTTP method (POST, GET, etc.) defaults to POST | | `**config.secret.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.secret.value**` | `String` | Secret value (HMAC secret, environment variable name, or vault secret name) | | `**config.headers**` | `Object` | Headers to include in the webhook request | | `**config.message.title**` | `String` | Title that appears in the webhook message | | `**config.message.body**` | `String` | Message template with variable substitution | ##### [Discord Notifications](https://docs.openzeppelin.com/monitor#discord-notifications-1) { "discord_url": { "type": "plain", "value": "https://discord.com/api/webhooks/123-456-789" }, "message": { "title": "Alert Title", "body": "Alert message for ${transaction.hash}" } } ##### [Discord Notification Fields](https://docs.openzeppelin.com/monitor#discord-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"discord"** for Discord notifications | | `**config.discord_url.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.discord_url.value**` | `String` | Secret value (URL, environment variable name, or vault secret name) | | `**config.message.title**` | `String` | Title that appears in the Discord message | | `**config.message.body**` | `String` | Message template with variable substitution | ##### [Telegram Notifications](https://docs.openzeppelin.com/monitor#telegram-notifications-1) { "token": { "type": "HashicorpCloudVault", "value": "telegram-bot-token" }, "chat_id": "9876543210", "message": { "title": "Alert Title", "body": "Alert message for ${transaction.hash}" } } ##### [Telegram Notification Fields](https://docs.openzeppelin.com/monitor#telegram-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"telegram"** for Telegram notifications | | `**config.token.type**` | `String` | Secret type (**"Plain"**, **"Environment"**, or **"HashicorpCloudVault"**) | | `**config.token.value**` | `String` | Secret value (bot token, environment variable name, or vault secret name) | | `**config.chat_id**` | `String` | Telegram chat ID | | `**config.disable_web_preview**` | `Boolean` | Whether to disable web preview in Telegram messages (defaults to false) | | `**config.message.title**` | `String` | Title that appears in the Telegram message | | `**config.message.body**` | `String` | Message template with variable substitution | ##### [Custom Script Notifications](https://docs.openzeppelin.com/monitor#custom-script-notifications) { "language": "Bash", "script_path": "./config/triggers/scripts/custom_notification.sh", "arguments": ["--verbose"], "timeout_ms": 1000 } ##### [Script Notification Fields](https://docs.openzeppelin.com/monitor#script-notification-fields) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** Human-readable name for the notification | | `**trigger_type**` | `String` | Must be **"script"** for Custom Script notifications | | `**language**` | `String` | The language of the script | | `**script_path**` | `String` | The path to the script | | `**arguments**` | `Array[String]` | The arguments of the script (optional). | | `**timeout_ms**` | `Number` | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed. | For more information about custom scripts, see [Custom Scripts Section](https://docs.openzeppelin.com/monitor/scripts) . _**Security Risk**_: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. #### [Available Template Variables](https://docs.openzeppelin.com/monitor#available-template-variables) The monitor uses a structured JSON format with nested objects for template variables. The data is flattened into dot notation for template use. ##### [Common Variables](https://docs.openzeppelin.com/monitor#common-variables) | **Variable** | **Description** | | --- | --- | | `**monitor.name**` | Name of the triggered monitor | | `**transaction.hash**` | Hash of the transaction | | `**functions.[index].signature**` | Function signature | | `**events.[index].signature**` | Event signature | ##### [Network-Specific Variables](https://docs.openzeppelin.com/monitor#network-specific-variables) ###### [EVM Variables](https://docs.openzeppelin.com/monitor#evm-variables) | **Variable** | **Description** | | --- | --- | | `**transaction.from**` | Sender address | | `**transaction.to**` | Recipient address | | `**transaction.value**` | Transaction value | | `**events.[index].args.[param]**` | Event parameters by name | | `**functions.[index].args.[param]**` | Function parameters by name | ###### [Stellar Variables](https://docs.openzeppelin.com/monitor#stellar-variables) | **Variable** | **Description** | | --- | --- | | `**events.[index].args.[position]**` | Event parameters by position | | `**functions.[index].args.[param]**` | Function parameters by name | Transaction-related variables (`transaction.from`, `transaction.to`, `transaction.value`) are not available for Stellar networks. #### [Message Formatting](https://docs.openzeppelin.com/monitor#message-formatting) Slack, Discord, Telegram, Email and Webhook support Markdown formatting in their message bodies. You can use Markdown syntax to enhance your notifications. ##### [Example Email Notification with Markdown](https://docs.openzeppelin.com/monitor#example-email-notification-with-markdown) { "email_notification": { "name": "Formatted Alert", "trigger_type": "email", "config": { "host": "smtp.example.com", "port": 465, "username": {"type": "plain", "value": "alerts@example.com"}, "password": {"type": "plain", "value": "password"}, "message": { "title": "**High Value Transfer Alert**", "body": "### Transaction Details\n\n* **Amount:** ${events.0.args.value} USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n> Transaction Hash: $transaction.hash\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" }, "sender": "alerts@example.com", "recipients": ["recipient@example.com"] } } } ##### [Example Slack Notification with Markdown](https://docs.openzeppelin.com/monitor#example-slack-notification-with-markdown) { "slack_notification": { "name": "Formatted Alert", "trigger_type": "slack", "config": { "slack_url": {"type": "plain", "value": "https://hooks.slack.com/services/XXX/YYY/ZZZ"}, "message": { "title": "*🚨 High Value Transfer Alert*", "body": "*Transaction Details*\n\n• *Amount:* `${events.0.args.value}` USDC\n• *From:* `$events.0.args.from`\n• *To:* `$events.0.args.to`\n\n>Transaction Hash: `$transaction.hash`\n\n" } } } } ##### [Example Discord Notification with Markdown](https://docs.openzeppelin.com/monitor#example-discord-notification-with-markdown) { "discord_notification": { "name": "Formatted Alert", "trigger_type": "discord", "config": { "discord_url": {"type": "plain", "value": "https://discord.com/api/webhooks/XXX/YYY"}, "message": { "title": "**🚨 High Value Transfer Alert**", "body": "# Transaction Details\n\n* **Amount:** `${events.0.args.value}` USDC\n* **From:** `$events.0.args.from`\n* **To:** `$events.0.args.to`\n\n>>> Transaction Hash: `$transaction.hash`\n\n**[View on Explorer](https://etherscan.io/tx/$transaction.hash)" } } } } ##### [Example Telegram Notification with Markdown](https://docs.openzeppelin.com/monitor#example-telegram-notification-with-markdown) { "telegram_notification": { "name": "Formatted Alert", "trigger_type": "telegram", "config": { "token": {"type": "plain", "value": "1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, "chat_id": "9876543210", "message": { "title": "*🚨 High Value Transfer Alert*", "body": "*Transaction Details*\n\n• *Amount:* `${events.0.args.value}` USDC\n• *From:* `$events.0.args.from`\n• *To:* `$events.0.args.to`\n\n`Transaction Hash: $transaction.hash`\n\n[View on Explorer](https://etherscan.io/tx/$transaction.hash)" } } } } #### [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-1) * Email notification port defaults to 465 if not specified. * Template variables are context-dependent: * Event-triggered notifications only populate event variables. * Function-triggered notifications only populate function variables. * Mixing contexts results in empty values. * Credentials in configuration files should be properly secured. * Consider using environment variables for sensitive information. ### [Monitor Configuration](https://docs.openzeppelin.com/monitor#monitor-configuration) A Monitor defines what blockchain activity to watch and what actions to take when conditions are met. Each monitor combines: * Network targets (which chains to monitor) * Contract addresses to watch * Conditions to match (functions, events, transactions) * Trigger conditions (custom scripts that act as filters for each monitor match to determine whether a trigger should be activated). * Triggers to execute when conditions are met **Example Monitor Configuration** { "name": "Large USDC Transfers", "networks": ["ethereum_mainnet"], "paused": false, "addresses": [\ {\ "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",\ "contract_spec": [ ... ]\ }\ ], "match_conditions": { "functions": [\ {\ "signature": "transfer(address,uint256)",\ "expression": "value > 1000000"\ }\ ], "events": [\ {\ "signature": "Transfer(address,address,uint256)",\ "expression": "value > 1000000"\ }\ ], "transactions": [\ {\ "status": "Success",\ "expression": "value > 1500000000000000000"\ }\ ] }, "trigger_conditions": [\ {\ "script_path": "./config/filters/evm_filter_block_number.sh",\ "language": "bash",\ "arguments": ["--verbose"],\ "timeout_ms": 1000\ }\ ], "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] } #### [Available Fields](https://docs.openzeppelin.com/monitor#available-fields-1) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**name**` | `String` | **Required** - **_Unique_** identifier for this monitor | | `**networks**` | `Array[String]` | List of network slugs this monitor should watch | | `**paused**` | `Boolean` | Whether this monitor is currently paused | | `**addresses**` | `Array[Object]` | Contract addresses to monitor with optional ABIs | | `**match_conditions**` | `Object` | Collection of conditions that can trigger the monitor | | `**trigger_conditions**` | `Array[Object]` | Collection of filters to apply to monitor matches before executing triggers | | `**triggers**` | `Array[String]` | IDs of triggers to execute when conditions match | #### [Match Conditions](https://docs.openzeppelin.com/monitor#match-conditions) Monitors support three types of match conditions that can be combined: ##### [Function Conditions](https://docs.openzeppelin.com/monitor#function-conditions) Match specific function calls to monitored contracts: { "functions": [\ {\ "signature": "transfer(address,uint256)",\ "expression": "value > 1000"\ }\ ] } ##### [Event Conditions](https://docs.openzeppelin.com/monitor#event-conditions) Match events emitted by monitored contracts: { "events": [\ {\ "signature": "Transfer(address,address,uint256)",\ "expression": "value > 1000000"\ }\ ] } ##### [Transaction Conditions](https://docs.openzeppelin.com/monitor#transaction-conditions) Match transaction properties. The available fields and expression syntax depend on the network type (EVM/Stellar) { "transactions": [\ {\ "status": "Success", // Only match successful transactions\ "expression": "value > 1500000000000000000" // Match transactions with value greater than 1.5 ETH\ }\ ] } #### [Available Transaction Fields (EVM)](https://docs.openzeppelin.com/monitor#available-transaction-fields-evm) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**value**` | `uint256` | Transaction value in wei | | `**from**` | `address` | Sender address (case-insensitive comparison) | | `**to**` | `address` | Recipient address (case-insensitive comparison) | | `**hash**` | `string` | Transaction hash | | `**gas_price**` | `uint256` | Gas price in wei (legacy transactions) | | `**max_fee_per_gas**` | `uint256` | EIP-1559 maximum fee per gas | | `**max_priority_fee_per_gas**` | `uint256` | EIP-1559 priority fee | | `**gas_limit**` | `uint256` | Gas limit for transaction | | `**nonce**` | `uint256` | Sender nonce | | `**input**` | `string` | Hex-encoded input data (e.g., **"0xa9059cbb..."**) | | `**gas_used**` | `uint256` | Actual gas used (from receipt) | | `**transaction_index**` | `uint64` | Position in block | #### [Available Transaction Fields (Stellar)](https://docs.openzeppelin.com/monitor#available-transaction-fields-stellar) | **Field** | **Type** | **Description** | | --- | --- | --- | | `**hash**` | `string` | Transaction hash | | `**ledger**` | `i64` | Ledger sequence number where the transaction was included | | `**value**` | `i64` | Value associated with the **first** relevant operation (e.g., payment amount). Defaults to 0 if no relevant operation or value is found. | | `**from**` | `address` | Source account address of the **first** relevant operation (e.g., payment sender). Case-insensitive comparison. | | `**to**` | `address` | Destination account address of the **first** relevant operation (e.g., payment recipient or invoked contract). Case-insensitive comparison. | #### [Matching Rules](https://docs.openzeppelin.com/monitor#matching-rules) * If no conditions are specified, all transactions match * For multiple condition types: * Transaction conditions are checked first * Then either function OR event conditions must match * Both transaction AND (function OR event) must match if both specified ### [Expressions](https://docs.openzeppelin.com/monitor#expressions) Expressions allow for condition checking of function arguments, event parameters, and transaction fields. **Supported Parameter/Field Types and Basic Operations:** | Type | Description | Example Operators | Notes | | --- | --- | --- | --- | | `**Numeric (uint/int variants)**` | Integer values (e.g., `42`, `-100`) or decimal values (e.g., `3.14`, `-0.5`). | `>`, `>=`, `<`, `<=`, `==`, `!=` | Numbers must have digits before and after a decimal point if one is present (e.g., `.5` or `5.` are not valid standalone numbers). | | `**Address**` | Blockchain addresses. | `==`, `!=` | Comparisons (e.g., `from == '0xABC...'`) are typically case-insensitive regarding the hex characters of the address value itself. | | `**String**` | Text values. Can be single-quoted (e.g., ’hello'`) or, on the right-hand side of a comparison, unquoted (e.g.,` active\`). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Quoted strings support `\'` to escape a single quote and `\\` to escape a backslash. All string comparison operations (e.g., `name == 'Alice'`, `description contains 'error'`) are performed case-insensitively during evaluation. See the dedicated "String Operations" section for more examples and details. | | `**Boolean**` | True or false values. | `==`, `!=` | Represented as `true` or `false`. These keywords are parsed case-insensitively (e.g., `TRUE`, `False` are also valid in expressions). | | `**Hex String Literal**` | A string literal starting with `0x` or `0X` followed by hexadecimal characters (0-9, a-f, A-F). | `==`, `!=`, `starts_with`, `ends_with`, `contains` | Treated as a string for comparison purposes (e.g., `input_data starts_with '0xa9059cbb'`). Comparison is case-sensitive for the hex characters after `0x`. | | `**Array (EVM/Stellar)**` | Ordered list of items. For Stellar, often a JSON string in config (e.g., ’\["a", "id":1\]'\`). For EVM, typically decoded from ABI parameters. | `contains`, `==`, `!=`, `[index]` | Detailed operations, including indexed access and behavior of `contains`, vary by network. See "Operations on Complex Types" below. | | `**Object/Map (Stellar)**` | Key-value pairs, typically represented as a JSON string in config (e.g., ’"key": "value", "id": 123'\`). | `.key_access`, `==`, `!=` | Supports dot notation for field access (e.g., `data.id`). See "Operations on Complex Types" for details. | | `**Vec (Stellar)**` | Ordered list, where the parameter’s value can be a CSV string (e.g., `"foo,bar"`) or a JSON array string (e.g., ’\["foo","bar"\]'\`). | `contains`, `==`, `!=` | Behavior of `contains` and `==` differs based on whether the value is CSV or a JSON array string. See "Operations on Complex Types" for details. | **Logical Operators:** * AND - All conditions must be true * OR - At least one condition must be true * () - Parentheses for grouping * AND has higher precedence than OR (i.e., AND operations are evaluated before OR operations if not grouped by parentheses) **Variable Naming and Access (Left-hand side of conditions):** The left-hand side (LHS) of a condition specifies the data field or parameter whose value you want to evaluate. **Base Names:** * These are the direct names of parameters or fields, such as `amount`, `from`, `status`, or event parameter indices like `0`, `1` (common in Stellar events). * Base names can consist of alphanumeric characters (a-z, A-Z, 0-9) and underscores (`_`). * They can start with a letter, an underscore, or a digit. Starting with a digit is primarily relevant for numerically indexed parameters (e.g., Stellar event parameters). * **Important:** Variable names are case-sensitive during evaluation. The name used in the expression must exactly match the casing of the field name in the source data (e.g., from an ABI or blockchain data structure). For example, if a field is named `TotalValue` in the data, an expression using `totalvalue` will not find it. * Variable names cannot be keywords (e.g., `true`, `AND`, `OR`, `contains`). Keywords themselves are parsed case-insensitively. **Path Accessors (for complex types):** If a base parameter is a complex type like an object, map, or array, you can access its internal data using accessors: **Key Access:** Use dot notation (`.`) to access properties of an object or map. * Examples: `transaction.value`, `user.name`, `data.0` (if `0` is a valid key name as a string). * Keys typically consist of alphanumeric characters and underscores. They usually start with a letter or underscore, but purely numeric keys (e.g., `.0`, `.123`) are also supported for map-like structures where keys might be strings representing numbers. * Keys cannot contain hyphens (`-`). **Index Access:** Use bracket notation (`[]`) to access elements of an array by their zero-based integer index. * Examples: `my_array[0]`, `log_entries[3]`. * The index must be a non-negative integer. **Combined Access:** You can combine key and index accessors to navigate nested structures. * Example: `event.data_array[0].property` (accesses the `property` field of the first object in `data_array`, which is part of `event`). * Example: `map.numeric_key_as_string_0[1].name` (accesses the `name` property of the second element of an array stored under the key `0` in `map`). **String Operations:** Several operators are available for matching patterns and comparing string values. These are particularly useful for EVM transaction `input` data, Stellar parameters defined with `kind: "string"`, or any other field that contains text. * `string_param starts_with 'prefix'`:: Checks if the string parameter’s value begins with the specified `prefix`. Example: `transaction.input starts_with '0xa9059cbb'` (checks for ERC20 transfer function selector). * `string_param ends_with 'suffix'`:: Checks if the string parameter’s value ends with the specified `suffix`. Example: `file_name ends_with '.txt'` * `string_param contains 'substring'`:: Checks if the string parameter’s value contains the specified `substring` anywhere within it. Example: `message contains 'error'` * `string_param == 'exact_string'`:: Checks if the string parameter’s value is exactly equal to `exact_string`. * `string_param != 'different_string'`:: Checks if the string parameter’s value is not equal to `different_string`. **Important Notes on String Operations:** * **Operator Keywords:** The operator keywords themselves (`starts_with`, `ends_with`, `contains`, `AND`, `OR`, `true`, `false`, comparison symbols like `==`, `>`) are parsed case-insensitively. For example, `CONTAINS` is treated the same as `contains`, and `TRUE` is the same as `true`. * **Case-Insensitive Evaluation for String Comparisons:** When comparing string data (e.g., from event parameters, transaction fields, or function arguments) with literal string values in your expression, all standard string operations perform a _**case-insensitive**_ comparison during evaluation. * Equality (`==`) and Inequality (`!=`) * Pattern matching (`starts_with`, `ends_with`, `contains`) * **Variable Name Case Sensitivity:** It is important to distinguish this from variable names (the left-hand side of your condition, e.g., `status`). Variable names **are** case-sensitive and must exactly match the field names in your source data (ABI, etc.). **Whitespace Handling:** Flexible whitespace is generally allowed around operators, parentheses, and keywords for readability. However, whitespace within quoted string literals is significant and preserved. #### [Operations on Complex Types](https://docs.openzeppelin.com/monitor#operations-on-complex-types) Beyond simple primitive types, expressions can also interact with more complex data structures like arrays, objects, and vectors. ##### [EVM Specifics](https://docs.openzeppelin.com/monitor#evm-specifics) **Array Operations (`kind: "array"`)** When an EVM parameter is an array (often represented internally or configured with `kind: "array"` and its value being a JSON string representation if manually configured), the following operations are supported: * `array_param contains 'value'` checks if the string ’value'\` exists within the array. * `array_param == '["raw_json_array_string"]'` string comparison of the array’s entire JSON string representation against the provided string * `array_param != '["raw_json_array_string"]'` the negation of the above * `array_param[0]` indexed access ##### [Stellar Specifics](https://docs.openzeppelin.com/monitor#stellar-specifics) **Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** * `object_param.key == 'value'` checks if the object or map has a key named `key` with the value ’value'\`. * `object_param.nested_key.another_key > 100` checks if the nested key `another_key` within `nested_key` has a value greater than 100. * `object_param == '"raw_json_object_string"'` checks if the object or map matches the provided JSON string representation. * `object_param != '"raw_json_object_string"'` the negation of the above **Array (`kind: "array"`) Operations** * `array_param[index]` accesses the element at the specified `index` in the array. * `array_param[0] == 'value'` checks if the first element in the array is equal to ’value'\`. * `array_param[1].property == 'value'` checks if the second element in the array has a property named `property` with the value ’value'\`. * `array_param contains 'value'` checks if the array contains the string ’value'\`. * `array_param == '["raw_json_array_string"]'` checks if the array matches the provided JSON string representation. * `array_param != '["raw_json_array_string"]'` the negation of the above **Vector (`kind: "vec"`) Operations** When a Stellar parameter has `kind: "vec"`, its value can be either a CSV string or a JSON array string. * `vec_param contains 'item'` checks if the vector contains the string ’item'\`. This works for both CSV and JSON array strings. * `vec_param == 'raw_string_value'` checks if the vector matches the provided raw string value. This works for both CSV and JSON array strings. * `vec_param != 'raw_string_value'` the negation of the above **Event Parameter Access (Stellar)** Stellar event parameters are typically accessed by their numeric index as the base variable name (e.g., `0`, `1`, `2`). If an indexed event parameter is itself a complex type (like an array or map, represented as a JSON string), you can then apply the respective access methods: * If event parameter `0` (kind: "Map") is ’"id": 123, "name": "Test"'\`: * `0.id == 123` * `0.name contains 'est'` (case-insensitive) * If event parameter `1` (kind: "array") is ’\["alpha", "val": "beta"\]'\`: * `1[0] == 'ALPHA'` (case-insensitive) * `1[1].val == 'Beta'` (case-insensitive) * `1 contains 'beta'` (case-insensitive deep search) ##### [EVM Examples](https://docs.openzeppelin.com/monitor#evm-examples) These examples assume common EVM event parameters or transaction fields. **Basic Comparisons** // Numeric "transaction.value > 1000000000000000000" // Value greater than 1 ETH "event.amount <= 500" "block.number == 12345678" // String (case-insensitive evaluation for '==' and 'contains') "transaction.to == '0xdeadbeef...'" // Address check (address value comparison itself is case-insensitive) "event.token_name == 'mytoken'" "transaction.input contains 'a9059cbb'" // Checks for ERC20 transfer selector // Boolean "receipt.status == true" // or simply "receipt.status" if boolean field can be evaluated directly "event.isFinalized == false" **Logical Operators** "transaction.value > 1000 AND event.type == 'Deposit'" "(receipt.status == true OR event.fallback_triggered == true) AND user.is_whitelisted == false" **String Operations** "transaction.input starts_with '0xa9059cbb'" // Case-insensitive for the operation "event.message ends_with 'failed'" "event.details contains 'critical alert'" **Array Operations** Assume `event.ids` is `[10, 20, 30]` and `event.participants` is `["user": "Alice", "role": "admin", "user": "Bob", "role": "editor"]`. "event.ids[0] == 10" "event.ids contains '20'" // Checks for string '20' (case-insensitive) "event.participants contains 'Alice'" // True (deep search, case-insensitive) "event.participants contains 'editor'" // True (deep search, case-insensitive) "event.participants == '[\"user\": \"Alice\", \"role\": \"admin\", \"user\": \"Bob\", \"role\": \"editor\"]'" // Raw JSON match (case-sensitive for structure and keys) ##### [Stellar Examples](https://docs.openzeppelin.com/monitor#stellar-examples) **Basic Comparisons** // Numeric "event.params.amount > 10000000" // Accessing 'amount' field in an object 'params' "ledger.sequence >= 123456" // String (case-insensitive evaluation for '==' and 'contains') "event.params.recipient == 'GBD22...'" // Address check "event.type == 'payment_processed'" // Boolean "transaction.successful == true" "event.data.is_verified == false" **Logical Operators** "event.data.value > 500 AND event.source_account == 'GCA7Z...'" "(event.type == 'TRANSFER' OR event.type == 'PAYMENT') AND event.params.asset_code == 'XLM'" **String Operations** "event.contract_id starts_with 'CA23...'" "event.memo ends_with '_TEST'" "event.params.description contains 'urgent'" **Object (`kind: "object"`) / Map (`kind: "Map"`) Operations** Assume `event.details` (kind: "Map") is ’"id": 123, "user": "name": "CHarlie", "status": "Active", "tags": \["new"\]'\`. "event.details.id == 123" "event.details.user.name == 'charlie'" // Case-insensitive string comparison "event.details.user.status contains 'act'" // Case-insensitive contains "event.details.tags == '[\"new\"]'" // Raw JSON string match for the 'tags' field **Array (`kind: "array"`) Operations** Assume `event.items` (kind: "array") is ’\["sku": "A1", "qty": 10, "sku": "B2", "qty": 5, "notes":"Rush order"\]'\`. "event.items[0].sku == 'a1'" "event.items[1].qty < 10" "event.items contains 'A1'" // Deep search (case-insensitive) "event.items contains 'rush order'" // Deep search (case-insensitive) **Vector (`kind: "vec"`) Operations** Assume `csv_data` (kind: "vec") is `"ALPHA,Bravo,Charlie"` and `json_array_data` (kind: "vec") is ’\["Delta", "id": "ECHO", "Foxtrot"\]'\`. "csv_data contains 'bravo'" // Case-insensitive CSV element match "csv_data == 'ALPHA,Bravo,Charlie'" // Raw string match "json_array_data contains 'delta'" // Case-insensitive deep search (like array) "json_array_data contains 'ECHO'" // Case-insensitive deep search (like array) **Event Parameter Access (Numerically Indexed)** Assume event parameter `0` is `12345` (u64), `1` (kind: "array") is ’\["Val1", "VAL2"\]'`, and` 2 `(kind: "Map") is ’"keyA": "dataX", "keyB": 789'`. "0 > 10000" "1[0] == 'val1'" "1 contains 'val2'" "2.keyA == 'DATAX'" "2.keyB < 1000" With SEP-48 support, Stellar functions can now reference parameters by name (e.g., `amount > 1000`) instead of position (e.g., `2 > 1000`). Events still use indexed parameters until SEP-48 support is added for events. You can find the contract specification through Stellar contract explorer tool. For example: [Stellar DEX Contract Interface](https://lab.stellar.org/smart-contracts/contract-explorer?$=network$id=mainnet&label=Mainnet&horizonUrl=https:////horizon.stellar.org&rpcUrl=https:////mainnet.sorobanrpc.com&passphrase=Public%20Global%20Stellar%20Network%20/;%20September%202015;&smartContracts$explorer$contractId=CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE;;) #### [Trigger Conditions (Custom filters)](https://docs.openzeppelin.com/monitor#trigger-conditions-custom-filters) Custom filters allow you to create sophisticated filtering logic for processing monitor matches. These filters act as additional validation layers that determine whether a match should trigger the execution of a trigger or not. For more information about custom scripts, see [Custom Scripts Section](https://docs.openzeppelin.com/monitor/scripts) . _**Security Risk**_: Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. **Example Trigger Conditions Configuration** { "script_path": "./config/filters/evm_filter_block_number.sh", "language": "Bash", "arguments": ["--verbose"], "timeout_ms": 1000 } #### [Available Fields](https://docs.openzeppelin.com/monitor#available-fields-2) ##### [Trigger Conditions Fields](https://docs.openzeppelin.com/monitor#trigger-conditions-fields) | Field | Type | Description | | --- | --- | --- | | `**script_path**` | String | The path to the script | | `**language**` | String | The language of the script | | `**arguments**` | Array\[String\] | The arguments of the script (optional). | | `**timeout_ms**` | Number | The timeout of the script is important to avoid infinite loops during the execution. If the script takes longer than the timeout, it will be killed and the match will be included by default. | #### [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-2) * Network slugs in the monitor must match valid network configurations. * Trigger IDs must match configured triggers. * Expression syntax and available variables differ between EVM and Stellar networks. * ABIs can be provided in two ways: * For EVM networks: Through the monitor configuration using standard Ethereum ABI format * For Stellar networks: Through the monitor configuration using SEP-48 format, or automatically fetched from the chain if not provided * The monitoring frequency is controlled by the network’s `cron_schedule`. * Each monitor can watch multiple networks and addresses simultaneously. * Monitors can be paused without removing their configuration. [Running the Monitor](https://docs.openzeppelin.com/monitor#running-the-monitor) --------------------------------------------------------------------------------- ### [Local Execution](https://docs.openzeppelin.com/monitor#local-execution) 1. _**Basic startup:**_ ./openzeppelin-monitor 2. _**With logging to file:**_ ./openzeppelin-monitor --log-file 3. _**With metrics enabled:**_ ./openzeppelin-monitor --metrics 4. _**Validate configuration without starting:**_ ./openzeppelin-monitor --check ### [Docker Execution](https://docs.openzeppelin.com/monitor#docker-execution) 1. _**Start all services:**_ cargo make docker-compose-up 2. _**With metrics and monitoring (Prometheus + Grafana):**_ # Set METRICS_ENABLED=true in .env file, then: docker compose --profile metrics up -d 3. _**View logs:**_ docker compose logs -f monitor 4. _**Stop services:**_ cargo make docker-compose-down ### [Command Line Options](https://docs.openzeppelin.com/monitor#command-line-options-1) | | | | | --- | --- | --- | | Option | Default | Description | | `--log-file` | `false` | Write logs to file instead of stdout | | `--log-level` | `info` | Set log level (trace, debug, info, warn, error) | | `--metrics` | `false` | Enable metrics server on port 8081 | | `--check` | `false` | Validate configuration files only | | `--help` | \- | Show all available options | ### [Testing your configuration](https://docs.openzeppelin.com/monitor#testing-your-configuration) #### [Network Configuration](https://docs.openzeppelin.com/monitor#network-configuration-1) The `validate_network_config.sh` script helps ensure your network configuration is properly set up and operational. The script: * Tests the health of all configured RPC endpoints * Validates connectivity using network-specific methods * Provides clear visual feedback for each endpoint # Test default networks directory (/config/networks/) ./scripts/validate_network_config.sh # Test a specific configuration directory ./scripts/validate_network_config.sh -f /path/to/configs Run this script when setting up new networks, before deploying configuration changes, or when troubleshooting connectivity issues. #### [Validating Configuration Files](https://docs.openzeppelin.com/monitor#validating-configuration-files) Before starting the monitor service, you can validate your configuration files using the `--check` option: ./openzeppelin-monitor --check This command will: * Parse and validate all configuration files * Check for syntax errors * Verify references between monitors, networks, and triggers * Report any issues without starting the service It’s recommended to run this check after making changes to any configuration files. #### [Monitor Configuration](https://docs.openzeppelin.com/monitor#monitor-configuration-1) The monitor can be tested in two modes: #### [1\. Latest Block Mode](https://docs.openzeppelin.com/monitor#1-latest-block-mode) This mode processes the most recent blocks across all configured networks. ./openzeppelin-monitor --monitor-path="config/monitors/evm_transfer_usdc.json" What this does: * Runs the "Large Transfer of USDC Token" monitor * Targets all networks specified in the configuration * Processes only the latest block for each network * Sends a notification to all associated channels for every match that is found #### [2\. Specific Block Mode](https://docs.openzeppelin.com/monitor#2-specific-block-mode) This mode allows you to analyze a particular block on a specific network, which is useful for debugging specific transactions, verifying monitor behavior on known events, and testing monitor performance on historical data. ./openzeppelin-monitor \ --monitor-path="config/monitors/evm_transfer_usdc.json" \ --network=ethereum_mainnet \ --block=12345678 What this does: * Runs the "Large Transfer of USDC Token" monitor * Targets only the specified network (`ethereum_mainnet`) * Processes only the specified block (`12345678`) * Sends a notification to all associated channels for every match that is found Specific Block Mode requires both parameters: * `--network`: The network to analyze * `--block`: The block number to process #### [Data Persistence (Optional)](https://docs.openzeppelin.com/monitor#data-persistence-optional) * Set `LOG_MODE` as file will persist the log data in `logs/` on host. To change it to a different directory use `LOG_DATA_DIR`. * Set `MONITOR_DATA_DIR` to specific dir on your host system which will persist data between container restarts. [Error Handling](https://docs.openzeppelin.com/monitor#error-handling) ----------------------------------------------------------------------- The monitor implements a comprehensive error handling system with rich context and tracing capabilities. For detailed information about error handling, see [Error Handling Guide](https://docs.openzeppelin.com/monitor/error) . [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-3) --------------------------------------------------------------------------------------------- ### [Performance Considerations](https://docs.openzeppelin.com/monitor#performance-considerations) * Monitor performance depends on network congestion and RPC endpoint reliability. * View the [list of RPC calls](https://docs.openzeppelin.com/monitor/rpc#list-of-rpc-calls) made by the monitor. * The `max_past_blocks` configuration is critical: * Calculate as: `(cron_interval_ms/block_time_ms) + confirmation_blocks + 1` (defaults to this calculation if not specified). * Example for 1-minute Ethereum cron: `(60000/12000) + 12 + 1 = 18 blocks`. * Too low settings may result in missed blocks. * Trigger conditions are executed sequentially based on their position in the trigger conditions array. Proper execution also depends on the number of available file descriptors on your system. To ensure optimal performance, it is recommended to increase the limit for open file descriptors to at least 2048 or higher. On Unix-based systems you can check the current limit by running `ulimit -n` and __**temporarily**__ increase it with `ulimit -n 2048`. * Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect. * See performance considerations about custom scripts [here](https://docs.openzeppelin.com/monitor/scripts#performance-considerations) . ### [Notification Considerations](https://docs.openzeppelin.com/monitor#notification-considerations) * Template variables are context-dependent: * Event-triggered notifications only populate event variables. * Function-triggered notifications only populate function variables. * Mixing contexts results in empty values. * Custom script notifications have additional considerations: * Scripts receive monitor match data and arguments as JSON input * Scripts must complete within their configured timeout\_ms or they will be terminated * Script modifications require monitor restart to take effect * Supported languages are limited to Python, JavaScript, and Bash [Support](https://docs.openzeppelin.com/monitor#support) --------------------------------------------------------- For support or inquiries, contact us on [Telegram](https://t.me/openzeppelin_tg/4) . Have feature requests or want to contribute? Join our community on [GitHub](https://github.com/OpenZeppelin/openzeppelin-monitor/) [License](https://docs.openzeppelin.com/monitor#license) --------------------------------------------------------- This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details. [Security](https://docs.openzeppelin.com/monitor#security) ----------------------------------------------------------- For security concerns, please refer to our [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md) . [Changelog\ \ Previous Page](https://docs.openzeppelin.com/relayer/changelog) [Quickstart\ \ Next Page](https://docs.openzeppelin.com/monitor/quickstart) ### On this page [Overview](https://docs.openzeppelin.com/monitor#overview) [Key Capabilities](https://docs.openzeppelin.com/monitor#key-capabilities) [Supported Networks](https://docs.openzeppelin.com/monitor#supported-networks) [Notification Channels](https://docs.openzeppelin.com/monitor#notification-channels) [Installation](https://docs.openzeppelin.com/monitor#installation) [Prerequisites](https://docs.openzeppelin.com/monitor#prerequisites) [Local Installation](https://docs.openzeppelin.com/monitor#local-installation) [Docker Installation](https://docs.openzeppelin.com/monitor#docker-installation) [Metrics Configuration](https://docs.openzeppelin.com/monitor#metrics-configuration) [Configuration Guidelines](https://docs.openzeppelin.com/monitor#configuration-guidelines) [Recommended File Naming Conventions](https://docs.openzeppelin.com/monitor#recommended-file-naming-conventions) [Configuration References](https://docs.openzeppelin.com/monitor#configuration-references) [Safe Protocol Guidelines](https://docs.openzeppelin.com/monitor#safe-protocol-guidelines) [Network Protocols](https://docs.openzeppelin.com/monitor#network-protocols) [RPC URLs](https://docs.openzeppelin.com/monitor#rpc-urls) [Notification Protocols](https://docs.openzeppelin.com/monitor#notification-protocols) [Webhook Notifications](https://docs.openzeppelin.com/monitor#webhook-notifications) [Slack Notifications](https://docs.openzeppelin.com/monitor#slack-notifications) [Discord Notifications](https://docs.openzeppelin.com/monitor#discord-notifications) [Telegram Notifications](https://docs.openzeppelin.com/monitor#telegram-notifications) [Email Notifications](https://docs.openzeppelin.com/monitor#email-notifications) [Notifications Retry Policy](https://docs.openzeppelin.com/monitor#notifications-retry-policy) [Script Security](https://docs.openzeppelin.com/monitor#script-security) [File Permissions (Unix Systems)](https://docs.openzeppelin.com/monitor#file-permissions-unix-systems) [Secret Management](https://docs.openzeppelin.com/monitor#secret-management) [Secret Sources](https://docs.openzeppelin.com/monitor#secret-sources) [Security Features](https://docs.openzeppelin.com/monitor#security-features) [Configuration](https://docs.openzeppelin.com/monitor#configuration) [Hashicorp Cloud Vault Integration](https://docs.openzeppelin.com/monitor#hashicorp-cloud-vault-integration) [Best Practices](https://docs.openzeppelin.com/monitor#best-practices) [Basic Configuration](https://docs.openzeppelin.com/monitor#basic-configuration) [Command Line Options](https://docs.openzeppelin.com/monitor#command-line-options) [Data Storage Configuration](https://docs.openzeppelin.com/monitor#data-storage-configuration) [File Storage](https://docs.openzeppelin.com/monitor#file-storage) [Configuration Files](https://docs.openzeppelin.com/monitor#configuration-files) [Network Configuration](https://docs.openzeppelin.com/monitor#network-configuration) [Available Fields](https://docs.openzeppelin.com/monitor#available-fields) [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations) [Trigger Configuration](https://docs.openzeppelin.com/monitor#trigger-configuration) [Trigger Types](https://docs.openzeppelin.com/monitor#trigger-types) [Slack Notifications](https://docs.openzeppelin.com/monitor#slack-notifications-1) [Slack Notification Fields](https://docs.openzeppelin.com/monitor#slack-notification-fields) [Email Notifications](https://docs.openzeppelin.com/monitor#email-notifications-1) [Email Notification Fields](https://docs.openzeppelin.com/monitor#email-notification-fields) [Webhook Notifications](https://docs.openzeppelin.com/monitor#webhook-notifications-1) [Webhook Notification Fields](https://docs.openzeppelin.com/monitor#webhook-notification-fields) [Discord Notifications](https://docs.openzeppelin.com/monitor#discord-notifications-1) [Discord Notification Fields](https://docs.openzeppelin.com/monitor#discord-notification-fields) [Telegram Notifications](https://docs.openzeppelin.com/monitor#telegram-notifications-1) [Telegram Notification Fields](https://docs.openzeppelin.com/monitor#telegram-notification-fields) [Custom Script Notifications](https://docs.openzeppelin.com/monitor#custom-script-notifications) [Script Notification Fields](https://docs.openzeppelin.com/monitor#script-notification-fields) [Available Template Variables](https://docs.openzeppelin.com/monitor#available-template-variables) [Common Variables](https://docs.openzeppelin.com/monitor#common-variables) [Network-Specific Variables](https://docs.openzeppelin.com/monitor#network-specific-variables) [EVM Variables](https://docs.openzeppelin.com/monitor#evm-variables) [Stellar Variables](https://docs.openzeppelin.com/monitor#stellar-variables) [Message Formatting](https://docs.openzeppelin.com/monitor#message-formatting) [Example Email Notification with Markdown](https://docs.openzeppelin.com/monitor#example-email-notification-with-markdown) [Example Slack Notification with Markdown](https://docs.openzeppelin.com/monitor#example-slack-notification-with-markdown) [Example Discord Notification with Markdown](https://docs.openzeppelin.com/monitor#example-discord-notification-with-markdown) [Example Telegram Notification with Markdown](https://docs.openzeppelin.com/monitor#example-telegram-notification-with-markdown) [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-1) [Monitor Configuration](https://docs.openzeppelin.com/monitor#monitor-configuration) [Available Fields](https://docs.openzeppelin.com/monitor#available-fields-1) [Match Conditions](https://docs.openzeppelin.com/monitor#match-conditions) [Function Conditions](https://docs.openzeppelin.com/monitor#function-conditions) [Event Conditions](https://docs.openzeppelin.com/monitor#event-conditions) [Transaction Conditions](https://docs.openzeppelin.com/monitor#transaction-conditions) [Available Transaction Fields (EVM)](https://docs.openzeppelin.com/monitor#available-transaction-fields-evm) [Available Transaction Fields (Stellar)](https://docs.openzeppelin.com/monitor#available-transaction-fields-stellar) [Matching Rules](https://docs.openzeppelin.com/monitor#matching-rules) [Expressions](https://docs.openzeppelin.com/monitor#expressions) [Operations on Complex Types](https://docs.openzeppelin.com/monitor#operations-on-complex-types) [EVM Specifics](https://docs.openzeppelin.com/monitor#evm-specifics) [Stellar Specifics](https://docs.openzeppelin.com/monitor#stellar-specifics) [EVM Examples](https://docs.openzeppelin.com/monitor#evm-examples) [Stellar Examples](https://docs.openzeppelin.com/monitor#stellar-examples) [Trigger Conditions (Custom filters)](https://docs.openzeppelin.com/monitor#trigger-conditions-custom-filters) [Available Fields](https://docs.openzeppelin.com/monitor#available-fields-2) [Trigger Conditions Fields](https://docs.openzeppelin.com/monitor#trigger-conditions-fields) [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-2) [Running the Monitor](https://docs.openzeppelin.com/monitor#running-the-monitor) [Local Execution](https://docs.openzeppelin.com/monitor#local-execution) [Docker Execution](https://docs.openzeppelin.com/monitor#docker-execution) [Command Line Options](https://docs.openzeppelin.com/monitor#command-line-options-1) [Testing your configuration](https://docs.openzeppelin.com/monitor#testing-your-configuration) [Network Configuration](https://docs.openzeppelin.com/monitor#network-configuration-1) [Validating Configuration Files](https://docs.openzeppelin.com/monitor#validating-configuration-files) [Monitor Configuration](https://docs.openzeppelin.com/monitor#monitor-configuration-1) [1\. Latest Block Mode](https://docs.openzeppelin.com/monitor#1-latest-block-mode) [2\. Specific Block Mode](https://docs.openzeppelin.com/monitor#2-specific-block-mode) [Data Persistence (Optional)](https://docs.openzeppelin.com/monitor#data-persistence-optional) [Error Handling](https://docs.openzeppelin.com/monitor#error-handling) [Important Considerations](https://docs.openzeppelin.com/monitor#important-considerations-3) [Performance Considerations](https://docs.openzeppelin.com/monitor#performance-considerations) [Notification Considerations](https://docs.openzeppelin.com/monitor#notification-considerations) [Support](https://docs.openzeppelin.com/monitor#support) [License](https://docs.openzeppelin.com/monitor#license) [Security](https://docs.openzeppelin.com/monitor#security) --- # Account Abstraction | OpenZeppelin Docs OpenZeppelin Contracts Account Abstraction =================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Unlike Externally Owned Accounts (EOAs), smart contracts may contain arbitrary verification logic based on authentication mechanisms different to Ethereum’s native [ECDSA](https://docs.openzeppelin.com/contracts/5.x/api/utils#ECDSA) and have execution advantages such as batching or gas sponsorship. To leverage these properties of smart contracts, the community has widely adopted [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) , a standard to process user operations through an alternative mempool. The library provides multiple contracts for Account Abstraction following this standard as it enables more flexible and user-friendly interactions with applications. Account Abstraction use cases include wallets in novel contexts (e.g. embedded wallets), more granular configuration of accounts, and recovery mechanisms. [ERC-4337 Overview](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#erc-4337-overview) ------------------------------------------------------------------------------------------------------- The ERC-4337 is a detailed specification of how to implement the necessary logic to handle operations without making changes to the protocol level (i.e. the rules of the blockchain itself). This specification defines the following components: ### [UserOperation](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#useroperation) A `UserOperation` is a higher-layer pseudo-transaction object that represents the intent of the account. This shares some similarities with regular EVM transactions like the concept of `gasFees` or `callData` but includes fields that enable new capabilities. struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; // concatenation of factory address and factoryData (or empty) bytes callData; bytes32 accountGasLimits; // concatenation of verificationGas (16 bytes) and callGas (16 bytes) uint256 preVerificationGas; bytes32 gasFees; // concatenation of maxPriorityFee (16 bytes) and maxFeePerGas (16 bytes) bytes paymasterAndData; // concatenation of paymaster fields (or empty) bytes signature; } This process of bundling user operations involves several costs that the bundler must cover, including base transaction fees, calldata serialization, entrypoint execution, and paymaster context costs. To compensate for these expenses, bundlers use the `preVerificationGas` and `gasFees` fields to charge users appropriately. Estimating `preVerificationGas` is not standardized as it varies based on network conditions such as gas prices and the size of the operation bundle. Use [`ERC4337Utils`](https://docs.openzeppelin.com/contracts/5.x/api/account#ERC4337Utils) to manipulate the `UserOperation` struct and other ERC-4337 related values. ### [Entrypoint](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#entrypoint) Each `UserOperation` is executed through a contract known as the [`EntryPoint`](https://etherscan.io/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108#code) . This contract is a singleton deployed across multiple networks at the same address although other custom implementations may be used. The Entrypoint contracts is considered a trusted entity by the account. ### [Bundlers](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#bundlers) The bundler is a piece of _offchain_ infrastructure that is in charge of processing an alternative mempool of user operations. Bundlers themselves call the Entrypoint contract’s `handleOps` function with an array of UserOperations that are executed and included in a block. During the process, the bundler pays for the gas of executing the transaction and gets refunded during the execution phase of the Entrypoint contract. function handleOps( PackedUserOperation[] calldata ops, address payable beneficiary ) external { ... } ### [Account Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#account-contract) The Account Contract is a smart contract that implements the logic required to validate a `UserOperation` in the context of ERC-4337. Any smart contract account should conform with the `IAccount` interface to validate operations. interface IAccount { function validateUserOp(PackedUserOperation calldata, bytes32, uint256) external returns (uint256 validationData); } Similarly, an Account should have a way to execute these operations by either handling arbitrary calldata on its `fallback` or implementing the `IAccountExecute` interface: interface IAccountExecute { function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external; } The `IAccountExecute` interface is optional. Developers might want to use [`ERC-7821`](https://docs.openzeppelin.com/contracts/5.x/api/account#ERC7821) for a minimal batched execution interface or rely on ERC-7579 or any other execution logic. To build your own account, see [accounts](https://docs.openzeppelin.com/contracts/5.x/accounts) . ### [Factory Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#factory-contract) The smart contract accounts are created by a Factory contract defined by the Account developer. This factory receives arbitrary bytes as `initData` and returns an `address` where the logic of the account is deployed. To build your own factory, see [account factories](https://docs.openzeppelin.com/contracts/5.x/accounts#accounts-factory) . ### [Paymaster Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#paymaster-contract) A Paymaster is an optional entity that can sponsor gas fees for Accounts, or allow them to pay for those fees in ERC-20 instead of native currency. This abstracts gas away of the user experience in the same way that computational costs of cloud servers are abstracted away from end-users. To build your own paymaster, see [paymasters](https://docs.openzeppelin.com/community-contracts/paymasters) . [Further notes](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#further-notes) ----------------------------------------------------------------------------------------------- ### [ERC-7562 Validation Rules](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#erc-7562-validation-rules) To process a bundle of `UserOperations`, bundlers call [`validateUserOp`](https://docs.openzeppelin.com/contracts/5.x/api/account#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-) on each operation sender to check whether the operation can be executed. However, the bundler has no guarantee that the state of the blockchain will remain the same after the validation phase. To overcome this problem, [ERC-7562](https://eips.ethereum.org/EIPS/eip-7562) proposes a set of limitations to EVM code so that bundlers (or node operators) are protected from unexpected state changes. These rules outline the requirements for operations to be processed by the canonical mempool. Accounts can access its own storage during the validation phase, they might easily violate ERC-7562 storage access rules in undirect ways. For example, most accounts access their public keys from storage when validating a signature, limiting the ability of having accounts that validate operations for other accounts (e.g. via ERC-1271) Although any Account that breaks such rules may still be processed by a private bundler, developers should keep in mind the centralization tradeoffs of relying on private infrastructure instead of _permissionless_ execution. [Access Control\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/access-control) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/accounts) ### On this page [ERC-4337 Overview](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#erc-4337-overview) [UserOperation](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#useroperation) [Entrypoint](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#entrypoint) [Bundlers](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#bundlers) [Account Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#account-contract) [Factory Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#factory-contract) [Paymaster Contract](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#paymaster-contract) [Further notes](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#further-notes) [ERC-7562 Validation Rules](https://docs.openzeppelin.com/contracts/5.x/account-abstraction#erc-7562-validation-rules) --- # API Reference | OpenZeppelin Docs OpenZeppelin Contracts API Reference ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This API reference is automatically generated from the OpenZeppelin Contracts repository. [Contract Categories](https://docs.openzeppelin.com/contracts/5.x/api#contract-categories) ------------------------------------------------------------------------------------------- ### [Access Control](https://docs.openzeppelin.com/contracts/5.x/api#access-control) * [Access Control](https://docs.openzeppelin.com/contracts/5.x/api/access) - Role-based access control mechanisms * [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable) - Simple ownership access control ### [Tokens](https://docs.openzeppelin.com/contracts/5.x/api#tokens) * [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) - Fungible token standard implementation * [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721) - Non-fungible token standard implementation * [ERC1155](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155) - Multi-token standard implementation ### [Utilities](https://docs.openzeppelin.com/contracts/5.x/api#utilities) * [Utils](https://docs.openzeppelin.com/contracts/5.x/api/utils) - General utility functions and contracts * [Cryptography](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography) - Cryptographic utilities ### [Governance](https://docs.openzeppelin.com/contracts/5.x/api#governance) * [Governance](https://docs.openzeppelin.com/contracts/5.x/api/governance) - On-chain governance systems ### [Proxy Patterns](https://docs.openzeppelin.com/contracts/5.x/api#proxy-patterns) * [Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy) - Upgradeable proxy patterns ### [Interfaces](https://docs.openzeppelin.com/contracts/5.x/api#interfaces) * [Interfaces](https://docs.openzeppelin.com/contracts/5.x/api/interfaces) - Standard interfaces [Changelog\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/changelog) [Access\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/api/access) ### On this page [Contract Categories](https://docs.openzeppelin.com/contracts/5.x/api#contract-categories) [Access Control](https://docs.openzeppelin.com/contracts/5.x/api#access-control) [Tokens](https://docs.openzeppelin.com/contracts/5.x/api#tokens) [Utilities](https://docs.openzeppelin.com/contracts/5.x/api#utilities) [Governance](https://docs.openzeppelin.com/contracts/5.x/api#governance) [Proxy Patterns](https://docs.openzeppelin.com/contracts/5.x/api#proxy-patterns) [Interfaces](https://docs.openzeppelin.com/contracts/5.x/api#interfaces) --- # ERC721 | OpenZeppelin Docs OpenZeppelin Contracts[API Reference](https://docs.openzeppelin.com/contracts/5.x/api) Token ERC721 ====== Smart contract ERC721 utilities and implementations Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This set of interfaces, contracts, and utilities is all related to the [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) . For a walk through on how to create an ERC-721 token read our [ERC-721 guide](https://docs.openzeppelin.com/contracts/5.x/erc721) . The ERC specifies four interfaces: * [`IERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721) : Core functionality required in all compliant implementation. * [`IERC721Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Metadata) : Optional extension that adds name, symbol, and token URI, almost always included. * [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Enumerable) : Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead. * [`IERC721Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver) : An interface that must be implemented by contracts if they want to accept tokens through `safeTransferFrom`. OpenZeppelin Contracts provides implementations of all four interfaces: * [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721) : The core and metadata extensions, with a base URI mechanism. * [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable) : The enumerable extension. * [`ERC721Holder`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Holder) : A bare bones implementation of the receiver interface. Additionally there are a few of other extensions: * [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive) : An implementation of [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) for minting batches of tokens during construction, in accordance with ERC-721. * [`ERC721URIStorage`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721URIStorage) : A more flexible but more expensive way of storing metadata. * [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes) : Support for voting and vote delegation. * [`ERC721Royalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Royalty) : A way to signal royalty information following ERC-2981. * [`ERC721Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Pausable) : A primitive to pause contract operation. * [`ERC721Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Burnable) : A way for token holders to burn their own tokens. * [`ERC721Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper) : Wrapper to create an ERC-721 backed by another ERC-721, with deposit and withdraw methods. Useful in conjunction with [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes) . This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC-721 (such as [`_mint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) ) and expose them as external functions in the way they prefer. [Core](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#core) -------------------------------------------------------------------------- [`IERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721) [`IERC721Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Metadata) [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Enumerable) [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721) [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable) [`IERC721Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#extensions) -------------------------------------------------------------------------------------- [`ERC721Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Pausable) [`ERC721Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Burnable) [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive) [`ERC721URIStorage`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721URIStorage) [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes) [`ERC721Royalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Royalty) [`ERC721Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper) [Utilities](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#utilities) ------------------------------------------------------------------------------------ [`ERC721Holder`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Holder) [`ERC721Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Utils) [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721) -------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/ERC721.sol) import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; Implementation of [ERC-721](https://eips.ethereum.org/EIPS/eip-721) Non-Fungible Token Standard, including the Metadata extension, but not including the Enumerable extension, which is available separately as [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable) . ### Functions * [constructor(name\_, symbol\_)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-constructor-string-string-) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc) ### Events #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-1) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-1) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-1) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-1) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-1) ### Errors #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-2) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-2) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-2) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-2) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-2) constructor(string name\_, string symbol\_) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-constructor-string-string-) Initializes the contract by setting a `name` and a `symbol` to the token collection. supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-supportsInterface-bytes4-) 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. balanceOf(address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-balanceOf-address-) Returns the number of tokens in `owner`'s account. ownerOf(uint256 tokenId) → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-ownerOf-uint256-) Returns the owner of the `tokenId` token. Requirements: * `tokenId` must exist. name() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-name--) Returns the token collection name. symbol() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-symbol--) Returns the token collection symbol. tokenURI(uint256 tokenId) → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-tokenURI-uint256-) Returns the Uniform Resource Identifier (URI) for `tokenId` token. \_baseURI() → string internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_baseURI--) Base URI for computing [`IERC6909ContentURI.tokenURI`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909ContentURI-tokenURI-uint256-) . If set, the resulting URI for each token will be the concatenation of the `baseURI` and the `tokenId`. Empty by default, can be overridden in child contracts. approve(address to, uint256 tokenId) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-approve-address-uint256-) Gives permission to `to` to transfer `tokenId` token to another account. The approval is cleared when the token is transferred. Only a single account can be approved at a time, so approving the zero address clears previous approvals. Requirements: * The caller must own the token or be an approved operator. * `tokenId` must exist. Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. getApproved(uint256 tokenId) → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-getApproved-uint256-) Returns the account approved for `tokenId` token. Requirements: * `tokenId` must exist. setApprovalForAll(address operator, bool approved) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-setApprovalForAll-address-bool-) Approve or remove `operator` as an operator for the caller. Operators can call [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) or [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) for any token owned by the caller. Requirements: * The `operator` cannot be the address zero. Emits an [`IERC1155.ApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-ApprovalForAll-address-address-bool-) event. isApprovedForAll(address owner, address operator) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-isApprovedForAll-address-address-) Returns if the `operator` is allowed to manage all of the assets of `owner`. See [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) transferFrom(address from, address to, uint256 tokenId) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-transferFrom-address-address-uint256-) Transfers `tokenId` token from `from` to `to`. Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 or else they may be permanently lost. Usage of [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) prevents loss, though the caller must understand this adds an external call which potentially creates a reentrancy vulnerability. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must be owned by `from`. * If the caller is not `from`, it must be approved to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. safeTransferFrom(address from, address to, uint256 tokenId) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-safeTransferFrom-address-address-uint256-) Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients are aware of the ERC-721 protocol to prevent tokens from being forever locked. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must exist and be owned by `from`. * If the caller is not `from`, it must have been allowed to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. safeTransferFrom(address from, address to, uint256 tokenId, bytes data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-safeTransferFrom-address-address-uint256-bytes-) Safely transfers `tokenId` token from `from` to `to`. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must exist and be owned by `from`. * If the caller is not `from`, it must be approved to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_ownerOf(uint256 tokenId) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_ownerOf-uint256-) Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist Any overrides to this function that add ownership of tokens not tracked by the core ERC-721 logic MUST be matched with the use of [`ERC721._increaseBalance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) to keep balances consistent with ownership. The invariant to preserve is that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`. \_getApproved(uint256 tokenId) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_getApproved-uint256-) Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. \_isAuthorized(address owner, address spender, uint256 tokenId) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_isAuthorized-address-address-uint256-) Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in particular (ignoring whether it is owned by `owner`). This function assumes that `owner` is the actual owner of `tokenId` and does not verify this assumption. \_checkAuthorized(address owner, address spender, uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_checkAuthorized-address-address-uint256-) Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. Reverts if: * `spender` does not have approval from `owner` for `tokenId`. * `spender` does not have approval to manage all of `owner`'s assets. This function assumes that `owner` is the actual owner of `tokenId` and does not verify this assumption. \_increaseBalance(address account, uint128 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_increaseBalance-address-uint128-) Unsafe write access to the balances, used by extensions that "mint" tokens using an [`ERC721.ownerOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) override. the value is limited to type(uint128).max. This protect against \_balance overflow. It is unrealistic that a uint256 would ever overflow from increments when these increments are bounded to uint128 values. Increasing an account's balance using this function tends to be paired with an override of the [`ERC721._ownerOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) function to resolve the ownership of the corresponding tokens so that balances and ownership remain consistent with one another. \_update(address to, uint256 tokenId, address auth) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_update-address-uint256-address-) Transfers `tokenId` 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 `tokenId` before the update. The `auth` argument is optional. If the value passed is non 0, 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 [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. If overriding this function in a way that tracks balances, see also [`ERC721._increaseBalance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) . \_mint(address to, uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_mint-address-uint256-) Mints `tokenId` and transfers it to `to`. Usage of this method is discouraged, use [`ERC721._safeMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) whenever possible Requirements: * `tokenId` must not exist. * `to` cannot be the zero address. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_safeMint(address to, uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_safeMint-address-uint256-) Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. Requirements: * `tokenId` must not exist. * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_safeMint(address to, uint256 tokenId, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_safeMint-address-uint256-bytes-) Same as [`_safeMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) , with an additional `data` parameter which is forwarded in [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) to contract recipients. \_burn(uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_burn-uint256-) Destroys `tokenId`. The approval is cleared when the token is burned. This is an internal function that does not check if the sender is authorized to operate on the token. Requirements: * `tokenId` must exist. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_transfer(address from, address to, uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_transfer-address-address-uint256-) Transfers `tokenId` from `from` to `to`. As opposed to [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) , this imposes no restrictions on msg.sender. Requirements: * `to` cannot be the zero address. * `tokenId` token must be owned by `from`. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_safeTransfer(address from, address to, uint256 tokenId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_safeTransfer-address-address-uint256-) Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients are aware of the ERC-721 standard to prevent tokens from being forever locked. `data` is additional data, it has no specified format and it is sent in call to `to`. This internal function is like [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) in the sense that it invokes [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) on the receiver, and can be used to e.g. implement alternative mechanisms to perform token transfer, such as signature-based. Requirements: * `tokenId` token must exist and be owned by `from`. * `to` cannot be the zero address. * `from` cannot be the zero address. * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_safeTransfer(address from, address to, uint256 tokenId, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_safeTransfer-address-address-uint256-bytes-) Same as [`_safeTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) , with an additional `data` parameter which is forwarded in [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) to contract recipients. \_approve(address to, uint256 tokenId, address auth) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_approve-address-uint256-address-) Approve `to` to operate on `tokenId` The `auth` argument is optional. If the value passed is non 0, 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 [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. \_approve(address to, uint256 tokenId, address auth, bool emitEvent) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_approve-address-uint256-address-bool-) Variant of `_approve` with an optional flag to enable or disable the [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. The event is not emitted in the context of transfers. \_setApprovalForAll(address owner, address operator, bool approved) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_setApprovalForAll-address-address-bool-) Approve `operator` to operate on all of `owner` tokens Requirements: * operator can't be the address zero. Emits an [`IERC1155.ApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-ApprovalForAll-address-address-bool-) event. \_requireOwned(uint256 tokenId) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721-_requireOwned-uint256-) Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). Returns the owner. Overrides to ownership logic should be done to [`ERC721._ownerOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) . [`IERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721) ---------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/IERC721.sol) import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; Required interface of an ERC-721 compliant contract. ### Functions * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ownerOf-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-bytes-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-transferFrom-address-address-uint256-) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-approve-address-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-setApprovalForAll-address-bool-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-getApproved-uint256-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-isApprovedForAll-address-address-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-3) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC165-supportsInterface-bytes4-) ### Events * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-4) balanceOf(address owner) → uint256 balance external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-balanceOf-address-) Returns the number of tokens in `owner`'s account. ownerOf(uint256 tokenId) → address owner external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-ownerOf-uint256-) Returns the owner of the `tokenId` token. Requirements: * `tokenId` must exist. safeTransferFrom(address from, address to, uint256 tokenId, bytes data) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-safeTransferFrom-address-address-uint256-bytes-) Safely transfers `tokenId` token from `from` to `to`. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must exist and be owned by `from`. * If the caller is not `from`, it must be approved to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. safeTransferFrom(address from, address to, uint256 tokenId) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-safeTransferFrom-address-address-uint256-) Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients are aware of the ERC-721 protocol to prevent tokens from being forever locked. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must exist and be owned by `from`. * If the caller is not `from`, it must have been allowed to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . * If `to` refers to a smart contract, it must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) , which is called upon a safe transfer. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. transferFrom(address from, address to, uint256 tokenId) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-transferFrom-address-address-uint256-) Transfers `tokenId` token from `from` to `to`. Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 or else they may be permanently lost. Usage of [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) prevents loss, though the caller must understand this adds an external call which potentially creates a reentrancy vulnerability. Requirements: * `from` cannot be the zero address. * `to` cannot be the zero address. * `tokenId` token must be owned by `from`. * If the caller is not `from`, it must be approved to move this token by either [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) . Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. approve(address to, uint256 tokenId) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-approve-address-uint256-) Gives permission to `to` to transfer `tokenId` token to another account. The approval is cleared when the token is transferred. Only a single account can be approved at a time, so approving the zero address clears previous approvals. Requirements: * The caller must own the token or be an approved operator. * `tokenId` must exist. Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. setApprovalForAll(address operator, bool approved) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-setApprovalForAll-address-bool-) Approve or remove `operator` as an operator for the caller. Operators can call [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) or [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) for any token owned by the caller. Requirements: * The `operator` cannot be the address zero. Emits an [`IERC1155.ApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#IERC1155-ApprovalForAll-address-address-bool-) event. getApproved(uint256 tokenId) → address operator external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-getApproved-uint256-) Returns the account approved for `tokenId` token. Requirements: * `tokenId` must exist. isApprovedForAll(address owner, address operator) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-isApprovedForAll-address-address-) Returns if the `operator` is allowed to manage all of the assets of `owner`. See [`ERC1155.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-setApprovalForAll-address-bool-) Transfer(address indexed from, address indexed to, uint256 indexed tokenId) event [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-Transfer-address-address-uint256-) Emitted when `tokenId` token is transferred from `from` to `to`. Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) event [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-Approval-address-address-uint256-) Emitted when `owner` enables `approved` to manage the `tokenId` token. ApprovalForAll(address indexed owner, address indexed operator, bool approved) event [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721-ApprovalForAll-address-address-bool-) Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. [`IERC721Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver) -------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/IERC721Receiver.sol) import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; Interface for any contract that wants to support safeTransfers from ERC-721 asset contracts. ### Functions * [onERC721Received(operator, from, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) onERC721Received(address operator, address from, uint256 tokenId, bytes data) → bytes4 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Receiver-onERC721Received-address-address-uint256-bytes-) Whenever an [`IERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721) `tokenId` token is transferred to this contract via [`IERC721.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-) by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. [`ERC721Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721burnable) ------------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Burnable.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; ERC-721 Token that can be burned (destroyed). ### Functions * [burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Burnable-burn-uint256-) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-3) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-3) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-3) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-3) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-5) ### Events #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-1) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-4) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-4) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-4) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-4) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-6) ### Errors #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-2) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-5) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-5) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-5) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-5) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-7) burn(uint256 tokenId) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Burnable-burn-uint256-) Burns `tokenId`. See [`ERC721._burn`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) . Requirements: * The caller must own `tokenId` or be an approved operator. [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721consecutive) ------------------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Consecutive.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Consecutive.sol"; Implementation of the ERC-2309 "Consecutive Transfer Extension" as defined in [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) . This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers. Using this extension removes the ability to mint single tokens during contract construction. This ability is regained after construction. During construction, only batch minting is allowed. This extension does not call the [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) function for tokens minted in batch. Any logic added to this function through overrides will not be triggered when token are minted in batch. You may want to also override [`ERC721._increaseBalance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) or [`ERC721Consecutive._mintConsecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) to account for these mints. When overriding [`ERC721Consecutive._mintConsecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) , be careful about call ordering. [`ERC721.ownerOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) may return invalid values during the [`ERC721Consecutive._mintConsecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) execution if the super call is not called first. To be safe, execute the super call before your custom logic. ### Functions * [\_maxBatchSize()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_maxBatchSize--) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_ownerOf-uint256-) * [\_mintConsecutive(to, batchSize)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_update-address-uint256-address-) * [\_firstConsecutiveId()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_firstConsecutiveId--) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-3) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-6) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-6) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-6) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-6) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-8) #### [IERC2309](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2309-toc) ### Events #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-4) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-7) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-7) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-7) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-7) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-9) #### [IERC2309](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2309-toc-1) * [ConsecutiveTransfer(fromTokenId, toTokenId, fromAddress, toAddress)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC2309-ConsecutiveTransfer-uint256-uint256-address-address-) ### Errors * [ERC721ForbiddenBatchMint()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-ERC721ForbiddenBatchMint--) * [ERC721ExceededMaxBatchMint(batchSize, maxBatch)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-ERC721ExceededMaxBatchMint-uint256-uint256-) * [ERC721ForbiddenMint()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-ERC721ForbiddenMint--) * [ERC721ForbiddenBatchBurn()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-ERC721ForbiddenBatchBurn--) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-5) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-8) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-8) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-8) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-8) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-10) #### [IERC2309](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2309-toc-2) \_maxBatchSize() → uint96 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-_maxBatchSize--) Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing services that have to record one entry per token, and have protections against "unreasonably large" batches of tokens. Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being correctly supported by off-chain indexing services (including marketplaces). \_ownerOf(uint256 tokenId) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-_ownerOf-uint256-) See [`ERC721._ownerOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) . Override that checks the sequential ownership structure for tokens that have been minted as part of a batch, and not yet transferred. \_mintConsecutive(address to, uint96 batchSize) → uint96 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-_mintConsecutive-address-uint96-) Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the batch; if `batchSize` is 0, returns the number of consecutive ids minted so far. Requirements: * `batchSize` must not be greater than [`ERC721Consecutive._maxBatchSize`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_maxBatchSize--) . * The function is called in the constructor of the contract (directly or indirectly). CAUTION: Does not emit a `Transfer` event. This is ERC-721 compliant as long as it is done inside of the constructor, which is enforced by this function. CAUTION: Does not invoke `onERC721Received` on the receiver. Emits a [`IERC2309.ConsecutiveTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC2309-ConsecutiveTransfer-uint256-uint256-address-address-) event. \_update(address to, uint256 tokenId, address auth) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-_update-address-uint256-address-) See [`ERC721._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) . Override version that restricts normal minting to after construction. Using [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive) prevents minting during construction in favor of [`ERC721Consecutive._mintConsecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) . After construction, [`ERC721Consecutive._mintConsecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive-_mintConsecutive-address-uint96-) is no longer available and minting through [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) becomes available. \_firstConsecutiveId() → uint96 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-_firstConsecutiveId--) Used to offset the first token id in `_nextConsecutiveId` ERC721ForbiddenBatchMint() error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-ERC721ForbiddenBatchMint--) Batch mint is restricted to the constructor. Any batch mint not emitting the [`IERC721.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) event outside of the constructor is non ERC-721 compliant. ERC721ExceededMaxBatchMint(uint256 batchSize, uint256 maxBatch) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-ERC721ExceededMaxBatchMint-uint256-uint256-) Exceeds the max amount of mints per batch. ERC721ForbiddenMint() error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-ERC721ForbiddenMint--) Individual minting is not allowed. ERC721ForbiddenBatchBurn() error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Consecutive-ERC721ForbiddenBatchBurn--) Batch burn is not supported. [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721enumerable) ---------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Enumerable.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; This implements an optional extension of [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721) defined in the ERC that adds enumerability of all the token ids in the contract as well as all token ids owned by each account. CAUTION: [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721) extensions that implement custom `balanceOf` logic, such as [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Consecutive) , interfere with enumerability and should not be used together with [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable) . ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-supportsInterface-bytes4-) * [tokenOfOwnerByIndex(owner, index)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-tokenOfOwnerByIndex-address-uint256-) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-totalSupply--) * [tokenByIndex(index)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-tokenByIndex-uint256-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-_update-address-uint256-address-) * [\_increaseBalance(account, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-_increaseBalance-address-uint128-) #### [IERC721Enumerable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721enumerable-toc) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-6) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-9) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-9) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-9) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-9) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-11) ### Events #### [IERC721Enumerable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721enumerable-toc-1) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-7) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-10) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-10) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-10) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-10) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-12) ### Errors * [ERC721OutOfBoundsIndex(owner, index)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-ERC721OutOfBoundsIndex-address-uint256-) * [ERC721EnumerableForbiddenBatchMint()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Enumerable-ERC721EnumerableForbiddenBatchMint--) #### [IERC721Enumerable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721enumerable-toc-2) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-8) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-11) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-11) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-11) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-11) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-13) supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-supportsInterface-bytes4-) 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. tokenOfOwnerByIndex(address owner, uint256 index) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-tokenOfOwnerByIndex-address-uint256-) Returns a token ID owned by `owner` at a given `index` of its token list. Use along with [`IERC777.balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-balanceOf-address-) to enumerate all of `owner`'s tokens. totalSupply() → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-totalSupply--) Returns the total amount of tokens stored by the contract. tokenByIndex(uint256 index) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-tokenByIndex-uint256-) Returns a token ID at a given `index` of all the tokens stored by the contract. Use along with [`IERC777.totalSupply`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-totalSupply--) to enumerate all tokens. \_update(address to, uint256 tokenId, address auth) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-_update-address-uint256-address-) Transfers `tokenId` 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 `tokenId` before the update. The `auth` argument is optional. If the value passed is non 0, 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 [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. If overriding this function in a way that tracks balances, see also [`ERC721._increaseBalance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) . \_increaseBalance(address account, uint128 amount) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-_increaseBalance-address-uint128-) ERC721OutOfBoundsIndex(address owner, uint256 index) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-ERC721OutOfBoundsIndex-address-uint256-) An `owner`'s token query was out of bounds for `index`. The owner being `address(0)` indicates a global out of bounds index. ERC721EnumerableForbiddenBatchMint() error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Enumerable-ERC721EnumerableForbiddenBatchMint--) Batch mint is not allowed. [`ERC721Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721pausable) ------------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Pausable.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; ERC-721 token with pausable token transfers, minting and burning. Useful for scenarios such as preventing trades until the end of an evaluation period, or having an emergency switch for freezing all token transfers in the event of a large bug. This contract does not include public pause and unpause functions. In addition to inheriting this contract, you must define both functions, invoking the [`Pausable._pause`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Pausable-_pause--) and [`Pausable._unpause`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Pausable-_unpause--) internal functions, with appropriate access control, e.g. using [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) or [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) . Not doing so will make the contract pause mechanism of the contract unreachable, and thus unusable. ### Functions * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Pausable-_update-address-uint256-address-) #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#pausable-toc) * [paused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-paused--) * [\_requireNotPaused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-_requireNotPaused--) * [\_requirePaused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-_requirePaused--) * [\_pause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-_pause--) * [\_unpause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-_unpause--) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-9) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-12) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-12) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-12) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-12) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-14) ### Events #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#pausable-toc-1) * [Paused(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-Paused-address-) * [Unpaused(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-Unpaused-address-) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-10) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-13) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-13) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-13) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-13) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-15) ### Errors #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#pausable-toc-2) * [EnforcedPause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-EnforcedPause--) * [ExpectedPause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Pausable-ExpectedPause--) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-11) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-14) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-14) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-14) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-14) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-16) \_update(address to, uint256 tokenId, address auth) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Pausable-_update-address-uint256-address-) See [`ERC721._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) . Requirements: * the contract must not be paused. [`ERC721Royalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721royalty) ---------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Royalty.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol"; Extension of ERC-721 with the ERC-2981 NFT Royalty Standard, a standardized way to retrieve royalty payment information. Royalty information can be specified globally for all token ids via [`ERC2981._setDefaultRoyalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/common#ERC2981-_setDefaultRoyalty-address-uint96-) , and/or individually for specific token ids via [`ERC2981._setTokenRoyalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/common#ERC2981-_setTokenRoyalty-uint256-address-uint96-) . The latter takes precedence over the first. ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See [Rationale](https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments) in the ERC. Marketplaces are expected to voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Royalty-supportsInterface-bytes4-) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-12) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-15) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-15) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-15) #### [ERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc2981-toc) * [royaltyInfo(tokenId, salePrice)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-royaltyInfo-uint256-uint256-) * [\_feeDenominator()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-_feeDenominator--) * [\_setDefaultRoyalty(receiver, feeNumerator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-_setDefaultRoyalty-address-uint96-) * [\_deleteDefaultRoyalty()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-_deleteDefaultRoyalty--) * [\_setTokenRoyalty(tokenId, receiver, feeNumerator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-_setTokenRoyalty-uint256-address-uint96-) * [\_resetTokenRoyalty(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-_resetTokenRoyalty-uint256-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-15) #### [IERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2981-toc) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-17) ### Events #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-13) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-16) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-16) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-16) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc2981-toc-1) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-16) #### [IERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2981-toc-1) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-18) ### Errors #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-14) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-17) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-17) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-17) #### [ERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc2981-toc-2) * [ERC2981InvalidDefaultRoyalty(numerator, denominator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-ERC2981InvalidDefaultRoyalty-uint256-uint256-) * [ERC2981InvalidDefaultRoyaltyReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-ERC2981InvalidDefaultRoyaltyReceiver-address-) * [ERC2981InvalidTokenRoyalty(tokenId, numerator, denominator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-ERC2981InvalidTokenRoyalty-uint256-uint256-uint256-) * [ERC2981InvalidTokenRoyaltyReceiver(tokenId, receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC2981-ERC2981InvalidTokenRoyaltyReceiver-uint256-address-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-17) #### [IERC2981](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc2981-toc-2) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-19) supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Royalty-supportsInterface-bytes4-) [`ERC721URIStorage`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721uristorage) ---------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721URIStorage.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; ERC-721 token with storage based token URI management. ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721URIStorage-supportsInterface-bytes4-) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721URIStorage-tokenURI-uint256-) * [\_setTokenURI(tokenId, \_tokenURI)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721URIStorage-_setTokenURI-uint256-string-) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-15) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-18) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-18) #### [IERC4906](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc4906-toc) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-18) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-18) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-20) ### Events #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-16) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-19) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-19) #### [IERC4906](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc4906-toc-1) * [MetadataUpdate(\_tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC4906-MetadataUpdate-uint256-) * [BatchMetadataUpdate(\_fromTokenId, \_toTokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC4906-BatchMetadataUpdate-uint256-uint256-) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-19) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-19) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-21) ### Errors #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-17) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-20) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-20) #### [IERC4906](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc4906-toc-2) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-20) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-20) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-22) supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721URIStorage-supportsInterface-bytes4-) 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. tokenURI(uint256 tokenId) → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721URIStorage-tokenURI-uint256-) \_setTokenURI(uint256 tokenId, string \_tokenURI) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721URIStorage-_setTokenURI-uint256-string-) Sets `_tokenURI` as the tokenURI of `tokenId`. Emits [`IERC4906.MetadataUpdate`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC4906-MetadataUpdate-uint256-) . [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721votes) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Votes.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; Extension of ERC-721 to support voting and delegation as implemented by [`Votes`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes) , where each individual NFT counts as 1 vote unit. Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of the votes in governance decisions, or they can delegate to themselves to be their own representative. ### Functions * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes-_update-address-uint256-address-) * [\_getVotingUnits(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes-_getVotingUnits-address-) * [\_increaseBalance(account, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes-_increaseBalance-address-uint128-) #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#votes-toc) * [clock()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-clock--) * [CLOCK\_MODE()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-CLOCK_MODE--) * [\_validateTimepoint(timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_validateTimepoint-uint256-) * [getVotes(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-getVotes-address-) * [getPastVotes(account, timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-getPastVotes-address-uint256-) * [getPastTotalSupply(timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-getPastTotalSupply-uint256-) * [\_getTotalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_getTotalSupply--) * [delegates(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-delegates-address-) * [delegate(delegatee)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-delegate-address-) * [delegateBySig(delegatee, nonce, expiry, v, r, s)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-delegateBySig-address-uint256-uint256-uint8-bytes32-bytes32-) * [\_delegate(account, delegatee)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_delegate-address-address-) * [\_transferVotingUnits(from, to, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_transferVotingUnits-address-address-uint256-) * [\_moveDelegateVotes(from, to, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_moveDelegateVotes-address-address-uint256-) * [\_numCheckpoints(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_numCheckpoints-address-) * [\_checkpoints(account, pos)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-_checkpoints-address-uint32-) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5805-toc) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ivotes-toc) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc6372-toc) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#nonces-toc) * [nonces(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Nonces-nonces-address-) * [\_useNonce(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Nonces-_useNonce-address-) * [\_useCheckedNonce(owner, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Nonces-_useCheckedNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#eip712-toc) * [\_domainSeparatorV4()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#EIP712-_domainSeparatorV4--) * [\_hashTypedDataV4(structHash)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#EIP712-_hashTypedDataV4-bytes32-) * [eip712Domain()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#EIP712-eip712Domain--) * [\_EIP712Name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#EIP712-_EIP712Name--) * [\_EIP712Version()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#EIP712-_EIP712Version--) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5267-toc) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-18) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-21) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-21) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-21) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-21) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-23) ### Events #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#votes-toc-1) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5805-toc-1) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ivotes-toc-1) * [DelegateChanged(delegator, fromDelegate, toDelegate)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IVotes-DelegateChanged-address-address-address-) * [DelegateVotesChanged(delegate, previousVotes, newVotes)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IVotes-DelegateVotesChanged-address-uint256-uint256-) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc6372-toc-1) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#nonces-toc-1) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#eip712-toc-1) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5267-toc-1) * [EIP712DomainChanged()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC5267-EIP712DomainChanged--) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-19) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-22) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-22) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-22) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-22) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-24) ### Errors #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#votes-toc-2) * [ERC6372InconsistentClock()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-ERC6372InconsistentClock--) * [ERC5805FutureLookup(timepoint, clock)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Votes-ERC5805FutureLookup-uint256-uint48-) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5805-toc-2) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ivotes-toc-2) * [VotesExpiredSignature(expiry)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IVotes-VotesExpiredSignature-uint256-) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc6372-toc-2) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#nonces-toc-2) * [InvalidAccountNonce(account, currentNonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#Nonces-InvalidAccountNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#eip712-toc-2) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc5267-toc-2) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-20) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-23) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-23) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-23) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-23) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-25) \_update(address to, uint256 tokenId, address auth) → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Votes-_update-address-uint256-address-) See [`ERC721._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) . Adjusts votes when tokens are transferred. Emits a [`IVotes.DelegateVotesChanged`](https://docs.openzeppelin.com/contracts/5.x/api/governance#IVotes-DelegateVotesChanged-address-uint256-uint256-) event. \_getVotingUnits(address account) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Votes-_getVotingUnits-address-) Returns the balance of `account`. Overriding this function will likely result in incorrect vote tracking. \_increaseBalance(address account, uint128 amount) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Votes-_increaseBalance-address-uint128-) See [`ERC721._increaseBalance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) . We need that to account tokens that were minted in batch. [`ERC721Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721wrapper) ---------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/ERC721Wrapper.sol) import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Wrapper.sol"; Extension of the ERC-721 token contract to support token wrapping. Users can deposit and withdraw an "underlying token" and receive a "wrapped token" with a matching tokenId. This is useful in conjunction with other modules. For example, combining this wrapping mechanism with [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Votes) will allow the wrapping of an existing "basic" ERC-721 into a governance token. ### Functions * [constructor(underlyingToken)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-constructor-contract-IERC721-) * [depositFor(account, tokenIds)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-depositFor-address-uint256---) * [withdrawTo(account, tokenIds)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-withdrawTo-address-uint256---) * [onERC721Received(, from, tokenId, )](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-onERC721Received-address-address-uint256-bytes-) * [\_recover(account, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-_recover-address-uint256-) * [underlying()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-underlying--) #### [IERC721Receiver](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver-toc) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-21) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-supportsInterface-bytes4-) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-ownerOf-uint256-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-tokenURI-uint256-) * [\_baseURI()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_baseURI--) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-approve-address-uint256-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-getApproved-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-setApprovalForAll-address-bool-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-isApprovedForAll-address-address-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-transferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-safeTransferFrom-address-address-uint256-bytes-) * [\_ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_ownerOf-uint256-) * [\_getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_getApproved-uint256-) * [\_isAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_isAuthorized-address-address-uint256-) * [\_checkAuthorized(owner, spender, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_checkAuthorized-address-address-uint256-) * [\_increaseBalance(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_increaseBalance-address-uint128-) * [\_update(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_update-address-uint256-address-) * [\_mint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_mint-address-uint256-) * [\_safeMint(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-) * [\_safeMint(to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeMint-address-uint256-bytes-) * [\_burn(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_burn-uint256-) * [\_transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_transfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-) * [\_safeTransfer(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_safeTransfer-address-address-uint256-bytes-) * [\_approve(to, tokenId, auth)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-) * [\_approve(to, tokenId, auth, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_approve-address-uint256-address-bool-) * [\_setApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_setApprovalForAll-address-address-bool-) * [\_requireOwned(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721-_requireOwned-uint256-) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-24) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-24) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-24) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-24) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-26) ### Events #### [IERC721Receiver](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver-toc-1) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-22) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-25) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-25) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-25) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-25) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-27) ### Errors * [ERC721UnsupportedToken(token)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-ERC721UnsupportedToken-address-) #### [IERC721Receiver](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver-toc-2) #### [ERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721-toc-23) #### [IERC721Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721errors-toc-26) * [ERC721InvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOwner-address-) * [ERC721NonexistentToken(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721NonexistentToken-uint256-) * [ERC721IncorrectOwner(sender, tokenId, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721IncorrectOwner-address-uint256-address-) * [ERC721InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidSender-address-) * [ERC721InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidReceiver-address-) * [ERC721InsufficientApproval(operator, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InsufficientApproval-address-uint256-) * [ERC721InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidApprover-address-) * [ERC721InvalidOperator(operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Errors-ERC721InvalidOperator-address-) #### [IERC721Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata-toc-26) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-26) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc165-toc-26) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-28) constructor(contract IERC721 underlyingToken) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-constructor-contract-IERC721-) depositFor(address account, uint256\[\] tokenIds) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-depositFor-address-uint256---) Allow a user to deposit underlying tokens and mint the corresponding tokenIds. withdrawTo(address account, uint256\[\] tokenIds) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-withdrawTo-address-uint256---) Allow a user to burn wrapped tokens and withdraw the corresponding tokenIds of the underlying tokens. onERC721Received(address, address from, uint256 tokenId, bytes) → bytes4 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-onERC721Received-address-address-uint256-bytes-) Overrides [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) to allow minting on direct ERC-721 transfers to this contract. In case there's data attached, it validates that the operator is this contract, so only trusted data is accepted from [`ERC20Wrapper.depositFor`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20Wrapper-depositFor-address-uint256-) . Doesn't work with unsafe transfers (eg. [`IERC721.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-transferFrom-address-address-uint256-) ). Use [`ERC721Wrapper._recover`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Wrapper-_recover-address-uint256-) for recovering in that scenario. \_recover(address account, uint256 tokenId) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-_recover-address-uint256-) Mint a wrapped token to cover any underlyingToken that would have been transferred by mistake. Internal function that can be exposed with access control if desired. underlying() → contract IERC721 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-underlying--) Returns the underlying token. ERC721UnsupportedToken(address token) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Wrapper-ERC721UnsupportedToken-address-) The received ERC-721 token couldn't be wrapped. [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721enumerable) ------------------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol) import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; See [https://eips.ethereum.org/EIPS/eip-721](https://eips.ethereum.org/EIPS/eip-721) ### Functions * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Enumerable-totalSupply--) * [tokenOfOwnerByIndex(owner, index)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Enumerable-tokenOfOwnerByIndex-address-uint256-) * [tokenByIndex(index)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Enumerable-tokenByIndex-uint256-) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-27) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ownerOf-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-bytes-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-transferFrom-address-address-uint256-) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-approve-address-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-setApprovalForAll-address-bool-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-getApproved-uint256-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-isApprovedForAll-address-address-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-29) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC165-supportsInterface-bytes4-) ### Events #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-28) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-30) totalSupply() → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Enumerable-totalSupply--) Returns the total amount of tokens stored by the contract. tokenOfOwnerByIndex(address owner, uint256 index) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Enumerable-tokenOfOwnerByIndex-address-uint256-) Returns a token ID owned by `owner` at a given `index` of its token list. Use along with [`IERC777.balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-balanceOf-address-) to enumerate all of `owner`'s tokens. tokenByIndex(uint256 index) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Enumerable-tokenByIndex-uint256-) Returns a token ID at a given `index` of all the tokens stored by the contract. Use along with [`IERC777.totalSupply`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-totalSupply--) to enumerate all tokens. [`IERC721Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata) -------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/extensions/IERC721Metadata.sol) import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; See [https://eips.ethereum.org/EIPS/eip-721](https://eips.ethereum.org/EIPS/eip-721) ### Functions * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Metadata-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Metadata-symbol--) * [tokenURI(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Metadata-tokenURI-uint256-) #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-29) * [balanceOf(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-balanceOf-address-) * [ownerOf(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ownerOf-uint256-) * [safeTransferFrom(from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-bytes-) * [safeTransferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-) * [transferFrom(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-transferFrom-address-address-uint256-) * [approve(to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-approve-address-uint256-) * [setApprovalForAll(operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-setApprovalForAll-address-bool-) * [getApproved(tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-getApproved-uint256-) * [isApprovedForAll(owner, operator)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-isApprovedForAll-address-address-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-31) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC165-supportsInterface-bytes4-) ### Events #### [IERC721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721-toc-30) * [Transfer(from, to, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Transfer-address-address-uint256-) * [Approval(owner, approved, tokenId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-Approval-address-address-uint256-) * [ApprovalForAll(owner, operator, approved)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-ApprovalForAll-address-address-bool-) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc165-toc-32) name() → string external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Metadata-name--) Returns the token collection name. symbol() → string external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Metadata-symbol--) Returns the token collection symbol. tokenURI(uint256 tokenId) → string external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC721Metadata-tokenURI-uint256-) Returns the Uniform Resource Identifier (URI) for `tokenId` token. [`ERC721Holder`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721holder) -------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/utils/ERC721Holder.sol) import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; Implementation of the [`IERC721Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver) interface. Accepts all token transfers. Make sure the contract is able to use its token with [`IERC721.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-) , [`IERC721.approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-approve-address-uint256-) or [`IERC721.setApprovalForAll`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721-setApprovalForAll-address-bool-) . ### Functions * [onERC721Received(, , , )](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Holder-onERC721Received-address-address-uint256-bytes-) #### [IERC721Receiver](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver-toc-3) onERC721Received(address, address, uint256, bytes) → bytes4 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Holder-onERC721Received-address-address-uint256-bytes-) See [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) . Always returns `IERC721Receiver.onERC721Received.selector`. [`ERC721Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721utils) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC721/utils/ERC721Utils.sol) import "@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol"; Library that provide common ERC-721 utility functions. See [ERC-721](https://eips.ethereum.org/EIPS/eip-721) . _Available since v5.1._ ### Functions * [checkOnERC721Received(operator, from, to, tokenId, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ERC721Utils-checkOnERC721Received-address-address-address-uint256-bytes-) checkOnERC721Received(address operator, address from, address to, uint256 tokenId, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721Utils-checkOnERC721Received-address-address-address-uint256-bytes-) Performs an acceptance check for the provided `operator` by calling [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). Otherwise, the recipient must implement [`IERC721Receiver.onERC721Received`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) and return the acceptance magic value to accept the transfer. ### On this page [Core](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#core) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#extensions) [Utilities](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#utilities) [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721) [`IERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721) [`IERC721Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721receiver) [`ERC721Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721burnable) [`ERC721Consecutive`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721consecutive) [`ERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721enumerable) [`ERC721Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721pausable) [`ERC721Royalty`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721royalty) [`ERC721URIStorage`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721uristorage) [`ERC721Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721votes) [`ERC721Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721wrapper) [`IERC721Enumerable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721enumerable) [`IERC721Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#ierc721metadata) [`ERC721Holder`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721holder) [`ERC721Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721#erc721utils) --- # ERC20 | OpenZeppelin Docs OpenZeppelin Contracts[API Reference](https://docs.openzeppelin.com/contracts/5.x/api) Token ERC20 ===== Smart contract ERC20 utilities and implementations Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This set of interfaces, contracts, and utilities are all related to the [ERC-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20) . For an overview of ERC-20 tokens and a walk through on how to create a token contract read our [ERC-20 guide](https://docs.openzeppelin.com/contracts/5.x/erc20) . There are a few core contracts that implement the behavior specified in the ERC-20 standard: * [`IERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20) : the interface all ERC-20 implementations should conform to. * [`IERC20Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata) : the extended ERC-20 interface including the [`name`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) , [`symbol`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) and [`decimals`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) functions. * [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) : the implementation of the ERC-20 interface, including the [`name`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) , [`symbol`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) and [`decimals`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) optional extensions to the standard interface. Additionally there are multiple custom extensions, including: * [`ERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit) : gasless approval of tokens (standardized as ERC-2612). * [`ERC20Bridgeable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable) : compatibility with crosschain bridges through ERC-7802. * [`ERC20Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Burnable) : destruction of own tokens. * [`ERC20Capped`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped) : enforcement of a cap to the total supply when minting tokens. * [`ERC20Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Pausable) : ability to pause token transfers. * [`ERC20FlashMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint) : token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC-3156). * [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes) : support for voting and vote delegation. * [`ERC20Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper) : wrapper to create an ERC-20 backed by another ERC-20, with deposit and withdraw methods. Useful in conjunction with [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes) . * [`ERC20TemporaryApproval`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval) : support for approvals lasting for only one transaction, as defined in ERC-7674. * [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) : support for calling the target of a transfer or approval, enabling code execution on the receiver within a single transaction. * [`ERC4626`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626) : tokenized vault that manages shares (represented as ERC-20) that are backed by assets (another ERC-20). Finally, there are some utilities to interact with ERC-20 contracts in various ways: * [`SafeERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20) : a wrapper around the interface that eliminates the need to handle boolean return values. Other utilities that support ERC-20 assets can be found in the codebase: * ERC-20 tokens can be timelocked (held for a beneficiary until a specified time) or vested (released following a given schedule) using a [`VestingWallet`](https://docs.openzeppelin.com/contracts/5.x/api/finance#VestingWallet) . This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC-20 (such as [`_mint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) ) and expose them as external functions in the way they prefer. [Core](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#core) ------------------------------------------------------------------------- [`IERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20) [`IERC20Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata) [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#extensions) ------------------------------------------------------------------------------------- [`IERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Permit) [`ERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit) [`ERC20Bridgeable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable) [`ERC20Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Burnable) [`ERC20Capped`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped) [`ERC20Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Pausable) [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes) [`ERC20Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper) [`ERC20FlashMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint) [`ERC20TemporaryApproval`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval) [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) [`ERC4626`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626) [Utilities](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#utilities) ----------------------------------------------------------------------------------- [`SafeERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20) [`ERC1363Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363Utils) [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20) ----------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/ERC20.sol) import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; Implementation of the [`IERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20) interface. This implementation is agnostic to the way tokens are created. This means that a supply mechanism has to be added in a derived contract using [`ERC1155._mint`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_mint-address-uint256-uint256-bytes-) . For a detailed writeup see our guide [How to implement supply mechanisms](https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226) . The default value of [`IERC6909Metadata.decimals`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909Metadata-decimals-uint256-) is 18. To change this, you should override this function so it returns a different value. We have followed general OpenZeppelin Contracts guidelines: functions revert instead returning `false` on failure. This behavior is nonetheless conventional and does not conflict with the expectations of ERC-20 applications. ### Functions * [constructor(name\_, symbol\_)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-constructor-string-string-) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc) ### Events #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-1) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-1) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-1) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-2) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-2) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-2) constructor(string name\_, string symbol\_) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-constructor-string-string-) Sets the values for [`Governor.name`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Governor-name--) and [`IERC777.symbol`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-symbol--) . Both values are immutable: they can only be set once during construction. name() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-name--) Returns the name of the token. symbol() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-symbol--) Returns the symbol of the token, usually a shorter version of the name. decimals() → uint8 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-decimals--) Returns the number of decimals used to get its user 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, unless it's overridden. This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including [`IERC20.balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-balanceOf-address-) and [`IERC20.transfer`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transfer-address-uint256-) . totalSupply() → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-totalSupply--) Returns the value of tokens in existence. balanceOf(address account) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-balanceOf-address-) Returns the value of tokens owned by `account`. transfer(address to, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-transfer-address-uint256-) See [`IERC20.transfer`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transfer-address-uint256-) . Requirements: * `to` cannot be the zero address. * the caller must have a balance of at least `value`. allowance(address owner, address spender) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-allowance-address-address-) Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) . This is zero by default. This value changes when [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) are called. approve(address spender, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-approve-address-uint256-) See [`IERC20.approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) . If `value` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: * `spender` cannot be the zero address. transferFrom(address from, address to, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-transferFrom-address-address-uint256-) See [`IERC20.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transferFrom-address-address-uint256-) . Skips emitting an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event indicating an allowance update. This is not required by the ERC. See [\_approve](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) . Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: * `from` and `to` cannot be the zero address. * `from` must have a balance of at least `value`. * the caller must have allowance for `from`'s tokens of at least `value`. \_transfer(address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_transfer-address-address-uint256-) Moves a `value` amount of tokens from `from` to `to`. This internal function is equivalent to [`IERC6909.transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transfer-address-uint256-uint256-) , and can be used to e.g. implement automatic token fees, slashing mechanisms, etc. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. This function is not virtual, [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) should be overridden instead. \_update(address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_update-address-address-uint256-) 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 [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. \_mint(address account, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_mint-address-uint256-) Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). Relies on the `_update` mechanism Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event with `from` set to the zero address. This function is not virtual, [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) should be overridden instead. \_burn(address account, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_burn-address-uint256-) Destroys a `value` amount of tokens from `account`, lowering the total supply. Relies on the `_update` mechanism. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event with `to` set to the zero address. This function is not virtual, [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) should be overridden instead \_approve(address owner, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_approve-address-address-uint256-) Sets `value` as the allowance of `spender` over the `owner`'s tokens. This internal function is equivalent to `approve`, and can be used to e.g. set automatic allowances for certain subsystems, etc. Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. Requirements: * `owner` cannot be the zero address. * `spender` cannot be the zero address. Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. \_approve(address owner, address spender, uint256 value, bool emitEvent) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_approve-address-address-uint256-bool-) Variant of [`ERC20._approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) with an optional flag to enable or disable the [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. By default (when calling [`ERC20._approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) ) the flag is set to true. On the other hand, approval changes made by `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any `Approval` event during `transferFrom` operations. Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to true using the following override: function _approve(address owner, address spender, uint256 value, bool) internal virtual override { super._approve(owner, spender, value, true); } Requirements are the same as [`ERC20._approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) . \_spendAllowance(address owner, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20-_spendAllowance-address-address-uint256-) Updates `owner`'s allowance for `spender` based on spent `value`. Does not update the allowance value in case of infinite allowance. Revert if not enough allowance is available. Does not emit an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. [`IERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20) ------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/IERC20.sol) import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; Interface of the ERC-20 standard as defined in the ERC. ### Functions * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transferFrom-address-address-uint256-) ### Events * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) totalSupply() → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-totalSupply--) Returns the value of tokens in existence. balanceOf(address account) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-balanceOf-address-) Returns the value of tokens owned by `account`. transfer(address to, uint256 value) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-transfer-address-uint256-) Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. allowance(address owner, address spender) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-allowance-address-address-) Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) . This is zero by default. This value changes when [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) or [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) are called. approve(address spender, uint256 value) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-approve-address-uint256-) Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: [https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729) Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. transferFrom(address from, address to, uint256 value) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-transferFrom-address-address-uint256-) Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. Transfer(address indexed from, address indexed to, uint256 value) event [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-Transfer-address-address-uint256-) Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero. Approval(address indexed owner, address indexed spender, uint256 value) event [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20-Approval-address-address-uint256-) Emitted when the allowance of a `spender` for an `owner` is set by a call to [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) . `value` is the new allowance. [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc1363) --------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC1363.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC1363.sol"; Extension of [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) tokens that adds support for code execution after transfers and approvals on recipient contracts. Calls after transfers are enabled through the [`ERC1363.transferAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferAndCall-address-uint256-bytes-) and [`ERC1363.transferFromAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferFromAndCall-address-address-uint256-bytes-) methods while calls after approvals can be made with [`ERC1363.approveAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-approveAndCall-address-uint256-bytes-) _Available since v5.1._ ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-supportsInterface-bytes4-) * [transferAndCall(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferAndCall-address-uint256-) * [transferAndCall(to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferAndCall-address-uint256-bytes-) * [transferFromAndCall(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferFromAndCall-address-address-uint256-) * [transferFromAndCall(from, to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-transferFromAndCall-address-address-uint256-bytes-) * [approveAndCall(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-approveAndCall-address-uint256-) * [approveAndCall(spender, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-approveAndCall-address-uint256-bytes-) #### [IERC1363](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc1363-toc) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-3) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-3) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-3) ### Events #### [IERC1363](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc1363-toc-1) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc-1) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc-1) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-1) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-4) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-4) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-4) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC1363TransferFailed(receiver, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-ERC1363TransferFailed-address-uint256-) * [ERC1363TransferFromFailed(sender, receiver, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-ERC1363TransferFromFailed-address-address-uint256-) * [ERC1363ApproveFailed(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-ERC1363ApproveFailed-address-uint256-) #### [IERC1363](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc1363-toc-2) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc-2) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc-2) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-2) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-5) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-5) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-5) supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-supportsInterface-bytes4-) 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. transferAndCall(address to, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-transferAndCall-address-uint256-) Moves a `value` amount of tokens from the caller's account to `to` and then calls [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) on `to`. Returns a flag that indicates if the call succeeded. Requirements: * The target has code (i.e. is a contract). * The target `to` must implement the [`IERC1363Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver) interface. * The target must return the [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) selector to accept the transfer. * The internal [`IERC6909.transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transfer-address-uint256-uint256-) must succeed (returned `true`). transferAndCall(address to, uint256 value, bytes data) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-transferAndCall-address-uint256-bytes-) Variant of [`IERC1363.transferAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363-transferAndCall-address-uint256-bytes-) that accepts an additional `data` parameter with no specified format. transferFromAndCall(address from, address to, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-transferFromAndCall-address-address-uint256-) Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism and then calls [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) on `to`. Returns a flag that indicates if the call succeeded. Requirements: * The target has code (i.e. is a contract). * The target `to` must implement the [`IERC1363Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver) interface. * The target must return the [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) selector to accept the transfer. * The internal [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) must succeed (returned `true`). transferFromAndCall(address from, address to, uint256 value, bytes data) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-transferFromAndCall-address-address-uint256-bytes-) Variant of [`IERC1363.transferFromAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363-transferFromAndCall-address-address-uint256-bytes-) that accepts an additional `data` parameter with no specified format. approveAndCall(address spender, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-approveAndCall-address-uint256-) Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens and then calls [`IERC1363Spender.onApprovalReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender-onApprovalReceived-address-uint256-bytes-) on `spender`. Returns a flag that indicates if the call succeeded. Requirements: * The target has code (i.e. is a contract). * The target `spender` must implement the [`IERC1363Spender`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender) interface. * The target must return the [`IERC1363Spender.onApprovalReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender-onApprovalReceived-address-uint256-bytes-) selector to accept the approval. * The internal [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) must succeed (returned `true`). approveAndCall(address spender, uint256 value, bytes data) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-approveAndCall-address-uint256-bytes-) Variant of [`IERC1363.approveAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363-approveAndCall-address-uint256-bytes-) that accepts an additional `data` parameter with no specified format. ERC1363TransferFailed(address receiver, uint256 value) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-ERC1363TransferFailed-address-uint256-) Indicates a failure within the [`IERC6909.transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transfer-address-uint256-uint256-) part of a transferAndCall operation. ERC1363TransferFromFailed(address sender, address receiver, uint256 value) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-ERC1363TransferFromFailed-address-address-uint256-) Indicates a failure within the [`IERC6909.transferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-transferFrom-address-address-uint256-uint256-) part of a transferFromAndCall operation. ERC1363ApproveFailed(address spender, uint256 value) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363-ERC1363ApproveFailed-address-uint256-) Indicates a failure within the [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) part of a approveAndCall operation. [`ERC20Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20burnable) --------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Burnable.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; Extension of [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) that allows token holders to destroy both their own tokens and those that they have an allowance for, in a way that can be recognized off-chain (via event analysis). ### Functions * [burn(value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Burnable-burn-uint256-) * [burnFrom(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Burnable-burnFrom-address-uint256-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-3) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-6) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-6) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-6) ### Events #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-4) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-7) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-7) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-7) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-5) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-8) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-8) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-8) burn(uint256 value) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Burnable-burn-uint256-) Destroys a `value` amount of tokens from the caller. See [`ERC20._burn`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) . burnFrom(address account, uint256 value) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Burnable-burnFrom-address-uint256-) Destroys a `value` amount of tokens from `account`, deducting from the caller's allowance. See [`ERC20._burn`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) and [`ERC20.allowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) . Requirements: * the caller must have allowance for `accounts`'s tokens of at least `value`. [`ERC20Capped`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20capped) ----------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Capped.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; Extension of [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) that adds a cap to the supply of tokens. ### Functions * [constructor(cap\_)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped-constructor-uint256-) * [cap()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped-cap--) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped-_update-address-address-uint256-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-6) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-9) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-9) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-9) ### Events #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-7) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-10) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-10) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-10) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC20ExceededCap(increasedSupply, cap)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped-ERC20ExceededCap-uint256-uint256-) * [ERC20InvalidCap(cap)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped-ERC20InvalidCap-uint256-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-8) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-11) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-11) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-11) constructor(uint256 cap\_) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Capped-constructor-uint256-) Sets the value of the `cap`. This value is immutable, it can only be set once during construction. cap() → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Capped-cap--) Returns the cap on the token's total supply. \_update(address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Capped-_update-address-address-uint256-) 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 [`IERC6909.Transfer`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Transfer-address-address-address-uint256-uint256-) event. ERC20ExceededCap(uint256 increasedSupply, uint256 cap) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Capped-ERC20ExceededCap-uint256-uint256-) Total supply cap has been exceeded. ERC20InvalidCap(uint256 cap) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Capped-ERC20InvalidCap-uint256-) The supplied cap is not a valid cap. [`ERC20FlashMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20flashmint) ----------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20FlashMint.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol"; Implementation of the ERC-3156 Flash loans extension, as defined in [ERC-3156](https://eips.ethereum.org/EIPS/eip-3156) . Adds the [`IERC3156FlashLender.flashLoan`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashLender-flashLoan-contract-IERC3156FlashBorrower-address-uint256-bytes-) method, which provides flash loan support at the token level. By default there is no fee, but this can be changed by overriding [`IERC3156FlashLender.flashFee`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashLender-flashFee-address-uint256-) . When this extension is used along with the [`ERC20Capped`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Capped) or [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes) extensions, [`IERC3156FlashLender.maxFlashLoan`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashLender-maxFlashLoan-address-) will not correctly reflect the maximum that can be flash minted. We recommend overriding [`IERC3156FlashLender.maxFlashLoan`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashLender-maxFlashLoan-address-) so that it correctly reflects the supply cap. ### Functions * [maxFlashLoan(token)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-maxFlashLoan-address-) * [flashFee(token, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-flashFee-address-uint256-) * [\_flashFee(token, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-_flashFee-address-uint256-) * [\_flashFeeReceiver()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-_flashFeeReceiver--) * [flashLoan(receiver, token, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-flashLoan-contract-IERC3156FlashBorrower-address-uint256-bytes-) #### [IERC3156FlashLender](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc3156flashlender-toc) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-9) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-12) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-12) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-12) ### Events #### [IERC3156FlashLender](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc3156flashlender-toc-1) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-10) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-13) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-13) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-13) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC3156UnsupportedToken(token)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-ERC3156UnsupportedToken-address-) * [ERC3156ExceededMaxLoan(maxLoan)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-ERC3156ExceededMaxLoan-uint256-) * [ERC3156InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-ERC3156InvalidReceiver-address-) #### [IERC3156FlashLender](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc3156flashlender-toc-2) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-11) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-14) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-14) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-14) maxFlashLoan(address token) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-maxFlashLoan-address-) Returns the maximum amount of tokens available for loan. flashFee(address token, uint256 value) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-flashFee-address-uint256-) Returns the fee applied when doing flash loans. This function calls the [`ERC20FlashMint._flashFee`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20FlashMint-_flashFee-address-uint256-) function which returns the fee applied when doing flash loans. \_flashFee(address token, uint256 value) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-_flashFee-address-uint256-) Returns the fee applied when doing flash loans. By default this implementation has 0 fees. This function can be overloaded to make the flash loan mechanism deflationary. \_flashFeeReceiver() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-_flashFeeReceiver--) Returns the receiver address of the flash fee. By default this implementation returns the address(0) which means the fee amount will be burnt. This function can be overloaded to change the fee receiver. flashLoan(contract IERC3156FlashBorrower receiver, address token, uint256 value, bytes data) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-flashLoan-contract-IERC3156FlashBorrower-address-uint256-bytes-) Performs a flash loan. New tokens are minted and sent to the `receiver`, who is required to implement the [`IERC3156FlashBorrower`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashBorrower) interface. By the end of the flash loan, the receiver is expected to own value + fee tokens and have them approved back to the token contract itself so they can be burned. ERC3156UnsupportedToken(address token) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-ERC3156UnsupportedToken-address-) The loan token is not valid. ERC3156ExceededMaxLoan(uint256 maxLoan) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-ERC3156ExceededMaxLoan-uint256-) The requested loan exceeds the max loan value for `token`. ERC3156InvalidReceiver(address receiver) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20FlashMint-ERC3156InvalidReceiver-address-) The receiver of a flashloan is not a valid [`IERC3156FlashBorrower.onFlashLoan`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC3156FlashBorrower-onFlashLoan-address-address-uint256-uint256-bytes-) implementer. [`ERC20Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20pausable) --------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Pausable.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; ERC-20 token with pausable token transfers, minting and burning. Useful for scenarios such as preventing trades until the end of an evaluation period, or having an emergency switch for freezing all token transfers in the event of a large bug. This contract does not include public pause and unpause functions. In addition to inheriting this contract, you must define both functions, invoking the [`Pausable._pause`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Pausable-_pause--) and [`Pausable._unpause`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Pausable-_unpause--) internal functions, with appropriate access control, e.g. using [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) or [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) . Not doing so will make the contract pause mechanism of the contract unreachable, and thus unusable. ### Functions * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Pausable-_update-address-address-uint256-) #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#pausable-toc) * [paused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-paused--) * [\_requireNotPaused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-_requireNotPaused--) * [\_requirePaused()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-_requirePaused--) * [\_pause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-_pause--) * [\_unpause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-_unpause--) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-12) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-15) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-15) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-15) ### Events #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#pausable-toc-1) * [Paused(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-Paused-address-) * [Unpaused(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-Unpaused-address-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-13) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-16) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-16) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-16) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors #### [Pausable](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#pausable-toc-2) * [EnforcedPause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-EnforcedPause--) * [ExpectedPause()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Pausable-ExpectedPause--) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-14) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-17) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-17) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-17) \_update(address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Pausable-_update-address-address-uint256-) See [`ERC20._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) . Requirements: * the contract must not be paused. [`ERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20permit) ----------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Permit.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in [ERC-2612](https://eips.ethereum.org/EIPS/eip-2612) . Adds the [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) method, which can be used to change an account's ERC-20 allowance (see [`IERC20.allowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-allowance-address-address-) ) by presenting a message signed by the account. By not relying on `[`IERC20.approve`](#IERC20-approve-address-uint256-)`, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ### Functions * [constructor(name)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-constructor-string-) * [permit(owner, spender, value, deadline, v, r, s)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) * [nonces(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-nonces-address-) * [DOMAIN\_SEPARATOR()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-DOMAIN_SEPARATOR--) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc) * [\_useNonce(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-_useNonce-address-) * [\_useCheckedNonce(owner, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-_useCheckedNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc) * [\_domainSeparatorV4()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_domainSeparatorV4--) * [\_hashTypedDataV4(structHash)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_hashTypedDataV4-bytes32-) * [eip712Domain()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-eip712Domain--) * [\_EIP712Name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_EIP712Name--) * [\_EIP712Version()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_EIP712Version--) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc) #### [IERC20Permit](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20permit-toc) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-15) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-18) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-18) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-18) ### Events #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc-1) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc-1) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc-1) * [EIP712DomainChanged()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC5267-EIP712DomainChanged--) #### [IERC20Permit](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20permit-toc-1) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-16) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-19) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-19) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-19) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC2612ExpiredSignature(deadline)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-ERC2612ExpiredSignature-uint256-) * [ERC2612InvalidSigner(signer, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-ERC2612InvalidSigner-address-address-) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc-2) * [InvalidAccountNonce(account, currentNonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-InvalidAccountNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc-2) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc-2) #### [IERC20Permit](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20permit-toc-2) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-17) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-20) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-20) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-20) constructor(string name) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-constructor-string-) Initializes the [`EIP712`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#EIP712) domain separator using the `name` parameter, and setting `version` to `"1"`. It's a good idea to use the same `name` that is defined as the ERC-20 token name. permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) Sets `value` as the allowance of `spender` over `owner`'s tokens, given `owner`'s signed approval. The same issues [`IERC20.approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) has related to transaction ordering also apply here. Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. Requirements: * `spender` cannot be the zero address. * `deadline` must be a timestamp in the future. * `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. * the signature must use `owner`'s current nonce (see [`ERC20Permit.nonces`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-nonces-address-) ). For more information on the signature format, see the [relevant EIP section](https://eips.ethereum.org/EIPS/eip-2612#specification) . CAUTION: See Security Considerations above. nonces(address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-nonces-address-) Returns the current nonce for `owner`. This value must be included whenever a signature is generated for [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) . Every successful call to [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) increases `owner`'s nonce by one. This prevents a signature from being used multiple times. DOMAIN\_SEPARATOR() → bytes32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-DOMAIN_SEPARATOR--) Returns the domain separator used in the encoding of the signature for [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) , as defined by [`EIP712`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#EIP712) . ERC2612ExpiredSignature(uint256 deadline) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-ERC2612ExpiredSignature-uint256-) Permit deadline has expired. ERC2612InvalidSigner(address signer, address owner) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Permit-ERC2612InvalidSigner-address-address-) Mismatched signature. [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20votes) --------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Votes.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; Extension of ERC-20 to support Compound-like voting and delegation. This version is more generic than Compound's, and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. This contract does not provide interface compatibility with Compound's COMP token. This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either by calling the [`Votes.delegate`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-delegate-address-) function directly, or by providing a signature to be used with [`Votes.delegateBySig`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-delegateBySig-address-uint256-uint256-uint8-bytes32-bytes32-) . Voting power can be queried through the public accessors [`Votes.getVotes`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-getVotes-address-) and [`Votes.getPastVotes`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-getPastVotes-address-uint256-) . 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. ### Functions * [\_maxSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-_maxSupply--) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-_update-address-address-uint256-) * [\_getVotingUnits(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-_getVotingUnits-address-) * [numCheckpoints(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-numCheckpoints-address-) * [checkpoints(account, pos)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-checkpoints-address-uint32-) #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#votes-toc) * [clock()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-clock--) * [CLOCK\_MODE()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-CLOCK_MODE--) * [\_validateTimepoint(timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_validateTimepoint-uint256-) * [getVotes(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-getVotes-address-) * [getPastVotes(account, timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-getPastVotes-address-uint256-) * [getPastTotalSupply(timepoint)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-getPastTotalSupply-uint256-) * [\_getTotalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_getTotalSupply--) * [delegates(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-delegates-address-) * [delegate(delegatee)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-delegate-address-) * [delegateBySig(delegatee, nonce, expiry, v, r, s)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-delegateBySig-address-uint256-uint256-uint8-bytes32-bytes32-) * [\_delegate(account, delegatee)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_delegate-address-address-) * [\_transferVotingUnits(from, to, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_transferVotingUnits-address-address-uint256-) * [\_moveDelegateVotes(from, to, amount)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_moveDelegateVotes-address-address-uint256-) * [\_numCheckpoints(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_numCheckpoints-address-) * [\_checkpoints(account, pos)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-_checkpoints-address-uint32-) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5805-toc) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ivotes-toc) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc6372-toc) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc-3) * [nonces(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-nonces-address-) * [\_useNonce(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-_useNonce-address-) * [\_useCheckedNonce(owner, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-_useCheckedNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc-3) * [\_domainSeparatorV4()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_domainSeparatorV4--) * [\_hashTypedDataV4(structHash)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_hashTypedDataV4-bytes32-) * [eip712Domain()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-eip712Domain--) * [\_EIP712Name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_EIP712Name--) * [\_EIP712Version()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#EIP712-_EIP712Version--) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc-3) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-18) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-21) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-21) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-21) ### Events #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#votes-toc-1) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5805-toc-1) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ivotes-toc-1) * [DelegateChanged(delegator, fromDelegate, toDelegate)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IVotes-DelegateChanged-address-address-address-) * [DelegateVotesChanged(delegate, previousVotes, newVotes)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IVotes-DelegateVotesChanged-address-uint256-uint256-) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc6372-toc-1) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc-4) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc-4) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc-4) * [EIP712DomainChanged()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC5267-EIP712DomainChanged--) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-19) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-22) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-22) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-22) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC20ExceededSafeSupply(increasedSupply, cap)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes-ERC20ExceededSafeSupply-uint256-uint256-) #### [Votes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#votes-toc-2) * [ERC6372InconsistentClock()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-ERC6372InconsistentClock--) * [ERC5805FutureLookup(timepoint, clock)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Votes-ERC5805FutureLookup-uint256-uint48-) #### [IERC5805](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5805-toc-2) #### [IVotes](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ivotes-toc-2) * [VotesExpiredSignature(expiry)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IVotes-VotesExpiredSignature-uint256-) #### [IERC6372](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc6372-toc-2) #### [Nonces](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#nonces-toc-5) * [InvalidAccountNonce(account, currentNonce)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#Nonces-InvalidAccountNonce-address-uint256-) #### [EIP712](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#eip712-toc-5) #### [IERC5267](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc5267-toc-5) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-20) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-23) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-23) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-23) \_maxSupply() → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-_maxSupply--) Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). This maximum is enforced in [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) . It limits the total supply of the token, which is otherwise a uint256, so that checkpoints can be stored in the Trace208 structure used by [`Votes`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes) . Increasing this value will not remove the underlying limitation, and will cause [`ERC1155._update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-_update-address-address-uint256---uint256---) to fail because of a math overflow in [`Votes._transferVotingUnits`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-_transferVotingUnits-address-address-uint256-) . An override could be used to further restrict the total supply (to a lower value) if additional logic requires it. When resolving override conflicts on this function, the minimum should be returned. \_update(address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-_update-address-address-uint256-) Move voting power when tokens are transferred. Emits a [`IVotes.DelegateVotesChanged`](https://docs.openzeppelin.com/contracts/5.x/api/governance#IVotes-DelegateVotesChanged-address-uint256-uint256-) event. \_getVotingUnits(address account) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-_getVotingUnits-address-) Returns the voting units of an `account`. Overriding this function may compromise the internal vote accounting. `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. numCheckpoints(address account) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-numCheckpoints-address-) Get number of checkpoints for `account`. checkpoints(address account, uint32 pos) → struct Checkpoints.Checkpoint208 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-checkpoints-address-uint32-) Get the `pos`\-th checkpoint for `account`. ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Votes-ERC20ExceededSafeSupply-uint256-uint256-) Total supply cap has been exceeded, introducing a risk of votes overflowing. [`ERC20Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20wrapper) ------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC20Wrapper.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol"; Extension of the ERC-20 token contract to support token wrapping. Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful in conjunction with other modules. For example, combining this wrapping mechanism with [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Votes) will allow the wrapping of an existing "basic" ERC-20 into a governance token. Any mechanism in which the underlying token changes the [`IERC777.balanceOf`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-balanceOf-address-) of an account without an explicit transfer may desynchronize this contract's supply and its underlying balance. Please exercise caution when wrapping tokens that may undercollateralize the wrapper (i.e. wrapper's total supply is higher than its underlying balance). See [`ERC20Wrapper._recover`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-_recover-address-) for recovering value accrued to the wrapper. ### Functions * [constructor(underlyingToken)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-constructor-contract-IERC20-) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-decimals--) * [underlying()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-underlying--) * [depositFor(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-depositFor-address-uint256-) * [withdrawTo(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-withdrawTo-address-uint256-) * [\_recover(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-_recover-address-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-21) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-24) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-24) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-24) ### Events #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-22) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-25) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-25) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-25) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC20InvalidUnderlying(token)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Wrapper-ERC20InvalidUnderlying-address-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-23) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-26) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-26) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-26) constructor(contract IERC20 underlyingToken) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-constructor-contract-IERC20-) decimals() → uint8 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-decimals--) underlying() → contract IERC20 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-underlying--) Returns the address of the underlying ERC-20 token that is being wrapped. depositFor(address account, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-depositFor-address-uint256-) Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. withdrawTo(address account, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-withdrawTo-address-uint256-) Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. \_recover(address account) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-_recover-address-) Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake or acquired from rebasing mechanisms. Internal function that can be exposed with access control if desired. ERC20InvalidUnderlying(address token) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Wrapper-ERC20InvalidUnderlying-address-) The underlying token couldn't be wrapped. [`ERC4626`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc4626) --------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/ERC4626.sol) import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; Implementation of the ERC-4626 "Tokenized Vault Standard" as defined in [ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) . This extension allows the minting and burning of "shares" (represented using the ERC-20 inheritance) in exchange for underlying "assets" through standardized [`IERC4626.deposit`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC4626-deposit-uint256-address-) , [`IERC4626.mint`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC4626-mint-uint256-address-) , [`IERC4626.redeem`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC4626-redeem-uint256-address-address-) and [`IERC777.burn`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC777-burn-uint256-bytes-) workflows. This contract extends the ERC-20 standard. Any additional extensions included along it would affect the "shares" token represented by this contract and not the "assets" token which is an independent contract. In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning with a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by verifying the amount received is as expected, using a wrapper that performs these checks such as [ERC4626Router](https://github.com/fei-protocol/ERC4626#erc4626router-and-base) . Since v4.9, this implementation introduces configurable virtual assets and shares to help developers mitigate that risk. The `_decimalsOffset()` corresponds to an offset in the decimal representation between the underlying asset's decimals and the vault decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which itself determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default offset (0) makes it non-profitable even if an attacker is able to capture value from multiple user deposits, as a result of the value being captured by the virtual shares (out of the attacker's donation) matching the attacker's expected gains. With a larger offset, the attack becomes orders of magnitude more expensive than it is profitable. More details about the underlying math can be found [here](https://docs.openzeppelin.com/contracts/5.x/erc4626#security-concern-inflation-attack) . The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets will cause the first user to exit to experience reduced losses in detriment to the last users that will experience bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the `_convertToShares` and `_convertToAssets` functions. To learn more, check out our [ERC-4626 guide](https://docs.openzeppelin.com/contracts/5.x/erc4626) . ### Functions * [constructor(asset\_)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-constructor-contract-IERC20-) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-decimals--) * [asset()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-asset--) * [totalAssets()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-totalAssets--) * [convertToShares(assets)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-convertToShares-uint256-) * [convertToAssets(shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-convertToAssets-uint256-) * [maxDeposit()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-maxDeposit-address-) * [maxMint()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-maxMint-address-) * [maxWithdraw(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-maxWithdraw-address-) * [maxRedeem(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-maxRedeem-address-) * [previewDeposit(assets)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-previewDeposit-uint256-) * [previewMint(shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-previewMint-uint256-) * [previewWithdraw(assets)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-previewWithdraw-uint256-) * [previewRedeem(shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-previewRedeem-uint256-) * [deposit(assets, receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-deposit-uint256-address-) * [mint(shares, receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-mint-uint256-address-) * [withdraw(assets, receiver, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-withdraw-uint256-address-address-) * [redeem(shares, receiver, owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-redeem-uint256-address-address-) * [\_convertToShares(assets, rounding)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-_convertToShares-uint256-enum-Math-Rounding-) * [\_convertToAssets(shares, rounding)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-_convertToAssets-uint256-enum-Math-Rounding-) * [\_deposit(caller, receiver, assets, shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-_deposit-address-address-uint256-uint256-) * [\_withdraw(caller, receiver, owner, assets, shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-_withdraw-address-address-address-uint256-uint256-) * [\_decimalsOffset()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-_decimalsOffset--) #### [IERC4626](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc4626-toc) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-24) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-27) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-27) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-27) ### Events #### [IERC4626](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc4626-toc-1) * [Deposit(sender, owner, assets, shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC4626-Deposit-address-address-uint256-uint256-) * [Withdraw(sender, receiver, owner, assets, shares)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC4626-Withdraw-address-address-address-uint256-uint256-) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-25) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-28) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-28) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-28) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors * [ERC4626ExceededMaxDeposit(receiver, assets, max)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-ERC4626ExceededMaxDeposit-address-uint256-uint256-) * [ERC4626ExceededMaxMint(receiver, shares, max)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-ERC4626ExceededMaxMint-address-uint256-uint256-) * [ERC4626ExceededMaxWithdraw(owner, assets, max)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-ERC4626ExceededMaxWithdraw-address-uint256-uint256-) * [ERC4626ExceededMaxRedeem(owner, shares, max)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC4626-ERC4626ExceededMaxRedeem-address-uint256-uint256-) #### [IERC4626](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc4626-toc-2) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-26) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-29) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-29) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-29) constructor(contract IERC20 asset\_) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-constructor-contract-IERC20-) Set the underlying asset contract. This must be an ERC20-compatible contract (ERC-20 or ERC-777). decimals() → uint8 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-decimals--) Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals. See [`IERC20Metadata.decimals`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata-decimals--) . asset() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-asset--) Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * MUST be an ERC-20 token contract. * MUST NOT revert. totalAssets() → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-totalAssets--) Returns the total amount of the underlying asset that is “managed” by Vault. * SHOULD include any compounding that occurs from yield. * MUST be inclusive of any fees that are charged against assets in the Vault. * MUST NOT revert. convertToShares(uint256 assets) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-convertToShares-uint256-) Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal scenario where all the conditions are met. * 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 revert. 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. convertToAssets(uint256 shares) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-convertToAssets-uint256-) Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal scenario where all the conditions are met. * 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 revert. 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. maxDeposit(address) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-maxDeposit-address-) Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, through a deposit call. * 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 revert. maxMint(address) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-maxMint-address-) Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * 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 revert. maxWithdraw(address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-maxWithdraw-address-) Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the Vault, through a withdraw call. * MUST return a limited value if owner is subject to some withdrawal limit or timelock. * MUST NOT revert. maxRedeem(address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-maxRedeem-address-) Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, through a redeem call. * MUST return a limited value if owner is subject to some withdrawal limit or timelock. * MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * MUST NOT revert. previewDeposit(uint256 assets) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-previewDeposit-uint256-) Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions. * 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. deposit should return the same or more shares as previewDeposit if called in the same transaction. * MUST NOT account for deposit limits like those returned from maxDeposit 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 revert. any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing. previewMint(uint256 shares) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-previewMint-uint256-) Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions. * 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. mint should return the same or fewer assets as previewMint if called in the same transaction. * MUST NOT account for mint limits like those returned from maxMint 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 revert. any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by minting. previewWithdraw(uint256 assets) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-previewWithdraw-uint256-) Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions. * 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. withdraw should return the same or fewer shares as previewWithdraw if called in the same transaction. * MUST NOT account for withdrawal limits like those returned from maxWithdraw 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 revert. any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing. previewRedeem(uint256 shares) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-previewRedeem-uint256-) Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block, given current on-chain conditions. * 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. redeem should return the same or more assets as previewRedeem if called in the same transaction. * MUST NOT account for redemption limits like those returned from maxRedeem 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 revert. any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by redeeming. deposit(uint256 assets, address receiver) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-deposit-uint256-address-) Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * MUST emit the 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 revert 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. mint(uint256 shares, address receiver) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-mint-uint256-address-) Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * MUST emit the 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 revert 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. withdraw(uint256 assets, address receiver, address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-withdraw-uint256-address-address-) Burns shares from owner and sends exactly assets of underlying tokens to receiver. * MUST emit the 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). Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. Those methods should be performed separately. redeem(uint256 shares, address receiver, address owner) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-redeem-uint256-address-address-) Burns exactly shares from owner and sends assets of underlying tokens to receiver. * MUST emit the 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. \_convertToShares(uint256 assets, enum Math.Rounding rounding) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-_convertToShares-uint256-enum-Math-Rounding-) Internal conversion function (from assets to shares) with support for rounding direction. \_convertToAssets(uint256 shares, enum Math.Rounding rounding) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-_convertToAssets-uint256-enum-Math-Rounding-) Internal conversion function (from shares to assets) with support for rounding direction. \_deposit(address caller, address receiver, uint256 assets, uint256 shares) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-_deposit-address-address-uint256-uint256-) Deposit/mint common workflow. \_withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-_withdraw-address-address-address-uint256-uint256-) Withdraw/redeem common workflow. \_decimalsOffset() → uint8 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-_decimalsOffset--) ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-ERC4626ExceededMaxDeposit-address-uint256-uint256-) Attempted to deposit more assets than the max amount for `receiver`. ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-ERC4626ExceededMaxMint-address-uint256-uint256-) Attempted to mint more shares than the max amount for `receiver`. ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-ERC4626ExceededMaxWithdraw-address-uint256-uint256-) Attempted to withdraw more assets than the max amount for `receiver`. ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC4626-ERC4626ExceededMaxRedeem-address-uint256-uint256-) Attempted to redeem more shares than the max amount for `receiver`. [`IERC20Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata) ----------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/IERC20Metadata.sol) import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; Interface for the optional metadata functions from the ERC-20 standard. ### Functions * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Metadata-decimals--) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-30) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-transferFrom-address-address-uint256-) ### Events #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-31) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) name() → string external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Metadata-name--) Returns the name of the token. symbol() → string external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Metadata-symbol--) Returns the symbol of the token. decimals() → uint8 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Metadata-decimals--) Returns the decimals places of the token. [`IERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20permit) ------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/IERC20Permit.sol) import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in [ERC-2612](https://eips.ethereum.org/EIPS/eip-2612) . Adds the [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) method, which can be used to change an account's ERC-20 allowance (see [`IERC20.allowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-allowance-address-address-) ) by presenting a message signed by the account. By not relying on [`IERC20.approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) , the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. \==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also [`SafeERC20.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeTransferFrom-contract-IERC20-address-address-uint256-) ). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit. ### Functions * [permit(owner, spender, value, deadline, v, r, s)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) * [nonces(owner)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Permit-nonces-address-) * [DOMAIN\_SEPARATOR()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Permit-DOMAIN_SEPARATOR--) permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) Sets `value` as the allowance of `spender` over `owner`'s tokens, given `owner`'s signed approval. The same issues [`IERC20.approve`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-approve-address-uint256-) has related to transaction ordering also apply here. Emits an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. Requirements: * `spender` cannot be the zero address. * `deadline` must be a timestamp in the future. * `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. * the signature must use `owner`'s current nonce (see [`ERC20Permit.nonces`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-nonces-address-) ). For more information on the signature format, see the [relevant EIP section](https://eips.ethereum.org/EIPS/eip-2612#specification) . CAUTION: See Security Considerations above. nonces(address owner) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Permit-nonces-address-) Returns the current nonce for `owner`. This value must be included whenever a signature is generated for [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) . Every successful call to [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) increases `owner`'s nonce by one. This prevents a signature from being used multiple times. DOMAIN\_SEPARATOR() → bytes32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/token/IERC20Permit-DOMAIN_SEPARATOR--) Returns the domain separator used in the encoding of the signature for [`ERC20Permit.permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-) , as defined by [`EIP712`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#EIP712) . [`ERC20Bridgeable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20bridgeable) ------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol) import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sol"; ERC20 extension that implements the standard token interface according to [ERC-7802](https://eips.ethereum.org/EIPS/eip-7802) . ### Modifiers * [onlyTokenBridge()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable-onlyTokenBridge--) ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable-supportsInterface-bytes4-) * [crosschainMint(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable-crosschainMint-address-uint256-) * [crosschainBurn(from, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable-crosschainBurn-address-uint256-) * [\_checkTokenBridge(caller)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Bridgeable-_checkTokenBridge-address-) #### [IERC7802](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7802-toc) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc-3) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc-3) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-27) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-allowance-address-address-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-30) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-30) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-32) ### Events #### [IERC7802](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7802-toc-1) * [CrosschainMint(to, amount, sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC7802-CrosschainMint-address-uint256-address-) * [CrosschainBurn(from, amount, sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC7802-CrosschainBurn-address-uint256-address-) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc-4) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc-4) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-28) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-31) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-31) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-33) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors #### [IERC7802](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7802-toc-2) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc165-toc-5) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc165-toc-5) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-29) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-32) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-32) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-34) onlyTokenBridge() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Bridgeable-onlyTokenBridge--) Modifier to restrict access to the token bridge. supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Bridgeable-supportsInterface-bytes4-) 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. crosschainMint(address to, uint256 value) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Bridgeable-crosschainMint-address-uint256-) See [`IERC7802.crosschainMint`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC7802-crosschainMint-address-uint256-) . Emits a [`IERC7802.CrosschainMint`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC7802-CrosschainMint-address-uint256-address-) event. crosschainBurn(address from, uint256 value) public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Bridgeable-crosschainBurn-address-uint256-) See [`IERC7802.crosschainBurn`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC7802-crosschainBurn-address-uint256-) . Emits a [`IERC7802.CrosschainBurn`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC7802-CrosschainBurn-address-uint256-address-) event. \_checkTokenBridge(address caller) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20Bridgeable-_checkTokenBridge-address-) Checks if the caller is a trusted token bridge. MUST revert otherwise. Developers should implement this function using an access control mechanism that allows customizing the list of allowed senders. Consider using [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) or [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged) . [`ERC20TemporaryApproval`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20temporaryapproval) --------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol) import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sol"; Extension of [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) that adds support for temporary allowances following ERC-7674. This is a draft contract. The corresponding ERC is still subject to changes. _Available since v5.1._ ### Functions * [allowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval-allowance-address-address-) * [\_temporaryAllowance(owner, spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval-_temporaryAllowance-address-address-) * [temporaryApprove(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval-temporaryApprove-address-uint256-) * [\_temporaryApprove(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval-_temporaryApprove-address-address-uint256-) * [\_spendAllowance(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20TemporaryApproval-_spendAllowance-address-address-uint256-) #### [IERC7674](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7674-toc) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-30) * [name()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-name--) * [symbol()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-symbol--) * [decimals()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-decimals--) * [totalSupply()](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-totalSupply--) * [balanceOf(account)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-balanceOf-address-) * [transfer(to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transfer-address-uint256-) * [approve(spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-approve-address-uint256-) * [transferFrom(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-transferFrom-address-address-uint256-) * [\_transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_transfer-address-address-uint256-) * [\_update(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_update-address-address-uint256-) * [\_mint(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_mint-address-uint256-) * [\_burn(account, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_burn-address-uint256-) * [\_approve(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-) * [\_approve(owner, spender, value, emitEvent)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_approve-address-address-uint256-bool-) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-33) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-33) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-35) ### Events #### [IERC7674](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7674-toc-1) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-31) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-34) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-34) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-36) * [Transfer(from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Transfer-address-address-uint256-) * [Approval(owner, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20-Approval-address-address-uint256-) ### Errors #### [IERC7674](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc7674-toc-2) #### [ERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20-toc-32) #### [IERC20Errors](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20errors-toc-35) * [ERC20InsufficientBalance(sender, balance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientBalance-address-uint256-uint256-) * [ERC20InvalidSender(sender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSender-address-) * [ERC20InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidReceiver-address-) * [ERC20InsufficientAllowance(spender, allowance, needed)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InsufficientAllowance-address-uint256-uint256-) * [ERC20InvalidApprover(approver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidApprover-address-) * [ERC20InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#IERC20Errors-ERC20InvalidSpender-address-) #### [IERC20Metadata](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata-toc-35) #### [IERC20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20-toc-37) allowance(address owner, address spender) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20TemporaryApproval-allowance-address-address-) [`IERC6909.allowance`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-allowance-address-address-uint256-) override that includes the temporary allowance when looking up the current allowance. If adding up the persistent and the temporary allowances result in an overflow, type(uint256).max is returned. \_temporaryAllowance(address owner, address spender) → uint256 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20TemporaryApproval-_temporaryAllowance-address-address-) Internal getter for the current temporary allowance that `spender` has over `owner` tokens. temporaryApprove(address spender, uint256 value) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20TemporaryApproval-temporaryApprove-address-uint256-) Alternative to [`IERC6909.approve`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-approve-address-uint256-uint256-) that sets a `value` amount of tokens as the temporary allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. Requirements: * `spender` cannot be the zero address. Does NOT emit an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. \_temporaryApprove(address owner, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20TemporaryApproval-_temporaryApprove-address-address-uint256-) Sets `value` as the temporary allowance of `spender` over the `owner`'s tokens. This internal function is equivalent to `temporaryApprove`, and can be used to e.g. set automatic allowances for certain subsystems, etc. Requirements: * `owner` cannot be the zero address. * `spender` cannot be the zero address. Does NOT emit an [`IERC6909.Approval`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC6909-Approval-address-address-uint256-uint256-) event. \_spendAllowance(address owner, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20TemporaryApproval-_spendAllowance-address-address-uint256-) [`ERC20._spendAllowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20-_spendAllowance-address-address-uint256-) override that consumes the temporary allowance (if any) before eventually falling back to consuming the persistent allowance. This function skips calling `super._spendAllowance` if the temporary allowance is enough to cover the spending. [`ERC1363Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc1363utils) ------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/utils/ERC1363Utils.sol) import "@openzeppelin/contracts/token/ERC20/utils/ERC1363Utils.sol"; Library that provides common ERC-1363 utility functions. See [ERC-1363](https://eips.ethereum.org/EIPS/eip-1363) . ### Functions * [checkOnERC1363TransferReceived(operator, from, to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363Utils-checkOnERC1363TransferReceived-address-address-address-uint256-bytes-) * [checkOnERC1363ApprovalReceived(operator, spender, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363Utils-checkOnERC1363ApprovalReceived-address-address-uint256-bytes-) ### Errors * [ERC1363InvalidReceiver(receiver)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363Utils-ERC1363InvalidReceiver-address-) * [ERC1363InvalidSpender(spender)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363Utils-ERC1363InvalidSpender-address-) checkOnERC1363TransferReceived(address operator, address from, address to, uint256 value, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363Utils-checkOnERC1363TransferReceived-address-address-address-uint256-bytes-) Performs a call to [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) on a target address. Requirements: * The target has code (i.e. is a contract). * The target `to` must implement the [`IERC1363Receiver`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver) interface. * The target must return the [`IERC1363Receiver.onTransferReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Receiver-onTransferReceived-address-address-uint256-bytes-) selector to accept the transfer. checkOnERC1363ApprovalReceived(address operator, address spender, uint256 value, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363Utils-checkOnERC1363ApprovalReceived-address-address-uint256-bytes-) Performs a call to [`IERC1363Spender.onApprovalReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender-onApprovalReceived-address-uint256-bytes-) on a target address. Requirements: * The target has code (i.e. is a contract). * The target `spender` must implement the [`IERC1363Spender`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender) interface. * The target must return the [`IERC1363Spender.onApprovalReceived`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1363Spender-onApprovalReceived-address-uint256-bytes-) selector to accept the approval. ERC1363InvalidReceiver(address receiver) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363Utils-ERC1363InvalidReceiver-address-) Indicates a failure with the token `receiver`. Used in transfers. ERC1363InvalidSpender(address spender) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1363Utils-ERC1363InvalidSpender-address-) Indicates a failure with the token `spender`. Used in approvals. [`SafeERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#safeerc20) ------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/token/ERC20/utils/SafeERC20.sol) import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; Wrappers around ERC-20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc. ### Functions * [safeTransfer(token, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeTransfer-contract-IERC20-address-uint256-) * [safeTransferFrom(token, from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeTransferFrom-contract-IERC20-address-address-uint256-) * [trySafeTransfer(token, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-trySafeTransfer-contract-IERC20-address-uint256-) * [trySafeTransferFrom(token, from, to, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-trySafeTransferFrom-contract-IERC20-address-address-uint256-) * [safeIncreaseAllowance(token, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeIncreaseAllowance-contract-IERC20-address-uint256-) * [safeDecreaseAllowance(token, spender, requestedDecrease)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeDecreaseAllowance-contract-IERC20-address-uint256-) * [forceApprove(token, spender, value)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-forceApprove-contract-IERC20-address-uint256-) * [transferAndCallRelaxed(token, to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-transferAndCallRelaxed-contract-IERC1363-address-uint256-bytes-) * [transferFromAndCallRelaxed(token, from, to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-transferFromAndCallRelaxed-contract-IERC1363-address-address-uint256-bytes-) * [approveAndCallRelaxed(token, to, value, data)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-approveAndCallRelaxed-contract-IERC1363-address-uint256-bytes-) ### Errors * [SafeERC20FailedOperation(token)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-SafeERC20FailedOperation-address-) * [SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease)](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-SafeERC20FailedDecreaseAllowance-address-uint256-uint256-) safeTransfer(contract IERC20 token, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-safeTransfer-contract-IERC20-address-uint256-) Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, non-reverting calls are assumed to be successful. safeTransferFrom(contract IERC20 token, address from, address to, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-safeTransferFrom-contract-IERC20-address-address-uint256-) Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. trySafeTransfer(contract IERC20 token, address to, uint256 value) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-trySafeTransfer-contract-IERC20-address-uint256-) Variant of [`SafeERC20.safeTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeTransfer-contract-IERC20-address-uint256-) that returns a bool instead of reverting if the operation is not successful. trySafeTransferFrom(contract IERC20 token, address from, address to, uint256 value) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-trySafeTransferFrom-contract-IERC20-address-address-uint256-) Variant of [`ERC1155.safeTransferFrom`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC1155#ERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-) that returns a bool instead of reverting if the operation is not successful. safeIncreaseAllowance(contract IERC20 token, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-safeIncreaseAllowance-contract-IERC20-address-uint256-) Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, non-reverting calls are assumed to be successful. If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using this function. Performing a [`SafeERC20.safeIncreaseAllowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeIncreaseAllowance-contract-IERC20-address-uint256-) or [`SafeERC20.safeDecreaseAllowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeDecreaseAllowance-contract-IERC20-address-uint256-) operation on a token contract that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. safeDecreaseAllowance(contract IERC20 token, address spender, uint256 requestedDecrease) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-safeDecreaseAllowance-contract-IERC20-address-uint256-) Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no value, non-reverting calls are assumed to be successful. If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using this function. Performing a [`SafeERC20.safeIncreaseAllowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeIncreaseAllowance-contract-IERC20-address-uint256-) or [`SafeERC20.safeDecreaseAllowance`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-safeDecreaseAllowance-contract-IERC20-address-uint256-) operation on a token contract that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. forceApprove(contract IERC20 token, address spender, uint256 value) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-forceApprove-contract-IERC20-address-uint256-) Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval to be set to zero before setting it to a non-zero value, such as USDT. If the token implements ERC-7674, this function will not modify any temporary allowance. This function only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being set here. transferAndCallRelaxed(contract IERC1363 token, address to, uint256 value, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-transferAndCallRelaxed-contract-IERC1363-address-uint256-bytes-) Performs an [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) transferAndCall, with a fallback to the simple [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) transfer if the target has no code. This can be used to implement an [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721) \-like safe transfer that rely on [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) checks when targeting contracts. Reverts if the returned value is other than `true`. transferFromAndCallRelaxed(contract IERC1363 token, address from, address to, uint256 value, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-transferFromAndCallRelaxed-contract-IERC1363-address-address-uint256-bytes-) Performs an [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) transferFromAndCall, with a fallback to the simple [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) transferFrom if the target has no code. This can be used to implement an [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721) \-like safe transfer that rely on [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) checks when targeting contracts. Reverts if the returned value is other than `true`. approveAndCallRelaxed(contract IERC1363 token, address to, uint256 value, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-approveAndCallRelaxed-contract-IERC1363-address-uint256-bytes-) Performs an [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) approveAndCall, with a fallback to the simple [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20) approve if the target has no code. This can be used to implement an [`ERC721`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC721#ERC721) \-like safe transfer that rely on [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363) checks when targeting contracts. When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as [`SafeERC20.forceApprove`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#SafeERC20-forceApprove-contract-IERC20-address-uint256-) . Opposedly, when the recipient address (`to`) has code, this function only attempts to call [`ERC1363.approveAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC1363-approveAndCall-address-uint256-bytes-) once without retrying, and relies on the returned value to be true. Reverts if the returned value is other than `true`. SafeERC20FailedOperation(address token) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-SafeERC20FailedOperation-address-) An operation with an ERC-20 token failed. SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease) error [#](https://docs.openzeppelin.com/contracts/5.x/api/token/SafeERC20-SafeERC20FailedDecreaseAllowance-address-uint256-uint256-) Indicates a failed `decreaseAllowance` request. ### On this page [Core](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#core) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#extensions) [Utilities](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#utilities) [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20) [`IERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20) [`ERC1363`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc1363) [`ERC20Burnable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20burnable) [`ERC20Capped`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20capped) [`ERC20FlashMint`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20flashmint) [`ERC20Pausable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20pausable) [`ERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20permit) [`ERC20Votes`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20votes) [`ERC20Wrapper`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20wrapper) [`ERC4626`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc4626) [`IERC20Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20metadata) [`IERC20Permit`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ierc20permit) [`ERC20Bridgeable`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20bridgeable) [`ERC20TemporaryApproval`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc20temporaryapproval) [`ERC1363Utils`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#erc1363utils) [`SafeERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#safeerc20) --- # Access | OpenZeppelin Docs OpenZeppelin Contracts[API Reference](https://docs.openzeppelin.com/contracts/5.x/api) Access ====== Smart contract access utilities and implementations Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This directory provides ways to restrict who can access the functions of a contract or when they can do it. * [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) is a full-fledged access control solution for smart contract systems. Allows creating and assigning multiple hierarchical roles with execution delays for each account across various contracts. * [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged) delegates its access control to an authority that dictates the permissions of the managed contract. It’s compatible with an AccessManager as an authority. * [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) provides a per-contract role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts within the same instance. * [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. [Core](https://docs.openzeppelin.com/contracts/5.x/api/access#core) -------------------------------------------------------------------- [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) [`Ownable2Step`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step) [`IAccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl) [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/access#extensions) -------------------------------------------------------------------------------- [`IAccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlEnumerable) [`AccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable) [`IAccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules) [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules) [AccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanager) -------------------------------------------------------------------------------------- [`IAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAuthority) [`IAccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager) [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) [`IAccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged) [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged) [`AuthorityUtils`](https://docs.openzeppelin.com/contracts/5.x/api/access#AuthorityUtils) [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol) ---------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/AccessControl.sol) import "@openzeppelin/contracts/access/AccessControl.sol"; Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see [`AccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable) . Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); Roles can be used to represent a set of permissions. To restrict access to a function call, use [`AccessControl.hasRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-hasRole-bytes32-address-) : function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } Roles can be granted and revoked dynamically via the [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) functions. Each role has an associated admin role, and only accounts that have a role's admin role can call [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) . 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 [`AccessControl._setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) . 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. We recommend using [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules) to enforce additional security measures for this role. ### Modifiers * [onlyRole(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-onlyRole-bytes32-) ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-supportsInterface-bytes4-) * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-hasRole-bytes32-address-) * [\_checkRole(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-) * [\_checkRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) * [renounceRole(role, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-renounceRole-bytes32-address-) * [\_setRoleAdmin(role, adminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) * [\_grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_grantRole-bytes32-address-) * [\_revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_revokeRole-bytes32-address-) * [DEFAULT\_ADMIN\_ROLE()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-DEFAULT_ADMIN_ROLE-bytes32) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc) ### Events #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-1) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-1) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-1) * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-2) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-2) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-2) * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) onlyRole(bytes32 role) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-onlyRole-bytes32-) Modifier that checks that an account has a specific role. Reverts with an [`IAccessControl.AccessControlUnauthorizedAccount`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) error including the required role. supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-supportsInterface-bytes4-) hasRole(bytes32 role, address account) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-hasRole-bytes32-address-) Returns `true` if `account` has been granted `role`. \_checkRole(bytes32 role) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-_checkRole-bytes32-) Reverts with an [`IAccessControl.AccessControlUnauthorizedAccount`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) error if `_msgSender()` is missing `role`. Overriding this function changes the behavior of the [`AccessControl.onlyRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-onlyRole-bytes32-) modifier. \_checkRole(bytes32 role, address account) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-_checkRole-bytes32-address-) Reverts with an [`IAccessControl.AccessControlUnauthorizedAccount`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) error if `account` is missing `role`. getRoleAdmin(bytes32 role) → bytes32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-getRoleAdmin-bytes32-) Returns the admin role that controls `role`. See [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) . To change a role's admin, use [`AccessControl._setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) . grantRole(bytes32 role, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-grantRole-bytes32-address-) Grants `role` to `account`. If `account` had not been already granted `role`, emits a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. Requirements: * the caller must have `role`'s admin role. May emit a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. revokeRole(bytes32 role, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-revokeRole-bytes32-address-) Revokes `role` from `account`. If `account` had been granted `role`, emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. Requirements: * the caller must have `role`'s admin role. May emit a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. renounceRole(bytes32 role, address callerConfirmation) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-renounceRole-bytes32-address-) Revokes `role` from the calling account. Roles are often managed via [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) : 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 [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. Requirements: * the caller must be `callerConfirmation`. May emit a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. \_setRoleAdmin(bytes32 role, bytes32 adminRole) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-_setRoleAdmin-bytes32-bytes32-) Sets `adminRole` as `role`'s admin role. Emits a [`IAccessControl.RoleAdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) event. \_grantRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-_grantRole-bytes32-address-) Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. Internal function without access restriction. May emit a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. \_revokeRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-_revokeRole-bytes32-address-) Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked. Internal function without access restriction. May emit a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. DEFAULT\_ADMIN\_ROLE() → bytes32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControl-DEFAULT_ADMIN_ROLE-bytes32) [`IAccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/IAccessControl.sol) import "@openzeppelin/contracts/access/IAccessControl.sol"; External interface of AccessControl declared to support ERC-165 detection. ### Functions * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-hasRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-getRoleAdmin-bytes32-) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-revokeRole-bytes32-address-) * [renounceRole(role, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-renounceRole-bytes32-address-) ### Events * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) hasRole(bytes32 role, address account) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-hasRole-bytes32-address-) Returns `true` if `account` has been granted `role`. getRoleAdmin(bytes32 role) → bytes32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-getRoleAdmin-bytes32-) Returns the admin role that controls `role`. See [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) . To change a role's admin, use [`AccessControl._setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) . grantRole(bytes32 role, address account) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-grantRole-bytes32-address-) Grants `role` to `account`. If `account` had not been already granted `role`, emits a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. Requirements: * the caller must have `role`'s admin role. revokeRole(bytes32 role, address account) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-revokeRole-bytes32-address-) Revokes `role` from `account`. If `account` had been granted `role`, emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. Requirements: * the caller must have `role`'s admin role. renounceRole(bytes32 role, address callerConfirmation) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-renounceRole-bytes32-address-) Revokes `role` from the calling account. Roles are often managed via [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) : 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 [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. Requirements: * the caller must be `callerConfirmation`. RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) Emitted when `newAdminRole` is set as `role`'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite [`IAccessControl.RoleAdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) not being emitted to signal this. RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-RoleGranted-bytes32-address-address-) Emitted when `account` is granted `role`. `sender` is the account that originated the contract call. This account bears the admin role (for the granted role). Expected in cases where the role was granted using the internal [`AccessControl._grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_grantRole-bytes32-address-) . RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-RoleRevoked-bytes32-address-address-) Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: * if using `revokeRole`, it is the admin role bearer * if using `renounceRole`, it is the role bearer (i.e. `account`) AccessControlUnauthorizedAccount(address account, bytes32 neededRole) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) The `account` is missing a role. AccessControlBadConfirmation() error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControl-AccessControlBadConfirmation--) The caller of a function is not the expected one. Don't confuse with [`IAccessControl.AccessControlUnauthorizedAccount`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) . [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable) ---------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/Ownable.sol) import "@openzeppelin/contracts/access/Ownable.sol"; Contract module which provides a basic access control mechanism, where there is an account (an owner) that can be granted exclusive access to specific functions. The initial owner is set to the address provided by the deployer. This can later be changed with [`Ownable.transferOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) . This module is used through inheritance. It will make available the modifier `onlyOwner`, which can be applied to your functions to restrict their use to the owner. ### Modifiers * [onlyOwner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-onlyOwner--) ### Functions * [constructor(initialOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-constructor-address-) * [owner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-owner--) * [\_checkOwner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-_checkOwner--) * [renounceOwnership()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-renounceOwnership--) * [transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) * [\_transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-_transferOwnership-address-) ### Events * [OwnershipTransferred(previousOwner, newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnershipTransferred-address-address-) ### Errors * [OwnableUnauthorizedAccount(account)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnableUnauthorizedAccount-address-) * [OwnableInvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnableInvalidOwner-address-) onlyOwner() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-onlyOwner--) Throws if called by any account other than the owner. constructor(address initialOwner) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-constructor-address-) Initializes the contract setting the address provided by the deployer as the initial owner. owner() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-owner--) Returns the address of the current owner. \_checkOwner() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-_checkOwner--) Throws if the sender is not the owner. renounceOwnership() public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-renounceOwnership--) Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner. transferOwnership(address newOwner) public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-transferOwnership-address-) Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner. \_transferOwnership(address newOwner) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-_transferOwnership-address-) Transfers ownership of the contract to a new account (`newOwner`). Internal function without access restriction. OwnershipTransferred(address indexed previousOwner, address indexed newOwner) event [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-OwnershipTransferred-address-address-) OwnableUnauthorizedAccount(address account) error [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-OwnableUnauthorizedAccount-address-) The caller account is not authorized to perform an operation. OwnableInvalidOwner(address owner) error [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable-OwnableInvalidOwner-address-) The owner is not a valid owner account. (eg. `address(0)`) [`Ownable2Step`](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable2step) -------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/Ownable2Step.sol) import "@openzeppelin/contracts/access/Ownable2Step.sol"; Contract module which provides access control mechanism, where there is an account (an owner) that can be granted exclusive access to specific functions. This extension of the [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) contract includes a two-step mechanism to transfer ownership, where the new owner must call [`Ownable2Step.acceptOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-acceptOwnership--) in order to replace the old one. This can help prevent common mistakes, such as transfers of ownership to incorrect accounts, or to contracts that are unable to interact with the permission system. The initial owner is specified at deployment time in the constructor for `Ownable`. This can later be changed with [`Ownable.transferOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) and [`Ownable2Step.acceptOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-acceptOwnership--) . This module is used through inheritance. It will make available all functions from parent (Ownable). ### Functions * [pendingOwner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-pendingOwner--) * [transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-transferOwnership-address-) * [\_transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-_transferOwnership-address-) * [acceptOwnership()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-acceptOwnership--) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable-toc) * [owner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-owner--) * [\_checkOwner()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-_checkOwner--) * [renounceOwnership()](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-renounceOwnership--) ### Events * [OwnershipTransferStarted(previousOwner, newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable2Step-OwnershipTransferStarted-address-address-) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable-toc-1) * [OwnershipTransferred(previousOwner, newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnershipTransferred-address-address-) ### Errors #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable-toc-2) * [OwnableUnauthorizedAccount(account)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnableUnauthorizedAccount-address-) * [OwnableInvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-OwnableInvalidOwner-address-) pendingOwner() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable2Step-pendingOwner--) Returns the address of the pending owner. transferOwnership(address newOwner) public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable2Step-transferOwnership-address-) Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner. Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer. \_transferOwnership(address newOwner) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable2Step-_transferOwnership-address-) Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. Internal function without access restriction. acceptOwnership() public [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable2Step-acceptOwnership--) The new owner accepts the ownership transfer. OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner) event [#](https://docs.openzeppelin.com/contracts/5.x/api/Ownable2Step-OwnershipTransferStarted-address-address-) [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontroldefaultadminrules) -------------------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/extensions/AccessControlDefaultAdminRules.sol) import "@openzeppelin/contracts/access/extensions/AccessControlDefaultAdminRules.sol"; Extension of [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) that allows specifying special rules to manage the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions over other roles that may potentially have privileged rights in the system. If a specific role doesn't have an admin role assigned, the holder of the `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it. This contract implements the following risk mitigations on top of [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) : * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced. * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account. * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted. * The delay can be changed by scheduling, see [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) . * Role transfers must wait at least one block after scheduling before it can be accepted. * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`. Example usage: contract MyToken is AccessControlDefaultAdminRules { constructor() AccessControlDefaultAdminRules( 3 days, msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder ) {} } ### Functions * [constructor(initialDelay, initialDefaultAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-constructor-uint48-address-) * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-supportsInterface-bytes4-) * [owner()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-owner--) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-revokeRole-bytes32-address-) * [renounceRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-renounceRole-bytes32-address-) * [\_grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_grantRole-bytes32-address-) * [\_revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_revokeRole-bytes32-address-) * [\_setRoleAdmin(role, adminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_setRoleAdmin-bytes32-bytes32-) * [defaultAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) * [pendingDefaultAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) * [defaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) * [pendingDefaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) * [defaultAdminDelayIncreaseWait()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) * [beginDefaultAdminTransfer(newAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) * [\_beginDefaultAdminTransfer(newAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_beginDefaultAdminTransfer-address-) * [cancelDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-cancelDefaultAdminTransfer--) * [\_cancelDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_cancelDefaultAdminTransfer--) * [acceptDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) * [\_acceptDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_acceptDefaultAdminTransfer--) * [changeDefaultAdminDelay(newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) * [\_changeDefaultAdminDelay(newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_changeDefaultAdminDelay-uint48-) * [rollbackDefaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-rollbackDefaultAdminDelay--) * [\_rollbackDefaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_rollbackDefaultAdminDelay--) * [\_delayChangeWait(newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-_delayChangeWait-uint48-) #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc) * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-hasRole-bytes32-address-) * [\_checkRole(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-) * [\_checkRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) * [DEFAULT\_ADMIN\_ROLE()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-DEFAULT_ADMIN_ROLE-bytes32) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-3) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-3) #### [IERC5313](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc5313-toc) #### [IAccessControlDefaultAdminRules](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontroldefaultadminrules-toc) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-3) ### Events #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc-1) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-4) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-4) #### [IERC5313](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc5313-toc-1) #### [IAccessControlDefaultAdminRules](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontroldefaultadminrules-toc-1) * [DefaultAdminTransferScheduled(newAdmin, acceptSchedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminTransferScheduled-address-uint48-) * [DefaultAdminTransferCanceled()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminTransferCanceled--) * [DefaultAdminDelayChangeScheduled(newDelay, effectSchedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminDelayChangeScheduled-uint48-uint48-) * [DefaultAdminDelayChangeCanceled()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminDelayChangeCanceled--) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-4) * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc-2) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-5) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-5) #### [IERC5313](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc5313-toc-2) #### [IAccessControlDefaultAdminRules](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontroldefaultadminrules-toc-2) * [AccessControlInvalidDefaultAdmin(defaultAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlInvalidDefaultAdmin-address-) * [AccessControlEnforcedDefaultAdminRules()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminRules--) * [AccessControlEnforcedDefaultAdminDelay(schedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminDelay-uint48-) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-5) * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) constructor(uint48 initialDelay, address initialDefaultAdmin) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-constructor-uint48-address-) Sets the initial values for [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) and [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) address. supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-supportsInterface-bytes4-) owner() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-owner--) Gets the address of the owner. grantRole(bytes32 role, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-grantRole-bytes32-address-) See [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) . Reverts for `DEFAULT_ADMIN_ROLE`. revokeRole(bytes32 role, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-revokeRole-bytes32-address-) See [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) . Reverts for `DEFAULT_ADMIN_ROLE`. renounceRole(bytes32 role, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-renounceRole-bytes32-address-) See [`AccessControl.renounceRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-renounceRole-bytes32-address-) . For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) to the `address(0)`, so it's required that the [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) schedule has also passed when calling this function. After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions. Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) , thereby disabling any functionality that is only available for it, and the possibility of reassigning a non-administrated role. \_grantRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_grantRole-bytes32-address-) See [`AccessControl._grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_grantRole-bytes32-address-) . For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) or if the role has been previously renounced. Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE` assignable again. Make sure to guarantee this is the expected behavior in your implementation. \_revokeRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_revokeRole-bytes32-address-) Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked. Internal function without access restriction. May emit a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event. \_setRoleAdmin(bytes32 role, bytes32 adminRole) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_setRoleAdmin-bytes32-bytes32-) See [`AccessControl._setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) . Reverts for `DEFAULT_ADMIN_ROLE`. defaultAdmin() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-defaultAdmin--) Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. pendingDefaultAdmin() → address newAdmin, uint48 schedule public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-pendingDefaultAdmin--) Returns a tuple of a `newAdmin` and an accept schedule. After the `schedule` passes, the `newAdmin` will be able to accept the [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) role by calling [`AccessControlDefaultAdminRules.acceptDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) , completing the role transfer. A zero value only in `acceptSchedule` indicates no pending admin transfer. A zero address `newAdmin` means that [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) is being renounced. defaultAdminDelay() → uint48 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-defaultAdminDelay--) Returns the delay required to schedule the acceptance of a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer started. This delay will be added to the current timestamp when calling [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) to set the acceptance schedule. If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this function returns the new delay. See [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) . pendingDefaultAdminDelay() → uint48 newDelay, uint48 schedule public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) Returns a tuple of `newDelay` and an effect schedule. After the `schedule` passes, the `newDelay` will get into effect immediately for every new [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . A zero value only in `effectSchedule` indicates no pending delay change. A zero value only for `newDelay` means that the next [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) will be zero after the effect schedule. defaultAdminDelayIncreaseWait() → uint48 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) Maximum time in seconds for an increase to [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) (that is scheduled using [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) ) to take effect. Default to 5 days. When the [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) is scheduled to be increased, it goes into effect after the new delay has passed with the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds) that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can be overrode for a custom [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) increase scheduling. Make sure to add a reasonable amount of time while overriding this value, otherwise, there's a risk of setting a high new delay that goes into effect almost immediately without the possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds). beginDefaultAdminTransfer(address newAdmin) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) Starts a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer by setting a [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) scheduled for acceptance after the current timestamp plus a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) . Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . Emits a DefaultAdminRoleChangeStarted event. \_beginDefaultAdminTransfer(address newAdmin) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_beginDefaultAdminTransfer-address-) See [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . Internal function without access restriction. cancelDefaultAdminTransfer() public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-cancelDefaultAdminTransfer--) Cancels a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer previously started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . A [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) not yet accepted can also be cancelled with this function. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . May emit a DefaultAdminTransferCanceled event. \_cancelDefaultAdminTransfer() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_cancelDefaultAdminTransfer--) See [`AccessControlDefaultAdminRules.cancelDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-cancelDefaultAdminTransfer--) . Internal function without access restriction. acceptDefaultAdminTransfer() public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) Completes a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer previously started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . After calling the function: * `DEFAULT_ADMIN_ROLE` should be granted to the caller. * `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. * [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) should be reset to zero values. Requirements: * Only can be called by the [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) 's `newAdmin`. * The [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) 's `acceptSchedule` should've passed. \_acceptDefaultAdminTransfer() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_acceptDefaultAdminTransfer--) See [`AccessControlDefaultAdminRules.acceptDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) . Internal function without access restriction. changeDefaultAdminDelay(uint48 newDelay) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) Initiates a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) update by setting a [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) scheduled for getting into effect after the current timestamp plus a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) . This function guarantees that any call to [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) done between the timestamp this method is called and the [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) effect schedule will use the current [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) set before calling. The [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) 's effect schedule is defined in a way that waiting until the schedule and then calling [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) with the new delay will take at least the same as another [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) complete transfer (including acceptance). The schedule is designed for two scenarios: * When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by [`AccessControlDefaultAdminRules.defaultAdminDelayIncreaseWait`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) . * When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`. A [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) that never got into effect will be canceled in favor of a new scheduled change. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. \_changeDefaultAdminDelay(uint48 newDelay) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_changeDefaultAdminDelay-uint48-) See [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) . Internal function without access restriction. rollbackDefaultAdminDelay() public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-rollbackDefaultAdminDelay--) Cancels a scheduled [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) change. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . May emit a DefaultAdminDelayChangeCanceled event. \_rollbackDefaultAdminDelay() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_rollbackDefaultAdminDelay--) See [`AccessControlDefaultAdminRules.rollbackDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-rollbackDefaultAdminDelay--) . Internal function without access restriction. \_delayChangeWait(uint48 newDelay) → uint48 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlDefaultAdminRules-_delayChangeWait-uint48-) Returns the amount of seconds to wait after the `newDelay` will become the new [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) . The value returned guarantees that if the delay is reduced, it will go into effect after a wait that honors the previously set delay. See [`AccessControlDefaultAdminRules.defaultAdminDelayIncreaseWait`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) . [`AccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrolenumerable) ------------------------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/extensions/AccessControlEnumerable.sol) import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; Extension of [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) that allows enumerating the members of each role. ### Functions * [supportsInterface(interfaceId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-supportsInterface-bytes4-) * [getRoleMember(role, index)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMember-bytes32-uint256-) * [getRoleMemberCount(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMemberCount-bytes32-) * [getRoleMembers(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMembers-bytes32-) * [\_grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-_grantRole-bytes32-address-) * [\_revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-_revokeRole-bytes32-address-) #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc-3) * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-hasRole-bytes32-address-) * [\_checkRole(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-) * [\_checkRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_checkRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) * [renounceRole(role, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-renounceRole-bytes32-address-) * [\_setRoleAdmin(role, adminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_setRoleAdmin-bytes32-bytes32-) * [DEFAULT\_ADMIN\_ROLE()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-DEFAULT_ADMIN_ROLE-bytes32) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-6) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-6) #### [IAccessControlEnumerable](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrolenumerable-toc) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-6) ### Events #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc-4) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-7) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-7) #### [IAccessControlEnumerable](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrolenumerable-toc-1) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-7) * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors #### [AccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol-toc-5) #### [ERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#erc165-toc-8) #### [IERC165](https://docs.openzeppelin.com/contracts/5.x/api/access#ierc165-toc-8) #### [IAccessControlEnumerable](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrolenumerable-toc-2) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-8) * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) supportsInterface(bytes4 interfaceId) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-supportsInterface-bytes4-) getRoleMember(bytes32 role, uint256 index) → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-getRoleMember-bytes32-uint256-) Returns one of the accounts that have `role`. `index` must be a value between 0 and [`AccessControlEnumerable.getRoleMemberCount`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMemberCount-bytes32-) , non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. When using [`AccessControlEnumerable.getRoleMember`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMember-bytes32-uint256-) and [`AccessControlEnumerable.getRoleMemberCount`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMemberCount-bytes32-) , make sure you perform all queries on the same block. See the following [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296) for more information. getRoleMemberCount(bytes32 role) → uint256 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-getRoleMemberCount-bytes32-) Returns the number of accounts that have `role`. Can be used together with [`AccessControlEnumerable.getRoleMember`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMember-bytes32-uint256-) to enumerate all bearers of a role. getRoleMembers(bytes32 role) → address\[\] public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-getRoleMembers-bytes32-) Return all accounts that have `role` 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. \_grantRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-_grantRole-bytes32-address-) Overload [`AccessControl._grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_grantRole-bytes32-address-) to track enumerable memberships \_revokeRole(bytes32 role, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessControlEnumerable-_revokeRole-bytes32-address-) Overload [`AccessControl._revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-_revokeRole-bytes32-address-) to track enumerable memberships [`IAccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontroldefaultadminrules) ---------------------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/extensions/IAccessControlDefaultAdminRules.sol) import "@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol"; External interface of AccessControlDefaultAdminRules declared to support ERC-165 detection. ### Functions * [defaultAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-defaultAdmin--) * [pendingDefaultAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-pendingDefaultAdmin--) * [defaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-defaultAdminDelay--) * [pendingDefaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-pendingDefaultAdminDelay--) * [beginDefaultAdminTransfer(newAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) * [cancelDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-cancelDefaultAdminTransfer--) * [acceptDefaultAdminTransfer()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) * [changeDefaultAdminDelay(newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) * [rollbackDefaultAdminDelay()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-rollbackDefaultAdminDelay--) * [defaultAdminDelayIncreaseWait()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-9) * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-hasRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-getRoleAdmin-bytes32-) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-revokeRole-bytes32-address-) * [renounceRole(role, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-renounceRole-bytes32-address-) ### Events * [DefaultAdminTransferScheduled(newAdmin, acceptSchedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminTransferScheduled-address-uint48-) * [DefaultAdminTransferCanceled()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminTransferCanceled--) * [DefaultAdminDelayChangeScheduled(newDelay, effectSchedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminDelayChangeScheduled-uint48-uint48-) * [DefaultAdminDelayChangeCanceled()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-DefaultAdminDelayChangeCanceled--) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-10) * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors * [AccessControlInvalidDefaultAdmin(defaultAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlInvalidDefaultAdmin-address-) * [AccessControlEnforcedDefaultAdminRules()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminRules--) * [AccessControlEnforcedDefaultAdminDelay(schedule)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminDelay-uint48-) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-11) * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) defaultAdmin() → address external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-defaultAdmin--) Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. pendingDefaultAdmin() → address newAdmin, uint48 acceptSchedule external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-pendingDefaultAdmin--) Returns a tuple of a `newAdmin` and an accept schedule. After the `schedule` passes, the `newAdmin` will be able to accept the [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) role by calling [`AccessControlDefaultAdminRules.acceptDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) , completing the role transfer. A zero value only in `acceptSchedule` indicates no pending admin transfer. A zero address `newAdmin` means that [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) is being renounced. defaultAdminDelay() → uint48 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-defaultAdminDelay--) Returns the delay required to schedule the acceptance of a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer started. This delay will be added to the current timestamp when calling [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) to set the acceptance schedule. If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this function returns the new delay. See [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) . pendingDefaultAdminDelay() → uint48 newDelay, uint48 effectSchedule external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-pendingDefaultAdminDelay--) Returns a tuple of `newDelay` and an effect schedule. After the `schedule` passes, the `newDelay` will get into effect immediately for every new [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . A zero value only in `effectSchedule` indicates no pending delay change. A zero value only for `newDelay` means that the next [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) will be zero after the effect schedule. beginDefaultAdminTransfer(address newAdmin) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) Starts a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer by setting a [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) scheduled for acceptance after the current timestamp plus a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) . Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . Emits a DefaultAdminRoleChangeStarted event. cancelDefaultAdminTransfer() external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-cancelDefaultAdminTransfer--) Cancels a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer previously started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . A [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) not yet accepted can also be cancelled with this function. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . May emit a DefaultAdminTransferCanceled event. acceptDefaultAdminTransfer() external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) Completes a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer previously started with [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) . After calling the function: * `DEFAULT_ADMIN_ROLE` should be granted to the caller. * `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. * [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) should be reset to zero values. Requirements: * Only can be called by the [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) 's `newAdmin`. * The [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) 's `acceptSchedule` should've passed. changeDefaultAdminDelay(uint48 newDelay) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) Initiates a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) update by setting a [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) scheduled for getting into effect after the current timestamp plus a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) . This function guarantees that any call to [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) done between the timestamp this method is called and the [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) effect schedule will use the current [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) set before calling. The [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) 's effect schedule is defined in a way that waiting until the schedule and then calling [`AccessControlDefaultAdminRules.beginDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-beginDefaultAdminTransfer-address-) with the new delay will take at least the same as another [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) complete transfer (including acceptance). The schedule is designed for two scenarios: * When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by [`AccessControlDefaultAdminRules.defaultAdminDelayIncreaseWait`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) . * When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`. A [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) that never got into effect will be canceled in favor of a new scheduled change. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. rollbackDefaultAdminDelay() external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-rollbackDefaultAdminDelay--) Cancels a scheduled [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) change. Requirements: * Only can be called by the current [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) . May emit a DefaultAdminDelayChangeCanceled event. defaultAdminDelayIncreaseWait() → uint48 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-defaultAdminDelayIncreaseWait--) Maximum time in seconds for an increase to [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) (that is scheduled using [`AccessControlDefaultAdminRules.changeDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-changeDefaultAdminDelay-uint48-) ) to take effect. Default to 5 days. When the [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) is scheduled to be increased, it goes into effect after the new delay has passed with the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds) that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can be overrode for a custom [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) increase scheduling. Make sure to add a reasonable amount of time while overriding this value, otherwise, there's a risk of setting a high new delay that goes into effect almost immediately without the possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds). DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-DefaultAdminTransferScheduled-address-uint48-) Emitted when a [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) transfer is started, setting `newAdmin` as the next address to become the [`AccessControlDefaultAdminRules.defaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdmin--) by calling [`AccessControlDefaultAdminRules.acceptDefaultAdminTransfer`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-acceptDefaultAdminTransfer--) only after `acceptSchedule` passes. DefaultAdminTransferCanceled() event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-DefaultAdminTransferCanceled--) Emitted when a [`AccessControlDefaultAdminRules.pendingDefaultAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdmin--) is reset if it was never accepted, regardless of its schedule. DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-DefaultAdminDelayChangeScheduled-uint48-uint48-) Emitted when a [`AccessControlDefaultAdminRules.defaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-defaultAdminDelay--) change is started, setting `newDelay` as the next delay to be applied between default admin transfer after `effectSchedule` has passed. DefaultAdminDelayChangeCanceled() event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-DefaultAdminDelayChangeCanceled--) Emitted when a [`AccessControlDefaultAdminRules.pendingDefaultAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules-pendingDefaultAdminDelay--) is reset if its schedule didn't pass. AccessControlInvalidDefaultAdmin(address defaultAdmin) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-AccessControlInvalidDefaultAdmin-address-) The new default admin is not a valid default admin. AccessControlEnforcedDefaultAdminRules() error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminRules--) At least one of the following rules was violated: * The `DEFAULT_ADMIN_ROLE` must only be managed by itself. * The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time. * Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps. AccessControlEnforcedDefaultAdminDelay(uint48 schedule) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlDefaultAdminRules-AccessControlEnforcedDefaultAdminDelay-uint48-) The delay for transferring the default admin delay is enforced and the operation must wait until `schedule`. `schedule` can be 0 indicating there's no transfer scheduled. [`IAccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrolenumerable) -------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/extensions/IAccessControlEnumerable.sol) import "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol"; External interface of AccessControlEnumerable declared to support ERC-165 detection. ### Functions * [getRoleMember(role, index)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlEnumerable-getRoleMember-bytes32-uint256-) * [getRoleMemberCount(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControlEnumerable-getRoleMemberCount-bytes32-) #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-12) * [hasRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-hasRole-bytes32-address-) * [getRoleAdmin(role)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-getRoleAdmin-bytes32-) * [grantRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-grantRole-bytes32-address-) * [revokeRole(role, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-revokeRole-bytes32-address-) * [renounceRole(role, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-renounceRole-bytes32-address-) ### Events #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-13) * [RoleAdminChanged(role, previousAdminRole, newAdminRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) * [RoleGranted(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) * [RoleRevoked(role, account, sender)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) ### Errors #### [IAccessControl](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol-toc-14) * [AccessControlUnauthorizedAccount(account, neededRole)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlUnauthorizedAccount-address-bytes32-) * [AccessControlBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-AccessControlBadConfirmation--) getRoleMember(bytes32 role, uint256 index) → address external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlEnumerable-getRoleMember-bytes32-uint256-) Returns one of the accounts that have `role`. `index` must be a value between 0 and [`AccessControlEnumerable.getRoleMemberCount`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMemberCount-bytes32-) , non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. When using [`AccessControlEnumerable.getRoleMember`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMember-bytes32-uint256-) and [`AccessControlEnumerable.getRoleMemberCount`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMemberCount-bytes32-) , make sure you perform all queries on the same block. See the following [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296) for more information. getRoleMemberCount(bytes32 role) → uint256 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessControlEnumerable-getRoleMemberCount-bytes32-) Returns the number of accounts that have `role`. Can be used together with [`AccessControlEnumerable.getRoleMember`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlEnumerable-getRoleMember-bytes32-uint256-) to enumerate all bearers of a role. [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanaged) ---------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/AccessManaged.sol) import "@openzeppelin/contracts/access/manager/AccessManaged.sol"; This contract module makes available a [`AccessManaged.restricted`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-restricted--) modifier. Functions decorated with this modifier will be permissioned according to an "authority": a contract like [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) that follows the [`IAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAuthority) interface, implementing a policy that allows certain callers to access certain functions. The `restricted` modifier should never be used on `internal` functions, judiciously used in `public` functions, and ideally only used in `external` functions. See [`AccessManaged.restricted`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-restricted--) . ### Modifiers * [restricted()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-restricted--) ### Functions * [constructor(initialAuthority)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-constructor-address-) * [authority()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-authority--) * [setAuthority(newAuthority)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-setAuthority-address-) * [isConsumingScheduledOp()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-isConsumingScheduledOp--) * [\_setAuthority(newAuthority)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-_setAuthority-address-) * [\_checkCanCall(caller, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-_checkCanCall-address-bytes-) #### [IAccessManaged](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanaged-toc) ### Events #### [IAccessManaged](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanaged-toc-1) * [AuthorityUpdated(authority)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AuthorityUpdated-address-) ### Errors #### [IAccessManaged](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanaged-toc-2) * [AccessManagedUnauthorized(caller)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedUnauthorized-address-) * [AccessManagedRequiredDelay(caller, delay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedRequiredDelay-address-uint32-) * [AccessManagedInvalidAuthority(authority)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedInvalidAuthority-address-) restricted() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-restricted--) Restricts access to a function as defined by the connected Authority for this contract and the caller and selector of the function that entered the contract. In general, this modifier should only be used on `external` functions. It is okay to use it on `public` functions that are used as external entry points and are not called internally. Unless you know what you're doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security implications! This is because the permissions are determined by the function that entered the contract, i.e. the function at the bottom of the call stack, and not the function where the modifier is visible in the source code. Avoid adding this modifier to the [`receive()`](https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function) function or the [`fallback()`](https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function) . These functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function if no calldata is provided. (See [`AccessManaged._checkCanCall`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-_checkCanCall-address-bytes-) ). The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length. constructor(address initialAuthority) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-constructor-address-) Initializes the contract connected to an initial authority. authority() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-authority--) Returns the current authority. setAuthority(address newAuthority) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-setAuthority-address-) Transfers control to a new authority. The caller must be the current authority. isConsumingScheduledOp() → bytes4 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-isConsumingScheduledOp--) Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs attacker controlled calls. \_setAuthority(address newAuthority) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-_setAuthority-address-) Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the permissions set by the current authority. \_checkCanCall(address caller, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManaged-_checkCanCall-address-bytes-) Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata is less than 4 bytes long. [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanager-1) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/AccessManager.sol) import "@openzeppelin/contracts/access/manager/AccessManager.sol"; AccessManager is a central contract to store the permissions of a system. A smart contract under the control of an AccessManager instance is known as a target, and will inherit from the [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged) contract, be connected to this contract as its manager and implement the [`AccessManaged.restricted`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-restricted--) modifier on a set of functions selected to be permissioned. Note that any function without this setup won't be effectively restricted. The restriction rules for such functions are defined in terms of "roles" identified by an `uint64` and scoped by target (`address`) and function selectors (`bytes4`). These roles are stored in this contract and can be configured by admins (`ADMIN_ROLE` members) after a delay (see [`AccessManager.getTargetAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getTargetAdminDelay-address-) ). For each target contract, admins can configure the following without any delay: * The target's [`AccessManaged.authority`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManaged-authority--) via [`AccessManager.updateAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-updateAuthority-address-address-) . * Close or open a target via [`AccessManager.setTargetClosed`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetClosed-address-bool-) keeping the permissions intact. * The roles that are allowed (or disallowed) to call a given function (identified by its selector) through [`AccessManager.setTargetFunctionRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetFunctionRole-address-bytes4---uint64-) . By default every address is member of the `PUBLIC_ROLE` and every target function is restricted to the `ADMIN_ROLE` until configured otherwise. Additionally, each role has the following configuration options restricted to this manager's admins: * A role's admin role via [`AccessManager.setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleAdmin-uint64-uint64-) who can grant or revoke roles. * A role's guardian role via [`AccessManager.setRoleGuardian`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleGuardian-uint64-uint64-) who's allowed to cancel operations. * A delay in which a role takes effect after being granted through [`AccessManager.setGrantDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) . * A delay of any target's admin action via [`AccessManager.setTargetAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetAdminDelay-address-uint32-) . * A role label for discoverability purposes with [`AccessManager.labelRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-labelRole-uint64-string-) . Any account can be added and removed into any number of these roles by using the [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) and [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) functions restricted to each role's admin (see [`AccessControl.getRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) ). Since all the permissions of the managed system can be modified by the admins of this instance, it is expected that they will be highly secured (e.g., a multisig or a well-configured DAO). This contract implements a form of the [`IAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAuthority) interface, but [`AccessManager.canCall`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-canCall-address-address-bytes4-) has additional return data so it doesn't inherit `IAuthority`. It is however compatible with the `IAuthority` interface since the first 32 bytes of the return data are a boolean as expected by that interface. Systems that implement other access control mechanisms (for example using [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) ) can be paired with an [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) by transferring permissions (ownership in the case of [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) ) directly to the [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) . Users will be able to interact with these contracts through the [`AccessManager.execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) function, following the access rules registered in the [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) . Keep in mind that in that context, the msg.sender seen by restricted functions will be [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) itself. When granting permissions over an [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) or [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) contract to an [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) , be very mindful of the danger associated with functions such as [`Ownable.renounceOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-renounceOwnership--) or [`AccessControl.renounceRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-renounceRole-bytes32-address-) . ### Modifiers * [onlyAuthorized()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-onlyAuthorized--) ### Functions * [constructor(initialAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-constructor-address-) * [canCall(caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-canCall-address-address-bytes4-) * [expiration()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-expiration--) * [minSetback()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-minSetback--) * [isTargetClosed(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-isTargetClosed-address-) * [getTargetFunctionRole(target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getTargetFunctionRole-address-bytes4-) * [getTargetAdminDelay(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getTargetAdminDelay-address-) * [getRoleAdmin(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getRoleAdmin-uint64-) * [getRoleGuardian(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getRoleGuardian-uint64-) * [getRoleGrantDelay(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getRoleGrantDelay-uint64-) * [getAccess(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getAccess-uint64-address-) * [hasRole(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-hasRole-uint64-address-) * [labelRole(roleId, label)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-labelRole-uint64-string-) * [grantRole(roleId, account, executionDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-grantRole-uint64-address-uint32-) * [revokeRole(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-revokeRole-uint64-address-) * [renounceRole(roleId, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-renounceRole-uint64-address-) * [setRoleAdmin(roleId, admin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleAdmin-uint64-uint64-) * [setRoleGuardian(roleId, guardian)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleGuardian-uint64-uint64-) * [setGrantDelay(roleId, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) * [\_grantRole(roleId, account, grantDelay, executionDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_grantRole-uint64-address-uint32-uint32-) * [\_revokeRole(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_revokeRole-uint64-address-) * [\_setRoleAdmin(roleId, admin)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setRoleAdmin-uint64-uint64-) * [\_setRoleGuardian(roleId, guardian)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setRoleGuardian-uint64-uint64-) * [\_setGrantDelay(roleId, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setGrantDelay-uint64-uint32-) * [setTargetFunctionRole(target, selectors, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetFunctionRole-address-bytes4---uint64-) * [\_setTargetFunctionRole(target, selector, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setTargetFunctionRole-address-bytes4-uint64-) * [setTargetAdminDelay(target, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetAdminDelay-address-uint32-) * [\_setTargetAdminDelay(target, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setTargetAdminDelay-address-uint32-) * [setTargetClosed(target, closed)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetClosed-address-bool-) * [\_setTargetClosed(target, closed)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_setTargetClosed-address-bool-) * [getSchedule(id)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getSchedule-bytes32-) * [getNonce(id)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getNonce-bytes32-) * [schedule(target, data, when)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-schedule-address-bytes-uint48-) * [execute(target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) * [cancel(caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-cancel-address-address-bytes-) * [consumeScheduledOp(caller, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-consumeScheduledOp-address-bytes-) * [\_consumeScheduledOp(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-_consumeScheduledOp-bytes32-) * [hashOperation(caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-hashOperation-address-address-bytes-) * [updateAuthority(target, newAuthority)](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-updateAuthority-address-address-) * [ADMIN\_ROLE()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-ADMIN_ROLE-uint64) * [PUBLIC\_ROLE()](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-PUBLIC_ROLE-uint64) #### [IAccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanager-toc) #### [Multicall](https://docs.openzeppelin.com/contracts/5.x/api/access#multicall-toc) * [multicall(data)](https://docs.openzeppelin.com/contracts/5.x/api/access#Multicall-multicall-bytes---) ### Events #### [IAccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanager-toc-1) * [OperationScheduled(operationId, nonce, schedule, caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationScheduled-bytes32-uint32-uint48-address-address-bytes-) * [OperationExecuted(operationId, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) * [OperationCanceled(operationId, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationCanceled-bytes32-uint32-) * [RoleLabel(roleId, label)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleLabel-uint64-string-) * [RoleGranted(roleId, account, delay, since, newMember)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGranted-uint64-address-uint32-uint48-bool-) * [RoleRevoked(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleRevoked-uint64-address-) * [RoleAdminChanged(roleId, admin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleAdminChanged-uint64-uint64-) * [RoleGuardianChanged(roleId, guardian)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGuardianChanged-uint64-uint64-) * [RoleGrantDelayChanged(roleId, delay, since)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) * [TargetClosed(target, closed)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetClosed-address-bool-) * [TargetFunctionRoleUpdated(target, selector, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) * [TargetAdminDelayUpdated(target, delay, since)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) #### [Multicall](https://docs.openzeppelin.com/contracts/5.x/api/access#multicall-toc-1) ### Errors #### [IAccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanager-toc-2) * [AccessManagerAlreadyScheduled(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerAlreadyScheduled-bytes32-) * [AccessManagerNotScheduled(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerNotScheduled-bytes32-) * [AccessManagerNotReady(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerNotReady-bytes32-) * [AccessManagerExpired(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerExpired-bytes32-) * [AccessManagerLockedRole(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerLockedRole-uint64-) * [AccessManagerBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerBadConfirmation--) * [AccessManagerUnauthorizedAccount(msgsender, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedAccount-address-uint64-) * [AccessManagerUnauthorizedCall(caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedCall-address-address-bytes4-) * [AccessManagerUnauthorizedConsume(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedConsume-address-) * [AccessManagerUnauthorizedCancel(msgsender, caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedCancel-address-address-address-bytes4-) * [AccessManagerInvalidInitialAdmin(initialAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerInvalidInitialAdmin-address-) #### [Multicall](https://docs.openzeppelin.com/contracts/5.x/api/access#multicall-toc-2) onlyAuthorized() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-onlyAuthorized--) Check that the caller is authorized to perform the operation. See [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) description for a detailed breakdown of the authorization logic. constructor(address initialAdmin) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-constructor-address-) canCall(address caller, address target, bytes4 selector) → bool immediate, uint32 delay public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-canCall-address-address-bytes4-) Check if an address (`caller`) is authorised to call a given function on a given contract directly (with no restriction). Additionally, it returns the delay needed to perform the call indirectly through the [`AccessManager.schedule`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-schedule-address-bytes-uint48-) & [`AccessManager.execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) workflow. This function is usually called by the targeted contract to control immediate execution of restricted functions. Therefore we only return true if the call can be performed without any delay. If the call is subject to a previously set delay (not zero), then the function should return false and the caller should schedule the operation for future execution. If `allowed` is true, the delay can be disregarded and the operation can be immediately executed, otherwise the operation can be executed if and only if delay is greater than 0. The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail to identify the indirect workflow, and will consider calls that require a delay to be forbidden. This function does not report the permissions of the admin functions in the manager itself. These are defined by the [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) documentation. expiration() → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-expiration--) Expiration delay for scheduled proposals. Defaults to 1 week. Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately, disabling any scheduling usage. minSetback() → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-minSetback--) Minimum setback for all delay updates, with the exception of execution delays. It can be increased without setback (and reset via [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) in the case event of an accidental increase). Defaults to 5 days. isTargetClosed(address target) → bool public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-isTargetClosed-address-) Get whether the contract is closed disabling any access. Otherwise role permissions are applied. When the manager itself is closed, admin functions are still accessible to avoid locking the contract. getTargetFunctionRole(address target, bytes4 selector) → uint64 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getTargetFunctionRole-address-bytes4-) Get the role required to call a function. getTargetAdminDelay(address target) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getTargetAdminDelay-address-) Get the admin delay for a target contract. Changes to contract configuration are subject to this delay. getRoleAdmin(uint64 roleId) → uint64 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getRoleAdmin-uint64-) Get the id of the role that acts as an admin for the given role. The admin permission is required to grant the role, revoke the role and update the execution delay to execute an operation that is restricted to this role. getRoleGuardian(uint64 roleId) → uint64 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getRoleGuardian-uint64-) Get the role that acts as a guardian for a given role. The guardian permission allows canceling operations that have been scheduled under the role. getRoleGrantDelay(uint64 roleId) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getRoleGrantDelay-uint64-) Get the role current grant delay. Its value may change at any point without an event emitted following a call to [`AccessManager.setGrantDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) . Changes to this value, including effect timepoint are notified in advance by the [`IAccessManager.RoleGrantDelayChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) event. getAccess(uint64 roleId, address account) → uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getAccess-uint64-address-) Get the access details for a given account for a given role. These details include the timepoint at which membership becomes active, and the delay applied to all operation by this user that requires this permission level. Returns: \[0\] Timestamp at which the account membership becomes valid. 0 means role is not granted. \[1\] Current execution delay for the account. \[2\] Pending execution delay for the account. \[3\] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled. hasRole(uint64 roleId, address account) → bool isMember, uint32 executionDelay public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-hasRole-uint64-address-) Check if a given account currently has the permission level corresponding to a given role. Note that this permission might be associated with an execution delay. [`AccessManager.getAccess`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getAccess-uint64-address-) can provide more details. labelRole(uint64 roleId, string label) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-labelRole-uint64-string-) Give a label to a role, for improved role discoverability by UIs. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleLabel`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleLabel-uint64-string-) event. grantRole(uint64 roleId, address account, uint32 executionDelay) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-grantRole-uint64-address-uint32-) Add `account` to `roleId`, or change its execution delay. This gives the account the authorization to call any function that is restricted to this role. An optional execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation that is restricted to members of this role. The user will only be able to execute the operation after the delay has passed, before it has expired. During this period, admin and guardians can cancel the operation (see [`AccessManager.cancel`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-cancel-address-address-bytes-) ). If the account has already been granted this role, the execution delay will be updated. This update is not immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any operation executed in the 3 hours that follows this update was indeed scheduled before this update. Requirements: * the caller must be an admin for the role (see [`AccessControl.getRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) ) * granted role must not be the `PUBLIC_ROLE` Emits a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. revokeRole(uint64 roleId, address account) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-revokeRole-uint64-address-) Remove an account from a role, with immediate effect. If the account does not have the role, this call has no effect. Requirements: * the caller must be an admin for the role (see [`AccessControl.getRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) ) * revoked role must not be the `PUBLIC_ROLE` Emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event if the account had the role. renounceRole(uint64 roleId, address callerConfirmation) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-renounceRole-uint64-address-) Renounce role permissions for the calling account with immediate effect. If the sender is not in the role this call has no effect. Requirements: * the caller must be `callerConfirmation`. Emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event if the account had the role. setRoleAdmin(uint64 roleId, uint64 admin) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setRoleAdmin-uint64-uint64-) Change admin role for a given role. Requirements: * the caller must be a global admin Emits a [`IAccessControl.RoleAdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) event setRoleGuardian(uint64 roleId, uint64 guardian) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setRoleGuardian-uint64-uint64-) Change guardian role for a given role. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleGuardianChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGuardianChanged-uint64-uint64-) event setGrantDelay(uint64 roleId, uint32 newDelay) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setGrantDelay-uint64-uint32-) Update the delay for granting a `roleId`. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleGrantDelayChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) event. \_grantRole(uint64 roleId, address account, uint32 grantDelay, uint32 executionDelay) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_grantRole-uint64-address-uint32-uint32-) Internal version of [`AccessControl.grantRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-grantRole-bytes32-address-) without access control. Returns true if the role was newly granted. Emits a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. \_revokeRole(uint64 roleId, address account) → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_revokeRole-uint64-address-) Internal version of [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) without access control. This logic is also used by [`AccessControl.renounceRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-renounceRole-bytes32-address-) . Returns true if the role was previously granted. Emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event if the account had the role. \_setRoleAdmin(uint64 roleId, uint64 admin) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setRoleAdmin-uint64-uint64-) Internal version of [`AccessManager.setRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleAdmin-uint64-uint64-) without access control. Emits a [`IAccessControl.RoleAdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) event. Setting the admin role as the `PUBLIC_ROLE` is allowed, but it will effectively allow anyone to set grant or revoke such role. \_setRoleGuardian(uint64 roleId, uint64 guardian) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setRoleGuardian-uint64-uint64-) Internal version of [`AccessManager.setRoleGuardian`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setRoleGuardian-uint64-uint64-) without access control. Emits a [`IAccessManager.RoleGuardianChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGuardianChanged-uint64-uint64-) event. Setting the guardian role as the `PUBLIC_ROLE` is allowed, but it will effectively allow anyone to cancel any scheduled operation for such role. \_setGrantDelay(uint64 roleId, uint32 newDelay) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setGrantDelay-uint64-uint32-) Internal version of [`AccessManager.setGrantDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) without access control. Emits a [`IAccessManager.RoleGrantDelayChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) event. setTargetFunctionRole(address target, bytes4\[\] selectors, uint64 roleId) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setTargetFunctionRole-address-bytes4---uint64-) Set the role required to call functions identified by the `selectors` in the `target` contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetFunctionRoleUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) event per selector. \_setTargetFunctionRole(address target, bytes4 selector, uint64 roleId) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setTargetFunctionRole-address-bytes4-uint64-) Internal version of [`AccessManager.setTargetFunctionRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetFunctionRole-address-bytes4---uint64-) without access control. Emits a [`IAccessManager.TargetFunctionRoleUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) event. setTargetAdminDelay(address target, uint32 newDelay) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setTargetAdminDelay-address-uint32-) Set the delay for changing the configuration of a given target contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetAdminDelayUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) event. \_setTargetAdminDelay(address target, uint32 newDelay) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setTargetAdminDelay-address-uint32-) Internal version of [`AccessManager.setTargetAdminDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setTargetAdminDelay-address-uint32-) without access control. Emits a [`IAccessManager.TargetAdminDelayUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) event. setTargetClosed(address target, bool closed) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-setTargetClosed-address-bool-) Set the closed flag for a contract. Closing the manager itself won't disable access to admin methods to avoid locking the contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetClosed`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetClosed-address-bool-) event. \_setTargetClosed(address target, bool closed) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_setTargetClosed-address-bool-) Set the closed flag for a contract. This is an internal setter with no access restrictions. Emits a [`IAccessManager.TargetClosed`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetClosed-address-bool-) event. getSchedule(bytes32 id) → uint48 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getSchedule-bytes32-) Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the operation is not yet scheduled, has expired, was executed, or was canceled. getNonce(bytes32 id) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-getNonce-bytes32-) Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never been scheduled. schedule(address target, bytes data, uint48 when) → bytes32 operationId, uint32 nonce public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-schedule-address-bytes-uint48-) Schedule a delayed operation for future execution, and return the operation identifier. It is possible to choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays required for the caller. The special value zero will automatically set the earliest possible time. Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this scheduled operation from other occurrences of the same `operationId` in invocations of [`AccessManager.execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) and [`AccessManager.cancel`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-cancel-address-address-bytes-) . Emits a [`IAccessManager.OperationScheduled`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationScheduled-bytes32-uint32-uint48-address-address-bytes-) event. It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target contract if it is using standard Solidity ABI encoding. execute(address target, bytes data) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-execute-address-bytes-) Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the execution delay is 0. Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the operation wasn't previously scheduled (if the caller doesn't have an execution delay). Emits an [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event only if the call was scheduled and delayed. cancel(address caller, address target, bytes data) → uint32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-cancel-address-address-bytes-) Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled operation that is cancelled. Requirements: * the caller must be the proposer, a guardian of the targeted function, or a global admin Emits a [`IAccessManager.OperationCanceled`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationCanceled-bytes32-uint32-) event. consumeScheduledOp(address caller, bytes data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-consumeScheduledOp-address-bytes-) Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed (emit an [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event and clean the state). Otherwise, throw an error. This is useful for contract that want to enforce that calls targeting them were scheduled on the manager, with all the verifications that it implies. Emit a [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event. \_consumeScheduledOp(bytes32 operationId) → uint32 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-_consumeScheduledOp-bytes32-) Internal variant of [`AccessManager.consumeScheduledOp`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-consumeScheduledOp-address-bytes-) that operates on bytes32 operationId. Returns the nonce of the scheduled operation that is consumed. hashOperation(address caller, address target, bytes data) → bytes32 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-hashOperation-address-address-bytes-) Hashing function for delayed operations. updateAuthority(address target, address newAuthority) public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-updateAuthority-address-address-) Changes the authority of a target managed by this manager instance. Requirements: * the caller must be a global admin ADMIN\_ROLE() → uint64 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-ADMIN_ROLE-uint64) The identifier of the admin role. Required to perform most configuration operations including other roles' management and target restrictions. PUBLIC\_ROLE() → uint64 public [#](https://docs.openzeppelin.com/contracts/5.x/api/AccessManager-PUBLIC_ROLE-uint64) The identifier of the public role. Automatically granted to all addresses with no delay. [`AuthorityUtils`](https://docs.openzeppelin.com/contracts/5.x/api/access#authorityutils) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/AuthorityUtils.sol) import "@openzeppelin/contracts/access/manager/AuthorityUtils.sol"; ### Functions * [canCallWithDelay(authority, caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#AuthorityUtils-canCallWithDelay-address-address-address-bytes4-) canCallWithDelay(address authority, address caller, address target, bytes4 selector) → bool immediate, uint32 delay internal [#](https://docs.openzeppelin.com/contracts/5.x/api/AuthorityUtils-canCallWithDelay-address-address-address-bytes4-) Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data. This helper function takes care of invoking `canCall` in a backwards compatible way without reverting. [`IAccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanaged) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/IAccessManaged.sol) import "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; ### Functions * [authority()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-authority--) * [setAuthority()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-setAuthority-address-) * [isConsumingScheduledOp()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-isConsumingScheduledOp--) ### Events * [AuthorityUpdated(authority)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AuthorityUpdated-address-) ### Errors * [AccessManagedUnauthorized(caller)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedUnauthorized-address-) * [AccessManagedRequiredDelay(caller, delay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedRequiredDelay-address-uint32-) * [AccessManagedInvalidAuthority(authority)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManaged-AccessManagedInvalidAuthority-address-) authority() → address external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-authority--) Returns the current authority. setAuthority(address) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-setAuthority-address-) Transfers control to a new authority. The caller must be the current authority. isConsumingScheduledOp() → bytes4 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-isConsumingScheduledOp--) Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs attacker controlled calls. AuthorityUpdated(address authority) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-AuthorityUpdated-address-) Authority that manages this contract was updated. AccessManagedUnauthorized(address caller) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-AccessManagedUnauthorized-address-) AccessManagedRequiredDelay(address caller, uint32 delay) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-AccessManagedRequiredDelay-address-uint32-) AccessManagedInvalidAuthority(address authority) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManaged-AccessManagedInvalidAuthority-address-) [`IAccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanager) ------------------------------------------------------------------------------------------ [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/IAccessManager.sol) import "@openzeppelin/contracts/access/manager/IAccessManager.sol"; ### Functions * [canCall(caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-canCall-address-address-bytes4-) * [expiration()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-expiration--) * [minSetback()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-minSetback--) * [isTargetClosed(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-isTargetClosed-address-) * [getTargetFunctionRole(target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getTargetFunctionRole-address-bytes4-) * [getTargetAdminDelay(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getTargetAdminDelay-address-) * [getRoleAdmin(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getRoleAdmin-uint64-) * [getRoleGuardian(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getRoleGuardian-uint64-) * [getRoleGrantDelay(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getRoleGrantDelay-uint64-) * [getAccess(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getAccess-uint64-address-) * [hasRole(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-hasRole-uint64-address-) * [labelRole(roleId, label)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-labelRole-uint64-string-) * [grantRole(roleId, account, executionDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-grantRole-uint64-address-uint32-) * [revokeRole(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-revokeRole-uint64-address-) * [renounceRole(roleId, callerConfirmation)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-renounceRole-uint64-address-) * [setRoleAdmin(roleId, admin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setRoleAdmin-uint64-uint64-) * [setRoleGuardian(roleId, guardian)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setRoleGuardian-uint64-uint64-) * [setGrantDelay(roleId, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setGrantDelay-uint64-uint32-) * [setTargetFunctionRole(target, selectors, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setTargetFunctionRole-address-bytes4---uint64-) * [setTargetAdminDelay(target, newDelay)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setTargetAdminDelay-address-uint32-) * [setTargetClosed(target, closed)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-setTargetClosed-address-bool-) * [getSchedule(id)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getSchedule-bytes32-) * [getNonce(id)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-getNonce-bytes32-) * [schedule(target, data, when)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-schedule-address-bytes-uint48-) * [execute(target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-execute-address-bytes-) * [cancel(caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-cancel-address-address-bytes-) * [consumeScheduledOp(caller, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-consumeScheduledOp-address-bytes-) * [hashOperation(caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-hashOperation-address-address-bytes-) * [updateAuthority(target, newAuthority)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-updateAuthority-address-address-) ### Events * [OperationScheduled(operationId, nonce, schedule, caller, target, data)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationScheduled-bytes32-uint32-uint48-address-address-bytes-) * [OperationExecuted(operationId, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) * [OperationCanceled(operationId, nonce)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationCanceled-bytes32-uint32-) * [RoleLabel(roleId, label)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleLabel-uint64-string-) * [RoleGranted(roleId, account, delay, since, newMember)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGranted-uint64-address-uint32-uint48-bool-) * [RoleRevoked(roleId, account)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleRevoked-uint64-address-) * [RoleAdminChanged(roleId, admin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleAdminChanged-uint64-uint64-) * [RoleGuardianChanged(roleId, guardian)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGuardianChanged-uint64-uint64-) * [RoleGrantDelayChanged(roleId, delay, since)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) * [TargetClosed(target, closed)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetClosed-address-bool-) * [TargetFunctionRoleUpdated(target, selector, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) * [TargetAdminDelayUpdated(target, delay, since)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) ### Errors * [AccessManagerAlreadyScheduled(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerAlreadyScheduled-bytes32-) * [AccessManagerNotScheduled(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerNotScheduled-bytes32-) * [AccessManagerNotReady(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerNotReady-bytes32-) * [AccessManagerExpired(operationId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerExpired-bytes32-) * [AccessManagerLockedRole(roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerLockedRole-uint64-) * [AccessManagerBadConfirmation()](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerBadConfirmation--) * [AccessManagerUnauthorizedAccount(msgsender, roleId)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedAccount-address-uint64-) * [AccessManagerUnauthorizedCall(caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedCall-address-address-bytes4-) * [AccessManagerUnauthorizedConsume(target)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedConsume-address-) * [AccessManagerUnauthorizedCancel(msgsender, caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerUnauthorizedCancel-address-address-address-bytes4-) * [AccessManagerInvalidInitialAdmin(initialAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-AccessManagerInvalidInitialAdmin-address-) canCall(address caller, address target, bytes4 selector) → bool allowed, uint32 delay external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-canCall-address-address-bytes4-) Check if an address (`caller`) is authorised to call a given function on a given contract directly (with no restriction). Additionally, it returns the delay needed to perform the call indirectly through the [`AccessManager.schedule`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-schedule-address-bytes-uint48-) & [`AccessManager.execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) workflow. This function is usually called by the targeted contract to control immediate execution of restricted functions. Therefore we only return true if the call can be performed without any delay. If the call is subject to a previously set delay (not zero), then the function should return false and the caller should schedule the operation for future execution. If `allowed` is true, the delay can be disregarded and the operation can be immediately executed, otherwise the operation can be executed if and only if delay is greater than 0. The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail to identify the indirect workflow, and will consider calls that require a delay to be forbidden. This function does not report the permissions of the admin functions in the manager itself. These are defined by the [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager) documentation. expiration() → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-expiration--) Expiration delay for scheduled proposals. Defaults to 1 week. Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately, disabling any scheduling usage. minSetback() → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-minSetback--) Minimum setback for all delay updates, with the exception of execution delays. It can be increased without setback (and reset via [`AccessControl.revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) in the case event of an accidental increase). Defaults to 5 days. isTargetClosed(address target) → bool external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-isTargetClosed-address-) Get whether the contract is closed disabling any access. Otherwise role permissions are applied. When the manager itself is closed, admin functions are still accessible to avoid locking the contract. getTargetFunctionRole(address target, bytes4 selector) → uint64 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getTargetFunctionRole-address-bytes4-) Get the role required to call a function. getTargetAdminDelay(address target) → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getTargetAdminDelay-address-) Get the admin delay for a target contract. Changes to contract configuration are subject to this delay. getRoleAdmin(uint64 roleId) → uint64 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getRoleAdmin-uint64-) Get the id of the role that acts as an admin for the given role. The admin permission is required to grant the role, revoke the role and update the execution delay to execute an operation that is restricted to this role. getRoleGuardian(uint64 roleId) → uint64 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getRoleGuardian-uint64-) Get the role that acts as a guardian for a given role. The guardian permission allows canceling operations that have been scheduled under the role. getRoleGrantDelay(uint64 roleId) → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getRoleGrantDelay-uint64-) Get the role current grant delay. Its value may change at any point without an event emitted following a call to [`AccessManager.setGrantDelay`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-setGrantDelay-uint64-uint32-) . Changes to this value, including effect timepoint are notified in advance by the [`IAccessManager.RoleGrantDelayChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) event. getAccess(uint64 roleId, address account) → uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getAccess-uint64-address-) Get the access details for a given account for a given role. These details include the timepoint at which membership becomes active, and the delay applied to all operation by this user that requires this permission level. Returns: \[0\] Timestamp at which the account membership becomes valid. 0 means role is not granted. \[1\] Current execution delay for the account. \[2\] Pending execution delay for the account. \[3\] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled. hasRole(uint64 roleId, address account) → bool isMember, uint32 executionDelay external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-hasRole-uint64-address-) Check if a given account currently has the permission level corresponding to a given role. Note that this permission might be associated with an execution delay. [`AccessManager.getAccess`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-getAccess-uint64-address-) can provide more details. labelRole(uint64 roleId, string label) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-labelRole-uint64-string-) Give a label to a role, for improved role discoverability by UIs. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleLabel`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleLabel-uint64-string-) event. grantRole(uint64 roleId, address account, uint32 executionDelay) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-grantRole-uint64-address-uint32-) Add `account` to `roleId`, or change its execution delay. This gives the account the authorization to call any function that is restricted to this role. An optional execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation that is restricted to members of this role. The user will only be able to execute the operation after the delay has passed, before it has expired. During this period, admin and guardians can cancel the operation (see [`AccessManager.cancel`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-cancel-address-address-bytes-) ). If the account has already been granted this role, the execution delay will be updated. This update is not immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any operation executed in the 3 hours that follows this update was indeed scheduled before this update. Requirements: * the caller must be an admin for the role (see [`AccessControl.getRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) ) * granted role must not be the `PUBLIC_ROLE` Emits a [`IAccessControl.RoleGranted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleGranted-bytes32-address-address-) event. revokeRole(uint64 roleId, address account) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-revokeRole-uint64-address-) Remove an account from a role, with immediate effect. If the account does not have the role, this call has no effect. Requirements: * the caller must be an admin for the role (see [`AccessControl.getRoleAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-getRoleAdmin-bytes32-) ) * revoked role must not be the `PUBLIC_ROLE` Emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event if the account had the role. renounceRole(uint64 roleId, address callerConfirmation) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-renounceRole-uint64-address-) Renounce role permissions for the calling account with immediate effect. If the sender is not in the role this call has no effect. Requirements: * the caller must be `callerConfirmation`. Emits a [`IAccessControl.RoleRevoked`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleRevoked-bytes32-address-address-) event if the account had the role. setRoleAdmin(uint64 roleId, uint64 admin) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setRoleAdmin-uint64-uint64-) Change admin role for a given role. Requirements: * the caller must be a global admin Emits a [`IAccessControl.RoleAdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessControl-RoleAdminChanged-bytes32-bytes32-bytes32-) event setRoleGuardian(uint64 roleId, uint64 guardian) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setRoleGuardian-uint64-uint64-) Change guardian role for a given role. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleGuardianChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGuardianChanged-uint64-uint64-) event setGrantDelay(uint64 roleId, uint32 newDelay) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setGrantDelay-uint64-uint32-) Update the delay for granting a `roleId`. Requirements: * the caller must be a global admin Emits a [`IAccessManager.RoleGrantDelayChanged`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) event. setTargetFunctionRole(address target, bytes4\[\] selectors, uint64 roleId) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setTargetFunctionRole-address-bytes4---uint64-) Set the role required to call functions identified by the `selectors` in the `target` contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetFunctionRoleUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) event per selector. setTargetAdminDelay(address target, uint32 newDelay) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setTargetAdminDelay-address-uint32-) Set the delay for changing the configuration of a given target contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetAdminDelayUpdated`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) event. setTargetClosed(address target, bool closed) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-setTargetClosed-address-bool-) Set the closed flag for a contract. Closing the manager itself won't disable access to admin methods to avoid locking the contract. Requirements: * the caller must be a global admin Emits a [`IAccessManager.TargetClosed`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-TargetClosed-address-bool-) event. getSchedule(bytes32 id) → uint48 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getSchedule-bytes32-) Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the operation is not yet scheduled, has expired, was executed, or was canceled. getNonce(bytes32 id) → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-getNonce-bytes32-) Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never been scheduled. schedule(address target, bytes data, uint48 when) → bytes32 operationId, uint32 nonce external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-schedule-address-bytes-uint48-) Schedule a delayed operation for future execution, and return the operation identifier. It is possible to choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays required for the caller. The special value zero will automatically set the earliest possible time. Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this scheduled operation from other occurrences of the same `operationId` in invocations of [`AccessManager.execute`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-execute-address-bytes-) and [`AccessManager.cancel`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessManager-cancel-address-address-bytes-) . Emits a [`IAccessManager.OperationScheduled`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationScheduled-bytes32-uint32-uint48-address-address-bytes-) event. It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target contract if it is using standard Solidity ABI encoding. execute(address target, bytes data) → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-execute-address-bytes-) Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the execution delay is 0. Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the operation wasn't previously scheduled (if the caller doesn't have an execution delay). Emits an [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event only if the call was scheduled and delayed. cancel(address caller, address target, bytes data) → uint32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-cancel-address-address-bytes-) Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled operation that is cancelled. Requirements: * the caller must be the proposer, a guardian of the targeted function, or a global admin Emits a [`IAccessManager.OperationCanceled`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationCanceled-bytes32-uint32-) event. consumeScheduledOp(address caller, bytes data) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-consumeScheduledOp-address-bytes-) Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed (emit an [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event and clean the state). Otherwise, throw an error. This is useful for contract that want to enforce that calls targeting them were scheduled on the manager, with all the verifications that it implies. Emit a [`IAccessManager.OperationExecuted`](https://docs.openzeppelin.com/contracts/5.x/api/access#IAccessManager-OperationExecuted-bytes32-uint32-) event. hashOperation(address caller, address target, bytes data) → bytes32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-hashOperation-address-address-bytes-) Hashing function for delayed operations. updateAuthority(address target, address newAuthority) external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-updateAuthority-address-address-) Changes the authority of a target managed by this manager instance. Requirements: * the caller must be a global admin OperationScheduled(bytes32 indexed operationId, uint32 indexed nonce, uint48 schedule, address caller, address target, bytes data) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-OperationScheduled-bytes32-uint32-uint48-address-address-bytes-) A delayed operation was scheduled. OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-OperationExecuted-bytes32-uint32-) A scheduled operation was executed. OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-OperationCanceled-bytes32-uint32-) A scheduled operation was canceled. RoleLabel(uint64 indexed roleId, string label) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleLabel-uint64-string-) Informational labelling for a roleId. RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleGranted-uint64-address-uint32-uint48-bool-) Emitted when `account` is granted `roleId`. The meaning of the `since` argument depends on the `newMember` argument. If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role, otherwise it indicates the execution delay for this account and roleId is updated. RoleRevoked(uint64 indexed roleId, address indexed account) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleRevoked-uint64-address-) Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous. RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleAdminChanged-uint64-uint64-) Role acting as admin over a given `roleId` is updated. RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleGuardianChanged-uint64-uint64-) Role acting as guardian over a given `roleId` is updated. RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-RoleGrantDelayChanged-uint64-uint32-uint48-) Grant delay for a given `roleId` will be updated to `delay` when `since` is reached. TargetClosed(address indexed target, bool closed) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-TargetClosed-address-bool-) Target mode is updated (true = closed, false = open). TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-TargetFunctionRoleUpdated-address-bytes4-uint64-) Role required to invoke `selector` on `target` is updated to `roleId`. TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since) event [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-TargetAdminDelayUpdated-address-uint32-uint48-) Admin delay for a given `target` will be updated to `delay` when `since` is reached. AccessManagerAlreadyScheduled(bytes32 operationId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerAlreadyScheduled-bytes32-) AccessManagerNotScheduled(bytes32 operationId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerNotScheduled-bytes32-) AccessManagerNotReady(bytes32 operationId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerNotReady-bytes32-) AccessManagerExpired(bytes32 operationId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerExpired-bytes32-) AccessManagerLockedRole(uint64 roleId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerLockedRole-uint64-) AccessManagerBadConfirmation() error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerBadConfirmation--) AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerUnauthorizedAccount-address-uint64-) AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerUnauthorizedCall-address-address-bytes4-) AccessManagerUnauthorizedConsume(address target) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerUnauthorizedConsume-address-) AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerUnauthorizedCancel-address-address-address-bytes4-) AccessManagerInvalidInitialAdmin(address initialAdmin) error [#](https://docs.openzeppelin.com/contracts/5.x/api/IAccessManager-AccessManagerInvalidInitialAdmin-address-) [`IAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#iauthority) ---------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/access/manager/IAuthority.sol) import "@openzeppelin/contracts/access/manager/IAuthority.sol"; Standard interface for permissioning originally defined in Dappsys. ### Functions * [canCall(caller, target, selector)](https://docs.openzeppelin.com/contracts/5.x/api/access#IAuthority-canCall-address-address-bytes4-) canCall(address caller, address target, bytes4 selector) → bool allowed external [#](https://docs.openzeppelin.com/contracts/5.x/api/IAuthority-canCall-address-address-bytes4-) Returns true if the caller can invoke on a target the function identified by a function selector. [Overview\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/api) [Account\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/api/account) ### On this page [Core](https://docs.openzeppelin.com/contracts/5.x/api/access#core) [Extensions](https://docs.openzeppelin.com/contracts/5.x/api/access#extensions) [AccessManager](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanager) [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrol) [`IAccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrol) [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable) [`Ownable2Step`](https://docs.openzeppelin.com/contracts/5.x/api/access#ownable2step) [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontroldefaultadminrules) [`AccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#accesscontrolenumerable) [`IAccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontroldefaultadminrules) [`IAccessControlEnumerable`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccesscontrolenumerable) [`AccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanaged) [`AccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#accessmanager-1) [`AuthorityUtils`](https://docs.openzeppelin.com/contracts/5.x/api/access#authorityutils) [`IAccessManaged`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanaged) [`IAccessManager`](https://docs.openzeppelin.com/contracts/5.x/api/access#iaccessmanager) [`IAuthority`](https://docs.openzeppelin.com/contracts/5.x/api/access#iauthority) --- # Extending Contracts | OpenZeppelin Docs OpenZeppelin Contracts Extending Contracts =================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Most of the OpenZeppelin Contracts are expected to be used via [inheritance](https://solidity.readthedocs.io/en/latest/contracts.html#inheritance) : you will _inherit_ from them when writing your own contracts. This is the commonly found `is` syntax, like in `contract MyToken is ERC20`. Unlike `contract`s, Solidity `library`s are not inherited from and instead rely on the [`using for`](https://solidity.readthedocs.io/en/latest/contracts.html#using-for) syntax. OpenZeppelin Contracts has some `library`s: most are in the [Utils](https://docs.openzeppelin.com/contracts/5.x/api/utils) directory. [Overriding](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#overriding) ----------------------------------------------------------------------------------------- Inheritance is often used to add the parent contract’s functionality to your own contract, but that’s not all it can do. You can also _change_ how some parts of the parent behave using _overrides_. For example, imagine you want to change [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) so that [`revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) can no longer be called. This can be achieved using overrides: // contracts/AccessControlModified.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; contract AccessControlModified is AccessControl { error AccessControlNonRevocable(); // Override the revokeRole function function revokeRole(bytes32, address) public pure override { revert AccessControlNonRevocable(); } } The old `revokeRole` is then replaced by our override, and any calls to it will immediately revert. We cannot _remove_ the function from the contract, but reverting on all calls is good enough. ### [Calling `super`](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#calling-super) Sometimes you want to _extend_ a parent’s behavior, instead of outright changing it to something else. This is where `super` comes in. The `super` keyword will let you call functions defined in a parent contract, even if they are overridden. This mechanism can be used to add additional checks to a function, emit events, or otherwise add functionality as you see fit. For more information on how overrides work, head over to the [official Solidity documentation](https://solidity.readthedocs.io/en/latest/contracts.html#index-17) . Here is a modified version of [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl) where [`revokeRole`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl-revokeRole-bytes32-address-) cannot be used to revoke the `DEFAULT_ADMIN_ROLE`: The `super.revokeRole` statement at the end will invoke \`\`AccessControl`’s original version of` revokeRole\`, the same code that would’ve run if there were no overrides in place. The same rule is implemented and extended in [`AccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControlDefaultAdminRules) , an extension that also adds enforced security measures for the `DEFAULT_ADMIN_ROLE`. [Security](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#security) ------------------------------------------------------------------------------------- The maintainers of OpenZeppelin Contracts are mainly concerned with the correctness and security of the code as published in the library, and the combinations of base contracts with the official extensions from the library. Custom overrides, especially to hooks, can disrupt important assumptions and may introduce security risks in the code that was previously secure. While we try to ensure the contracts remain secure in the face of a wide range of potential customizations, this is done in a best-effort manner. While we try to document all important assumptions, this should not be relied upon. Custom overrides should be carefully reviewed and checked against the source code of the contract they are customizing to fully understand their impact and guarantee their security. The way functions interact internally should not be assumed to stay stable across releases of the library. For example, a function that is used in one context in a particular release may not be used in the same context in the next release. Contracts that override functions should revalidate their assumptions when updating the version of OpenZeppelin Contracts they are built on. [Contracts Wizard\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/wizard) [Using with Upgrades\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/upgradeable) ### On this page [Overriding](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#overriding) [Calling `super`](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#calling-super) [Security](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#security) --- # Cross-chain messaging | OpenZeppelin Docs [Community Contracts](https://docs.openzeppelin.com/community-contracts) Cross-chain messaging ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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](https://docs.openzeppelin.com/community-contracts/crosschain#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](https://docs.openzeppelin.com/community-contracts/crosschain#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`](https://docs.openzeppelin.com/community-contracts/api/crosschain#AxelarGatewaySource-sendMessage-bytes-bytes-bytes---) function and emits a [`MessageSent`](https://docs.openzeppelin.com/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`](https://docs.openzeppelin.com/community-contracts/api/crosschain#ERC7786Receiver-receiveMessage-bytes32-bytes-bytes-) function. Smart contract developers only need to worry about implementing the [IERC7786GatewaySource](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786GatewaySource) interface to send a message on the source chain and the [IERC7786GatewaySource](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786GatewaySource) and [IERC7786Receiver](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786Receiver) interface to receive such message on the destination chain. ### [Getting started with Axelar Network](https://docs.openzeppelin.com/community-contracts/crosschain#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. // contracts/MyCustomAxelarGatewayDuplex.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {AxelarGatewayDuplex, AxelarExecutable} from "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayDuplex.sol"; import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; abstract contract MyCustomAxelarGatewayDuplex is AxelarGatewayDuplex { /// @dev Initializes the contract with the Axelar gateway and the initial owner. constructor(IAxelarGateway gateway, address initialOwner) AxelarGatewayDuplex(gateway, initialOwner) {} } For more details of how the duplex gateway works, see [how to send and receive messages with the Axelar Network](https://docs.openzeppelin.com/community-contracts/crosschain#axelar-network) below Developers can register supported chains and destination gateways using the [`registerChainEquivalence`](https://docs.openzeppelin.com/community-contracts/api/crosschain#AxelarGatewayBase-registerChainEquivalence-string-string-) and [`registerRemoteGateway`](https://docs.openzeppelin.com/community-contracts/api/crosschain#AxelarGatewayBase-registerRemoteGateway-string-string-) functions [Cross-chain communication](https://docs.openzeppelin.com/community-contracts/crosschain#cross-chain-communication) -------------------------------------------------------------------------------------------------------------------- ### [Sending a message](https://docs.openzeppelin.com/community-contracts/crosschain#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`](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786GatewaySource-MessageSent-bytes32-string-string-bytes-bytes---) event and deliver it to the receiver on the destination chain. // contracts/MyERC7786GatewaySource.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {IERC7786GatewaySource} from "@openzeppelin/community-contracts/interfaces/IERC7786.sol"; import {InteroperableAddress} from "@openzeppelin/contracts/utils/draft-InteroperableAddress.sol"; abstract contract MyERC7786GatewaySource is IERC7786GatewaySource { error UnsupportedNativeTransfer(); /// @inheritdoc IERC7786GatewaySource function supportsAttribute(bytes4 /*selector*/) public pure returns (bool) { return false; } /// @inheritdoc IERC7786GatewaySource function sendMessage( bytes calldata recipient, // Binary Interoperable Address bytes calldata payload, bytes[] calldata attributes ) external payable returns (bytes32 sendId) { require(msg.value == 0, UnsupportedNativeTransfer()); // Use of `if () revert` syntax to avoid accessing attributes[0] if it's empty if (attributes.length > 0) revert UnsupportedAttribute(attributes[0].length < 0x04 ? bytes4(0) : bytes4(attributes[0][0:4])); // Emit event sendId = bytes32(0); // Explicitly set to 0. Can be used for post-processing emit MessageSent( sendId, InteroperableAddress.formatEvmV1(block.chainid, msg.sender), recipient, payload, 0, attributes ); // Optionally: If this is an adapter, send the message to a protocol gateway for processing // This may require the logic for tracking destination gateway addresses and chain identifiers return sendId; } } 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](https://docs.openzeppelin.com/community-contracts/crosschain#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](https://docs.openzeppelin.com/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. // contracts/MyERC7786ReceiverContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; import {ERC7786Receiver} from "@openzeppelin/community-contracts/crosschain/utils/ERC7786Receiver.sol"; contract MyERC7786ReceiverContract is ERC7786Receiver, AccessManaged { constructor(address initialAuthority) AccessManaged(initialAuthority) {} /// @dev Check if the given instance is a known gateway. function _isKnownGateway(address /* instance */) internal view virtual override returns (bool) { return true; } /// @dev Internal endpoint for receiving cross-chain message. function _processMessage( address gateway, bytes32 receiveId, bytes calldata sender, bytes calldata payload ) internal virtual override restricted { // Process the message here } } 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](https://docs.openzeppelin.com/community-contracts/crosschain#axelar-network) Aside from the [AxelarGatewayDuplex](https://docs.openzeppelin.com/community-contracts/api/crosschain#AxelarGatewayDuplex) , the library offers an implementation of the [IERC7786GatewaySource](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786GatewaySource) interface called [AxelarGatewaySource](https://docs.openzeppelin.com/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](https://docs.openzeppelin.com/community-contracts/api/crosschain#AxelarGatewaySource) implementation can be used out of the box // contracts/MyERC7786ReceiverContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {AxelarGatewaySource} from "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewaySource.sol"; import {AxelarGatewayBase} from "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayBase.sol"; import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; abstract contract MyCustomAxelarGatewaySource is AxelarGatewaySource { /// @dev Initializes the contract with the Axelar gateway and the initial owner. constructor(IAxelarGateway gateway, address initialOwner) Ownable(initialOwner) AxelarGatewayBase(gateway) {} } For a destination gateway, the library provides an adapter of the `AxelarExecutable` interface to receive messages and relay them to an [IERC7786Receiver](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786Receiver) . // contracts/MyCustomAxelarGatewayDestination.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {AxelarGatewayDestination, AxelarExecutable} from "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayDestination.sol"; import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; abstract contract MyCustomAxelarGatewayDestination is AxelarGatewayDestination { /// @dev Initializes the contract with the Axelar gateway and the initial owner. constructor(IAxelarGateway gateway, address initialOwner) AxelarExecutable(address(gateway)) {} } ### [Open Bridge](https://docs.openzeppelin.com/community-contracts/crosschain#open-bridge) The [ERC7786OpenBridge](https://docs.openzeppelin.com/community-contracts/api/crosschain#ERC7786OpenBridge) is a special gateway that implements both [IERC7786GatewaySource](https://docs.openzeppelin.com/community-contracts/api/crosschain#IERC7786GatewaySource) and [IERC7786Receiver](https://docs.openzeppelin.com/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: 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`](https://docs.openzeppelin.com/community-contracts/api/crosschain#ERC7786OpenBridge-receiveMessage-string-string-string-bytes-bytes---) function handles this process: 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`](https://docs.openzeppelin.com/community-contracts/api/crosschain#ERC7786OpenBridge-_addGateway-address-) and [`_setThreshold`](https://docs.openzeppelin.com/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. [Paymasters\ \ Previous Page](https://docs.openzeppelin.com/community-contracts/paymasters) [Utilities\ \ Next Page](https://docs.openzeppelin.com/community-contracts/utilities) ### On this page [ERC-7786 Gateway](https://docs.openzeppelin.com/community-contracts/crosschain#erc-7786-gateway) [Message passing overview](https://docs.openzeppelin.com/community-contracts/crosschain#message-passing-overview) [Getting started with Axelar Network](https://docs.openzeppelin.com/community-contracts/crosschain#getting-started-with-axelar-network) [Cross-chain communication](https://docs.openzeppelin.com/community-contracts/crosschain#cross-chain-communication) [Sending a message](https://docs.openzeppelin.com/community-contracts/crosschain#sending-a-message) [Receiving a message](https://docs.openzeppelin.com/community-contracts/crosschain#receiving-a-message) [Axelar Network](https://docs.openzeppelin.com/community-contracts/crosschain#axelar-network) [Open Bridge](https://docs.openzeppelin.com/community-contracts/crosschain#open-bridge) --- # OpenZeppelin Upgrades Core & CLI | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) OpenZeppelin Upgrades Core & CLI ================================ Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) The `@openzeppelin/upgrades-core` package provides a `validate` command to check for upgrade safety and storage layout compatibility in upgradeable contracts. It can be used throughout your development process to ensure that your contracts are upgrade safe and compatible with previous versions. It also provides APIs to perform these checks programmatically, and contains the core logic for these checks to be performed with the OpenZeppelin Upgrades plugins. [CLI: Validate Command](https://docs.openzeppelin.com/upgrades-plugins/api-core#cli-validate-command) ------------------------------------------------------------------------------------------------------ Detects upgradeable contracts from a directory containing build info files and validates whether they are upgrade safe. Use this if you want to validate all of your project's upgradeable contracts from the command line, in a script, or as part of your CI/CD pipeline. "Build info files" are generated by your compilation toolchain (Hardhat, Foundry) and contain the inputs and outputs of the compilation process. ### [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites) Before using the `validate` command, you must define upgradeable contracts so that they can be detected and validated, define reference contracts for storage layout comparisons, and compile your contracts. #### [Define Upgradeable Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-upgradeable-contracts) The `validate` command performs upgrade safety checks on contracts that look like upgradeable contracts. Specifically, it performs checks on implementation contracts that meet any of the following criteria: * Inherits [`Initializable`](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/proxy/utils/Initializable.sol) . * Has an `upgradeTo(address)` or `upgradeToAndCall(address,bytes)` function. This is the case for contracts that inherit [`UUPSUpgradeable`](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol) . * Has the NatSpec annotation `@custom:oz-upgrades` * Has the NatSpec annotation `@custom:oz-upgrades-from ` according to [Define Reference Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-reference-contracts) below. Simply add the NatSpec annotation `@custom:oz-upgrades` or `@custom:oz-upgrades-from ` to each implementation contract so that it can be detected as an upgradeable contract for validation. #### [Define Reference Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-reference-contracts) If an implementation contract is meant to deployed as an upgrade to an existing proxy, you **MUST** define a reference contract for storage layout comparisons. Otherwise, you will not receive errors if there are any storage layout incompatibilities. Define a reference contract by adding the NatSpec annotation `@custom:oz-upgrades-from ` to your implementation contract, where `` is the contract name or fully qualified contract name of the reference contract to use for storage layout comparisons. The contract does not need to be in scope, and the contract name will suffice if it is unambiguous across the project. Example: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @custom:oz-upgrades-from MyContractV1 contract MyContractV2 { ... } Or: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @custom:oz-upgrades-from contracts/MyContract.sol:MyContractV1 contract MyContractV2 { ... } #### [Compile Contracts with Storage Layouts](https://docs.openzeppelin.com/upgrades-plugins/api-core#compile-contracts-with-storage-layouts) Compile your contracts and ensure that your build is configured to output JSON files with Solidity compiler inputs and outputs in a build info directory. The compiler output must include storage layouts. If any previous build artifacts exist, they must be cleaned first to avoid duplicate contract definitions. ##### [Hardhat](https://docs.openzeppelin.com/upgrades-plugins/api-core#hardhat) Configure `hardhat.config.js` or `hardhat.config.ts` to include storage layout in the output selection: module.exports = { solidity: { settings: { outputSelection: { '*': { '*': ['storageLayout'], }, }, }, }, }; Then compile your contracts: npx hardhat clean && npx hardhat compile ##### [Foundry](https://docs.openzeppelin.com/upgrades-plugins/api-core#foundry) Configure `foundry.toml` to include build info and storage layout: [profile.default] build_info = true extra_output = ["storageLayout"] Then compile your contracts: forge clean && forge build ### [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage) After performing the prerequisites, run the `npx @openzeppelin/upgrades-core validate` command to validate your contracts: npx @openzeppelin/upgrades-core validate [] [] If any errors are found, the command will exit with a non-zero exit code and print a detailed report of the errors to the console. **Parameters:** * `` - Optional path to the build info directory which contains JSON files with Solidity compiler input and output. Defaults to `artifacts/build-info` for Hardhat projects or `out/build-info` for Foundry projects. If your project uses a custom output directory, you must specify its build info directory here. **Options:** * `--contract ` - The name or fully qualified name of the contract to validate. If not specified, all upgradeable contracts in the build info directory will be validated. * `--reference ` - Can only be used when the `--contract` option is also provided. The name or fully qualified name of the reference contract to use for storage layout comparisons. If not specified, uses the `@custom:oz-upgrades-from` annotation if it is defined in the contract that is being validated. * `--requireReference` - Can only be used when the `--contract` option is also provided. Not compatible with `--unsafeSkipStorageCheck`. If specified, requires either the `--reference` option to be provided or the contract to have a `@custom:oz-upgrades-from` annotation. * `--referenceBuildInfoDirs "[,...]"` - Optional paths of additional build info directories from previous versions of the project to use for storage layout comparisons. When using this option, refer to one of these directories using prefix `:` before the contract name or fully qualified name in the `--reference` option or `@custom:oz-upgrades-from` annotation, where `` is the directory short name. Each directory short name must be unique, including compared to the main build info directory. If passing in multiple directories, separate them with commas or call the option multiple times, once for each directory. * `--exclude "" [--exclude ""...]` - Exclude validations for contracts in source file paths that match any of the given glob patterns. For example, `--exclude "contracts/mocks/\***/**.sol"`. Does not apply to reference contracts. If passing in multiple patterns, call the option multiple times, once for each pattern. * `--unsafeAllow "[,...]"` - Selectively disable one or more validation errors or warnings. Comma-separated list with one or more of the following: * Errors: `state-variable-assignment, state-variable-immutable, external-library-linking, struct-definition, enum-definition, constructor, delegatecall, selfdestruct, missing-public-upgradeto, internal-function-storage, missing-initializer, missing-initializer-call, duplicate-initializer-call` * Warnings: `incorrect-initializer-order` * `--unsafeAllowRenames` - Configure storage layout check to allow variable renaming. * `--unsafeSkipStorageCheck` - Skips checking for storage layout compatibility errors. This is a dangerous option meant to be used as a last resort. [High-Level API](https://docs.openzeppelin.com/upgrades-plugins/api-core#high-level-api) ----------------------------------------------------------------------------------------- The high-level API is a programmatic equivalent to the [validate command](https://docs.openzeppelin.com/upgrades-plugins/api-core#cli:-validate-command) . Use this API if you want to validate all of your project's upgradeable contracts from a JavaScript or TypeScript environment. ### [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites-1) Same prerequisites as the [validate command](https://docs.openzeppelin.com/upgrades-plugins/api-core#cli:-validate-command) . ### [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage-1) Import the `validateUpgradeSafety` function: import { validateUpgradeSafety } from '@openzeppelin/upgrades-core'; Then call the function to validate your contracts and get a project report with the validation results. #### [validateUpgradeSafety](https://docs.openzeppelin.com/upgrades-plugins/api-core#validateupgradesafety) validateUpgradeSafety( buildInfoDir?: string, contract?: string, reference?: string, opts: ValidateUpgradeSafetyOptions = {}, referenceBuildInfoDirs?: string[], exclude?: string[], ): Promise Detects upgradeable contracts from a build info directory and validates whether they are upgrade safe. Returns a [project report](https://docs.openzeppelin.com/upgrades-plugins/api-core#projectreport) with the results. Note that this function does not throw validation errors directly. Instead, you must use the project report to determine whether any errors were found. **Parameters:** * `buildInfoDir` - the path to the build info directory which contains JSON files with Solidity compiler input and output. Defaults to `artifacts/build-info` for Hardhat projects or `out/build-info` for Foundry projects. If your project uses a custom output directory, you must specify its build info directory here. * `contract` - The name or fully qualified name of the contract to validate. If not specified, all upgradeable contracts in the build info directory will be validated. * `reference` - Can only be used when the `contract` argument is also provided. The name or fully qualified name of the reference contract to use for storage layout comparisons. If not specified, uses the `@custom:oz-upgrades-from` annotation if it is defined in the contract that is being validated. * `opts` - an object with the following options as defined in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) : * `unsafeAllow` * `unsafeAllowRenames` * `unsafeSkipStorageCheck` * `requireReference` - Can only be used when the `contract` argument is also provided. Not compatible with the `unsafeSkipStorageCheck` option. If specified, requires either the `reference` argument to be provided or the contract to have a `@custom:oz-upgrades-from` annotation. * `referenceBuildInfoDirs` - Optional paths of additional build info directories from previous versions of the project to use for storage layout comparisons. When using this option, refer to one of these directories using prefix `:` before the contract name or fully qualified name in the `reference` param or `@custom:oz-upgrades-from` annotation, where `` is the directory short name. Each directory short name must be unique, including compared to the main build info directory. * `exclude` - Exclude validations for contracts in source file paths that match any of the given glob patterns. **Returns:** * a [project report](https://docs.openzeppelin.com/upgrades-plugins/api-core#projectreport) . #### [ProjectReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#projectreport) interface ProjectReport { ok: boolean; explain(color?: boolean): string; numPassed: number; numTotal: number; } An object that represents the result of upgrade safety checks and storage layout comparisons, and contains a report of all errors found. _**Members:**_ * `ok` - `false` if any errors were found, otherwise `true`. * `explain()` - returns a message explaining the errors in detail, if any. * `numPassed` - number of contracts that passed upgrade safety checks. * `numTotal` - total number of upgradeable contracts detected. [Low-Level API](https://docs.openzeppelin.com/upgrades-plugins/api-core#low-level-api) --------------------------------------------------------------------------------------- This low-level API is deprecated. Use the [High-Level API](https://docs.openzeppelin.com/upgrades-plugins/api-core#high-level-api) instead. The low-level API works with [Solidity input and output JSON objects](https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-input-and-output-json-description) and lets you perform upgrade safety checks and storage layout comparisons on individual contracts. Use this API if you want to validate specific contracts rather than a whole project. ### [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites-2) Compile your contracts to generate Solidity input and output JSON objects. The compiler output must include storage layouts. Note that the other prerequisites from the [validate command](https://docs.openzeppelin.com/upgrades-plugins/api-core#cli:-validate-command) are not required, because the low-level API does not detect upgradeable contracts automatically. Instead, you must create an instance of `UpgradeableContract` for each implementation contract that you want to validate, and call functions on it to get the upgrade safety and storage layout reports. ### [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage-2) Import the `UpgradeableContract` class: import { UpgradeableContract } from '@openzeppelin/upgrades-core'; Then create an instance of `UpgradeableContract` for each implementation contract that you want to validate, and call `.getErrorReport()` and/or `.getStorageLayoutReport()` on it to get the upgrade safety and storage layout reports, respectively. #### [UpgradeableContract](https://docs.openzeppelin.com/upgrades-plugins/api-core#upgradeablecontract) This class represents the implementation for an upgradeable contract and gives access to error reports. ##### [constructor UpgradeableContract](https://docs.openzeppelin.com/upgrades-plugins/api-core#constructor-upgradeablecontract) constructor UpgradeableContract( name: string, solcInput: SolcInput, solcOutput: SolcOutput, opts?: { unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, kind?: 'uups' | 'transparent' | 'beacon', }, solcVersion?: string, ): UpgradeableContract Creates a new instance of `UpgradeableContract`. **Parameters:** * `name` - the name of the implementation contract as either a fully qualified name or contract name. If multiple contracts have the same name, you must use the fully qualified name e.g., `contracts/Bar.sol:Bar`. * `solcInput` - the Solidity input JSON object for the implementation contract. * `solcOutput` - the Solidity output JSON object for the implementation contract. * `opts` - an object with the following options as defined in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) : * `kind` * `unsafeAllow` * `unsafeAllowRenames` * `unsafeSkipStorageCheck` * `solcVersion` - the Solidity version used to compile the implementation contract. In Hardhat, `solcInput` and `solcOutput` can be obtained from the Build Info file, which itself can be retrieved with `hre.artifacts.getBuildInfo`. ##### [.getErrorReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#geterrorreport) getErrorReport(): Report _**Returns:**_ * a report about errors pertaining to proxied contracts, e.g. the use of `selfdestruct`. ##### [.getStorageUpgradeReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#getstorageupgradereport) getStorageUpgradeReport( upgradedContract: UpgradeableContract, opts?: { unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, kind?: 'uups' | 'transparent' | 'beacon', }, ): Report Compares the storage layout of an upgradeable contract with that of a proposed upgrade. **Parameters:** * `upgradedContract` - another instance of `UpgradeableContract` representing the proposed upgrade. * `opts` - an object with the following options as defined in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) : * `kind` * `unsafeAllow` * `unsafeAllowRenames` * `unsafeSkipStorageCheck` _**Returns:**_ * a report about errors pertaining to proxied contracts, e.g. the use of `selfdestruct`, and storage layout conflicts. #### [Report](https://docs.openzeppelin.com/upgrades-plugins/api-core#report) interface Report { ok: boolean; explain(color?: boolean): string; } An object that represents the results of an analysis. _**Members:**_ * `ok` - `false` if any errors were found, otherwise `true`. * `explain()` - returns a message explaining the errors in detail, if any. ### On this page [CLI: Validate Command](https://docs.openzeppelin.com/upgrades-plugins/api-core#cli-validate-command) [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites) [Define Upgradeable Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-upgradeable-contracts) [Define Reference Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-reference-contracts) [Compile Contracts with Storage Layouts](https://docs.openzeppelin.com/upgrades-plugins/api-core#compile-contracts-with-storage-layouts) [Hardhat](https://docs.openzeppelin.com/upgrades-plugins/api-core#hardhat) [Foundry](https://docs.openzeppelin.com/upgrades-plugins/api-core#foundry) [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage) [High-Level API](https://docs.openzeppelin.com/upgrades-plugins/api-core#high-level-api) [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites-1) [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage-1) [validateUpgradeSafety](https://docs.openzeppelin.com/upgrades-plugins/api-core#validateupgradesafety) [ProjectReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#projectreport) [Low-Level API](https://docs.openzeppelin.com/upgrades-plugins/api-core#low-level-api) [Prerequisites](https://docs.openzeppelin.com/upgrades-plugins/api-core#prerequisites-2) [Usage](https://docs.openzeppelin.com/upgrades-plugins/api-core#usage-2) [UpgradeableContract](https://docs.openzeppelin.com/upgrades-plugins/api-core#upgradeablecontract) [constructor UpgradeableContract](https://docs.openzeppelin.com/upgrades-plugins/api-core#constructor-upgradeablecontract) [.getErrorReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#geterrorreport) [.getStorageUpgradeReport](https://docs.openzeppelin.com/upgrades-plugins/api-core#getstorageupgradereport) [Report](https://docs.openzeppelin.com/upgrades-plugins/api-core#report) --- # Using with Hardhat | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) Using with Hardhat ================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This package adds functions to your Hardhat scripts so you can deploy and upgrade proxies for your contracts. Depends on `ethers.js`. Check out the [step by step tutorial](https://forum.openzeppelin.com/t/openzeppelin-buidler-upgrades-step-by-step-tutorial/3580) , showing from creating, testing and deploying, all the way through to upgrading with Gnosis Safe. [Installation](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#installation) --------------------------------------------------------------------------------------------- $ npm install --save-dev @openzeppelin/hardhat-upgrades $ npm install --save-dev @nomicfoundation/hardhat-ethers ethers # peer dependencies And register the plugin in your [`hardhat.config.js`](https://hardhat.org/config) : require('@openzeppelin/hardhat-upgrades'); [Usage in scripts](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-in-scripts) ----------------------------------------------------------------------------------------------------- ### [Proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#proxies) You can use this plugin in a [Hardhat script](https://hardhat.org/guides/scripts.html) to deploy an upgradeable instance of one of your contracts via the `deployProxy` function: // scripts/create-box.js const ethers, upgrades = require("hardhat"); async function main() const Box = await ethers.getContractFactory("Box"); const box = await upgrades.deployProxy(Box, [42]); await box.waitForDeployment(); console.log("Box deployed to:", await box.getAddress()); main(); This will automatically check that the `Box` contract is upgrade-safe, deploy an implementation contract for the `Box` contract (unless there is one already from a previous deployment), create a proxy (along with a proxy admin if needed), and initialize it by calling `initialize(42)`. Then, in another script, you can use the `upgradeProxy` function to upgrade the deployed instance to a new version. The new version can be a different contract (such as `BoxV2`), or you can just modify the existing `Box` contract and recompile it - the plugin will note it changed. // scripts/upgrade-box.js const ethers, upgrades = require("hardhat"); async function main() const BoxV2 = await ethers.getContractFactory("BoxV2"); const box = await upgrades.upgradeProxy(BOX_ADDRESS, BoxV2); console.log("Box upgraded"); main(); > Note: While this plugin keeps track of all the implementation contracts you have deployed per network, in order to reuse them and validate storage compatibilities, it does _not_ keep track of the proxies you have deployed. This means that you will need to manually keep track of each deployment address, to supply those to the upgrade function when needed. The plugin will take care of comparing `BoxV2` to the previous one to ensure they are compatible for the upgrade, deploy the new `BoxV2` implementation contract (unless there is one already from a previous deployment), and upgrade the existing proxy to the new implementation. ### [Beacon proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#beacon-proxies) You can also use this plugin to deploy an upgradeable beacon for your contract with the `deployBeacon` function, then deploy one or more beacon proxies that point to it by using the `deployBeaconProxy` function. // scripts/create-box.js const ethers, upgrades = require("hardhat"); async function main() const Box = await ethers.getContractFactory("Box"); const beacon = await upgrades.deployBeacon(Box); await beacon.waitForDeployment(); console.log("Beacon deployed to:", await beacon.getAddress()); const box = await upgrades.deployBeaconProxy(beacon, Box, [42]); await box.waitForDeployment(); console.log("Box deployed to:", await box.getAddress()); main(); Then, in another script, you can use the `upgradeBeacon` function to upgrade the beacon to a new version. When the beacon is upgraded, all of the beacon proxies that point to it will use the new contract implementation. // scripts/upgrade-box.js const ethers, upgrades = require("hardhat"); async function main() const BoxV2 = await ethers.getContractFactory("BoxV2"); await upgrades.upgradeBeacon(BEACON_ADDRESS, BoxV2); console.log("Beacon upgraded"); const box = BoxV2.attach(BOX_ADDRESS); main(); [Usage in tests](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-in-tests) ------------------------------------------------------------------------------------------------- You can also use the plugin’s functions from your Hardhat tests, in case you want to add tests for upgrading your contracts (which you should!). The API is the same as in scripts. ### [Proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#proxies-1) const expect = require("chai"); describe("Box", function() it('works', async () => { const Box = await ethers.getContractFactory("Box"); const BoxV2 = await ethers.getContractFactory("BoxV2"); const instance = await upgrades.deployProxy(Box, [42]); const upgraded = await upgrades.upgradeProxy(await instance.getAddress(), BoxV2); const value = await upgraded.value(); expect(value.toString()).to.equal('42'); ); }); ### [Beacon proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#beacon-proxies-1) const expect = require("chai"); describe("Box", function() it('works', async () => { const Box = await ethers.getContractFactory("Box"); const BoxV2 = await ethers.getContractFactory("BoxV2"); const beacon = await upgrades.deployBeacon(Box); const instance = await upgrades.deployBeaconProxy(beacon, Box, [42]); await upgrades.upgradeBeacon(beacon, BoxV2); const upgraded = BoxV2.attach(await instance.getAddress()); const value = await upgraded.value(); expect(value.toString()).to.equal('42'); ); }); [Usage with Defender](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-with-defender) ----------------------------------------------------------------------------------------------------------- If you are using OpenZeppelin Defender, see [OpenZeppelin Defender with Hardhat](https://docs.openzeppelin.com/upgrades-plugins/defender-deploy) for how to use it for deployments. [API](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#api) --------------------------------------------------------------------------- See [Hardhat Upgrades API](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades) for the full API documentation. ### On this page [Installation](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#installation) [Usage in scripts](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-in-scripts) [Proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#proxies) [Beacon proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#beacon-proxies) [Usage in tests](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-in-tests) [Proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#proxies-1) [Beacon proxies](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#beacon-proxies-1) [Usage with Defender](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#usage-with-defender) [API](https://docs.openzeppelin.com/upgrades-plugins/hardhat-upgrades#api) --- # Backwards Compatibility | OpenZeppelin Docs OpenZeppelin Contracts Backwards Compatibility ======================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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. [API](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#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](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#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. ### [Draft or Pre-Final ERCs](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#draft-or-pre-final-ercs) ERCs that are not Final can change in incompatible ways. For this reason, we avoid shipping implementations of ERCs before they are Final. Some exceptions are made for ERCs that have been published for a long time and seem unlikely to change. Implementations for ERCs that may have breaking changes are published in files named `draft-*.sol` to make that condition explicit. There is no backwards compatibility guarantee for content in files prefixed with `draft`. Standards that have achieved widespread adoption with strong backwards compatibility expectations from the community may be treated as de-facto finalized and published without the `draft-` prefix, as extensive ecosystem reliance makes breaking changes highly unlikely. ### [Virtual & Overrides](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#virtual--overrides) Almost all functions in this library are virtual with some exceptions, but this does not mean that overrides are encouraged. There is a subset of functions that are designed to be overridden. By defining overrides outside of this subset you are potentially relying on internal implementation details. We make efforts to preserve backwards compatibility even in these cases but it is extremely difficult and easy to accidentally break. Caution is advised. Additionally, some minor updates may result in new compilation errors of the kind "two or more base classes define function with same name and parameter types" or "need to specify overridden contract", due to what Solidity considers ambiguity in inherited functions. This should be resolved by adding an override that invokes the function via `super`. See [Extending Contracts](https://docs.openzeppelin.com/contracts/5.x/extending-contracts) for more about virtual and overrides. ### [Structs](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#structs) Struct members with an underscore prefix should be considered "private" and may break in minor versions. Struct data should only be accessed and modified through library functions. ### [Errors](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#errors) The specific error format and data that is included with reverts should not be assumed stable unless otherwise specified. ### [Major Releases](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#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. [Storage Layout](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#storage-layout) ----------------------------------------------------------------------------------------------------- Minor and patch updates always preserve storage layout compatibility. 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. We recommend using [OpenZeppelin Upgrades Plugins or CLI](https://docs.openzeppelin.com/upgrades-plugins) to ensure storage layout safety of upgrades. [Solidity Version](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#solidity-version) --------------------------------------------------------------------------------------------------------- The minimum Solidity version required to compile the contracts will remain unchanged in minor and patch updates. New contracts introduced in minor releases may make use of newer Solidity features and require a more recent version of the compiler. [Using with Upgrades\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/upgradeable) [Access Control\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/access-control) ### On this page [API](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#api) [Security](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#security) [Draft or Pre-Final ERCs](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#draft-or-pre-final-ercs) [Virtual & Overrides](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#virtual--overrides) [Structs](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#structs) [Errors](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#errors) [Major Releases](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#major-releases) [Storage Layout](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#storage-layout) [Solidity Version](https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility#solidity-version) --- # Defender | OpenZeppelin Docs Defender Defender ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) New sign-ups were disabled on June 30, 2025. Until the final shutdown on July 1, 2026, Defender will remain fully operational while we focus on the open source versions of tools like Relayers and Monitor. Detailed migration guides are coming soon to help you transition seamlessly to open source. [Read more](https://blog.openzeppelin.com/doubling-down-on-open-source-and-phasing-out-defender) OpenZeppelin Defender is a mission-critical developer security platform to **code**, **audit**, **deploy**, **monitor**, and **operate** blockchain applications with confidence. Integrating directly into the developer workflow, Defender makes it easy and fast for developers and operators to prevent and fix security issues pre and post-deployment. [Subscriptions](https://docs.openzeppelin.com/defender#subscriptions) ---------------------------------------------------------------------- Defender offers flexible subscriptions to match your team’s needs and support your project at any scale. * **Builder (Free)** - Suitable for individuals and small projects that are getting started on testnets and need access to all basic features with limited quotas. * **Professional** - For mature projects running on mainnets that need access to premium features, higher quotas and metered billing, as well as access to OpenZeppelin support and SLA. * **Enterprise** - For large projects with higher volumes that need a custom plan to meet their project needs, with higher quotas, access to all premium and security features, and a dedicated support channel. [Modules](https://docs.openzeppelin.com/defender#modules) ---------------------------------------------------------- Defender modules work seamlessly together, providing users powerful features and a superior, integrated experience. Learn more about each module by clicking on its card. [### Code Inspector\ \ Automatic code analysis powered by AI models and tools developed by our security experts.](https://docs.openzeppelin.com/defender/module/code) [### Audit\ \ Manage the smart contract audit process and track issues and resolutions.](https://docs.openzeppelin.com/defender/module/audit) [### Deploy\ \ Manage deployments and upgrades to ensure secure releases.](https://docs.openzeppelin.com/defender/module/deploy) [### Relayers\ \ Send transactions to the blockchain via Defender automatically.](https://docs.openzeppelin.com/defender/module/relayers) [### Monitor\ \ Detect smart contract activity and anomalies through trigger actions and alerts.](https://docs.openzeppelin.com/defender/module/monitor) [### Transaction Proposals\ \ Create transactions to be executed on-chain.](https://docs.openzeppelin.com/defender/module/transaction-proposals) [### Actions\ \ Create automated actions to perform on-chain and off-chain operations.](https://docs.openzeppelin.com/defender/module/actions) [### Address Book\ \ Create a shared repository of user-friendly names for your accounts or contracts.](https://docs.openzeppelin.com/defender/module/address-book) [### Access Control\ \ Manage smart contract accounts, roles, and permissions easily.](https://docs.openzeppelin.com/defender/module/access-control) [Available networks](https://docs.openzeppelin.com/defender#available-networks) -------------------------------------------------------------------------------- Defender works with most mainnet and testnet networks, as well as local mainnet forks. * [**Arbitrum One**](https://arbitrum.io/) , [**Arbitrum Nova**](https://nova.arbitrum.io/) , **Arbitrum Sepolia**. * [**Aurora**](https://aurora.dev/) and **Aurora Testnet**. * [**Avalanche C**](https://docs.avax.network/dapps) and **FUJI C-Chain**. * [**Base Mainnet**](https://www.base.org/) and **Base Sepolia**. * [**Binance Smart Chain**](https://docs.binance.org/smart-chain/guides/bsc-intro.html) and **BSC testnet**. * [**Celo**](https://celo.org/) and **Alfajores**. * [**Ethereum Mainnet**](https://ethereum.org/en/) , **Sepolia** testnet and **Holesky** testnet. * [**Fantom**](https://fantom.foundation/what-is-fantom-opera/) and **Fantom Testnet**. * [**Fuse**](https://fuse.io/) . * [**Gnosis Chain**](https://www.gnosis.io/) * [**Hedera**](https://hedera.com/) and **Hedera Testnet**. * [**Japan Open Chain**](https://www.japanopenchain.org/en/docs/developer/mainnet) and **Japan Open Chain Testnet**. * [**Linea Mainnet**](https://linea.build/) and **Linea Sepolia**. * [**Scroll Mainnet**](https://scroll.io/) and **Scroll Sepolia**. * [**Mantle Mainnet**](https://www.mantle.xyz/) and **Mantle Sepolia**. * [**Meld Mainnet**](https://www.meld.com/) and **Meld Testnet**. * [**Moonbeam**](https://moonbeam.network/) , **Moonriver**, and **Moonbase Alpha (Testnet)**. * [**OP Mainnet**](https://optimism.io/) , **OP Sepolia**. * [**Polygon** (POL)](https://www.polygon.technology/) , **Amoy**, [**zkEVM**](https://polygon.technology/polygon-zkevm) and **Polygon Cardona zkEVM testnet** * [**Scroll Mainnet**](https://scroll.io/) and **Scroll Sepolia**. * [**Unichain**](https://www.unichain.org/) and **Unichain Sepolia**. * [**zkSync Era Mainnet**](https://zksync.io/) and **zkSync Era Sepolia**. * [**Geist Mainnet**](https://www.playongeist.com//) and **Polter Testnet**. * [**Abstract Mainnet**](https://docs.abs.xyz/overview) and **Abstract Sepolia**. * [**Peaq Mainnet**](https://www.peaq.network/) and **Peaq Agung**. * [**Sei**](https://www.sei.io/) and **Sei Testnet (Atlantic-2)**. If there is any other network or layer-2 solution you would like to use from Defender, please [reach out to us via the form on Defender](https://docs.openzeppelin.com/defender#feedback) ! ### [Status](https://docs.openzeppelin.com/defender#status) You can check the status of Defender and the supported networks on our [status page](https://status.defender.openzeppelin.com/) , where you can also subscribe to receive notifications. If a supported network experiences issues, some features in Defender for that network may not work properly. [Integrations](https://docs.openzeppelin.com/defender#integrations) -------------------------------------------------------------------- Integrations throughout Defender allow users to connect with other services and tools. Find the list of integrations and more information [here](https://docs.openzeppelin.com/defender/integrations) . [Service Level and Support Agreement](https://docs.openzeppelin.com/defender#service-level-and-support-agreement) ------------------------------------------------------------------------------------------------------------------ For our [paid subscriptions](https://www.openzeppelin.com/pricing) , we’re offering enhanced service reliability, guaranteed uptime, and priority support. You can learn more on our [Service Level and Support Agreement (SLA) page](https://www.openzeppelin.com/service-level-agreement) . [Feedback](https://docs.openzeppelin.com/defender#feedback) ------------------------------------------------------------ As a Defender user, your feedback is important! Please provide us feedback by accesing the form on the bottom-right corner of your screen. ![Feedback form button bottom-right corner](https://docs.openzeppelin.com/defender/feedback-button.png) ### On this page [Subscriptions](https://docs.openzeppelin.com/defender#subscriptions) [Modules](https://docs.openzeppelin.com/defender#modules) [Available networks](https://docs.openzeppelin.com/defender#available-networks) [Status](https://docs.openzeppelin.com/defender#status) [Integrations](https://docs.openzeppelin.com/defender#integrations) [Service Level and Support Agreement](https://docs.openzeppelin.com/defender#service-level-and-support-agreement) [Feedback](https://docs.openzeppelin.com/defender#feedback) --- # Utilities | OpenZeppelin Docs [Community Contracts](https://docs.openzeppelin.com/community-contracts) Utilities ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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](https://docs.openzeppelin.com/community-contracts/api/utils) . [Cryptography](https://docs.openzeppelin.com/community-contracts/utilities#cryptography) ----------------------------------------------------------------------------------------- ### [Validating Typed Data Signatures](https://docs.openzeppelin.com/community-contracts/utilities#validating-typed-data-signatures) _For prior knowledge on how to validate signatures on-chain, check out the [OpenZeppelin Contracts documentation](https://docs.openzeppelin.com/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`](https://docs.openzeppelin.com/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](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#EIP712-_hashTypedDataV4-bytes32-) : // contracts/MyContractDomain.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; /// @dev Unsafe contract to demonstrate the use of EIP712 and ECDSA. abstract contract MyContractDomain is EIP712 { function validateSignature( address mailTo, string memory mailContents, bytes memory signature ) internal view returns (address) { bytes32 digest = _hashTypedDataV4( keccak256(abi.encode(keccak256("Mail(address to,string contents)"), mailTo, keccak256(bytes(mailContents)))) ); return ECDSA.recover(digest, signature); } } 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](https://docs.openzeppelin.com/community-contracts/utilities#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`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#ERC7739) signer will implement the [`IERC1271`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1271) interface for validating smart contract signatures following the approach suggested by ERC-7739: // contracts/ERC7739ECDSA.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol"; contract ERC7739ECDSA is ERC7739 { address private immutable _signer; constructor(address signerAddr) EIP712("ERC7739ECDSA", "1") { _signer = signerAddr; } function _rawSignatureValidation( bytes32 hash, bytes calldata signature ) internal view virtual override returns (bool) { (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); return _signer == recovered && err == ECDSA.RecoverError.NoError; } } ### [ERC-7913 Signature Verifiers](https://docs.openzeppelin.com/community-contracts/utilities#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`](https://docs.openzeppelin.com/community-contracts/api/utils/cryptography#ERC7913Utils) provides functions for verifying signatures using ERC-7913 compatible verifiers: 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](https://docs.openzeppelin.com/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. ### On this page [Cryptography](https://docs.openzeppelin.com/community-contracts/utilities#cryptography) [Validating Typed Data Signatures](https://docs.openzeppelin.com/community-contracts/utilities#validating-typed-data-signatures) [Validating Nested EIP-712 Signatures](https://docs.openzeppelin.com/community-contracts/utilities#validating-nested-eip-712-signatures) [ERC-7913 Signature Verifiers](https://docs.openzeppelin.com/community-contracts/utilities#erc-7913-signature-verifiers) --- # Learn | OpenZeppelin Docs Learn Learn ===== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Comprehensive guides for every step of your development journey. * [Setting up a Node project](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project) - Get your Node development environment set up for using OpenZeppelin tools * [Developing smart contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts) - Learn the basics of writing Solidity contracts with OpenZeppelin * [Deploying and interacting with smart contracts](https://docs.openzeppelin.com/contracts/5.x/learn/deploying-and-interacting) - Deploy contracts to local and test networks and interact with them * [Writing automated smart contract tests](https://docs.openzeppelin.com/contracts/5.x/learn/writing-automated-tests) - Write comprehensive tests to verify your contracts work as intended * [Upgrading smart contracts](https://docs.openzeppelin.com/contracts/5.x/learn/upgrading-smart-contracts) - Modify your contract code while preserving state and address using OpenZeppelin Upgrades * [Connecting to public test networks](https://docs.openzeppelin.com/contracts/5.x/learn/connecting-to-public-test-networks) - Move from local development to persistent test environments * [Preparing for mainnet](https://docs.openzeppelin.com/contracts/5.x/learn/preparing-for-mainnet) - Security considerations and best practices for production deployment * [Building a dapp](https://docs.openzeppelin.com/contracts/5.x/learn/building-a-dapp) - Create decentralized web applications with OpenZeppelin Network JS and hot-loading * [Sending gasless transactions](https://docs.openzeppelin.com/contracts/5.x/learn/sending-gasless-transactions) - Enable meta-transactions using the Gas Station Network for better user onboarding [Contracts Wizard\ \ Previous Page](https://docs.openzeppelin.com/wizard) [Setting up a Node project\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project) --- # ERC-6909 | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) ERC-6909 ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) ERC-6909 is a draft EIP that draws on ERC-1155 learnings since it was published in 2018. The main goals of ERC-6909 is to decrease gas costs and complexity--this is mainly accomplished by removing batching and callbacks. To understand the inspiration for a multi token standard, see the [multi token standard](https://docs.openzeppelin.com/contracts/5.x/erc1155#multi-token-standard) section within the EIP-1155 docs. [Changes from ERC-1155](https://docs.openzeppelin.com/contracts/5.x/erc6909#changes-from-erc-1155) --------------------------------------------------------------------------------------------------- There are three main changes from ERC-1155 which are as follows: 1. The removal of batch operations. 2. The removal of transfer callbacks. 3. Granularization in approvals--approvals can be set globally (as operators) or as amounts per token (inspired by ERC20). [Constructing an ERC-6909 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc6909#constructing-an-erc-6909-token-contract) --------------------------------------------------------------------------------------------------------------------------------------- We’ll use ERC-6909 to track multiple items in a game, each having their own unique attributes. All item types will by minted to the deployer of the contract, which we can later transfer to players. We’ll also use the [`ERC6909Metadata`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC6909#ERC6909Metadata) extension to add decimals to our fungible items (the vanilla ERC-6909 implementation does not have decimals). For simplicity, we will mint all items in the constructor--however, minting functionality could be added to the contract to mint on demand to players. For an overview of minting mechanisms, check out [Creating ERC-20 Supply](https://docs.openzeppelin.com/contracts/5.x/erc20-supply) . Here’s what a contract for tokenized items might look like: // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC6909Metadata} from "@openzeppelin/contracts/token/ERC6909/extensions/draft-ERC6909Metadata.sol"; contract ERC6909GameItems is ERC6909Metadata { uint256 public constant GOLD = 0; uint256 public constant SILVER = 1; uint256 public constant THORS_HAMMER = 2; uint256 public constant SWORD = 3; uint256 public constant SHIELD = 4; constructor() { _setDecimals(GOLD, 18); _setDecimals(SILVER, 18); // Default decimals is 0 _setDecimals(SWORD, 9); _setDecimals(SHIELD, 9); _mint(msg.sender, GOLD, 10 ** 18); _mint(msg.sender, SILVER, 10_000 ** 18); _mint(msg.sender, THORS_HAMMER, 1); _mint(msg.sender, SWORD, 10 ** 9); _mint(msg.sender, SHIELD, 10 ** 9); } } Note that there is no content URI functionality in the base implementation, but the [`ERC6909ContentURI`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC6909#ERC6909ContentURI) extension adds it. Additionally, the base implementation does not track total supplies, but the [`ERC6909TokenSupply`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC6909#ERC6909TokenSupply) extension tracks the total supply of each token id. Once the contract is deployed, we will be able to query the deployer’s balance: > gameItems.balanceOf(deployerAddress, 3) 1000000000 We can transfer items to player accounts: > gameItems.transfer(playerAddress, 2, 1) > gameItems.balanceOf(playerAddress, 2) 1 > gameItems.balanceOf(deployerAddress, 2) 0 [ERC-4626\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc4626) [Governance\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/governance) ### On this page [Changes from ERC-1155](https://docs.openzeppelin.com/contracts/5.x/erc6909#changes-from-erc-1155) [Constructing an ERC-6909 Token Contract](https://docs.openzeppelin.com/contracts/5.x/erc6909#constructing-an-erc-6909-token-contract) --- # Polkadot Parachain Runtimes | OpenZeppelin Docs Polkadot Parachain Runtimes =========================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) A collection of secure runtime templates to build parachains more easily on Polkadot. [Runtimes](https://docs.openzeppelin.com/substrate-runtimes#runtimes) ---------------------------------------------------------------------- * [Generic Runtime Template](https://docs.openzeppelin.com/substrate-runtimes/runtimes/generic) * [EVM Runtime Template](https://docs.openzeppelin.com/substrate-runtimes/runtimes/evm) [Where to get started](https://docs.openzeppelin.com/substrate-runtimes#where-to-get-started) ---------------------------------------------------------------------------------------------- * [Quick Start](https://docs.openzeppelin.com/substrate-runtimes/guides/quick_start) : a generic parachain runtime that works out of the box. It has all the must have features, and allows further customization based on your project’s needs. Generic Runtime Template also serves as the base for our other runtime templates. * [Testing with Zombienet](https://docs.openzeppelin.com/substrate-runtimes/guides/testing_with_zombienet) : a more opinionated parachain runtime template that maximizes Ethereum compatibility by using `AccountId20` and configures a local EVM instance. You can easily migrate/deploy Solidity Smart Contracts to this one. ### On this page [Runtimes](https://docs.openzeppelin.com/substrate-runtimes#runtimes) [Where to get started](https://docs.openzeppelin.com/substrate-runtimes#where-to-get-started) --- # Using with Foundry | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) Using with Foundry ================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Foundry library for deploying and managing upgradeable contracts, which includes upgrade safety validations. [Installation](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#installation) ----------------------------------------------------------------------------------------------------- Follow one of the sections below depending on which version of OpenZeppelin Contracts you are using. OpenZeppelin Contracts v5 is required for new deployments. ### [Using OpenZeppelin Contracts v5](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#using-openzeppelin-contracts-v5) Run these commands: forge install foundry-rs/forge-std forge install OpenZeppelin/openzeppelin-foundry-upgrades forge install OpenZeppelin/openzeppelin-contracts-upgradeable Set the following in `remappings.txt`, replacing any previous definitions of these remappings: @openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/ @openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ The above remappings mean that both `@openzeppelin/contracts/` (including proxy contracts deployed by this library) and `@openzeppelin/contracts-upgradeable/` come from your installation of the `openzeppelin-contracts-upgradeable` submodule and its subdirectories, which includes its own transitive copy of `openzeppelin-contracts` of the same release version number. This format is needed for Etherscan verification to work. Particularly, any copies of `openzeppelin-contracts` that you install separately are NOT used. ### [Using OpenZeppelin Contracts v4](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#using-openzeppelin-contracts-v4) Run these commands, replacing `v4.9.6` with the specific version of OpenZeppelin Contracts that you are using: forge install foundry-rs/forge-std forge install OpenZeppelin/openzeppelin-foundry-upgrades forge install OpenZeppelin/[email protected] forge install OpenZeppelin/[email protected] Set the following in `remappings.txt`: @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ Use `LegacyUpgrades.sol` instead of `Upgrades.sol` to upgrade existing deployments that were created with OpenZeppelin Contracts v4. ### [Optional: Alternative installation methods](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#optional-alternative-installation-methods) #### [NPM](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#npm) Follow the steps above, but instead of running `forge install OpenZeppelin/openzeppelin-foundry-upgrades`, use this command instead: npm install @openzeppelin/foundry-upgrades Then add the following additional line to `remappings.txt`, in addition to the ones described above: openzeppelin-foundry-upgrades/=node_modules/@openzeppelin/foundry-upgrades/src/ #### [Soldeer](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#soldeer) Follow the steps above, but instead of running `forge install OpenZeppelin/openzeppelin-foundry-upgrades`, use one of the install commands described in [https://soldeer.xyz/project/openzeppelin-foundry-upgrades](https://soldeer.xyz/project/openzeppelin-foundry-upgrades) Then add the following additional line to `remappings.txt`, in addition to the ones described above (replace `0.3.6` with the version of the plugin that you installed): openzeppelin-foundry-upgrades/=dependencies/openzeppelin-foundry-upgrades-0.3.6/src/ [Foundry Requirements](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#foundry-requirements) --------------------------------------------------------------------------------------------------------------------- This library requires [forge-std](https://github.com/foundry-rs/forge-std) version 1.9.5 or higher. [Before Running](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#before-running) --------------------------------------------------------------------------------------------------------- This library uses the [OpenZeppelin Upgrades CLI](https://docs.openzeppelin.com/upgrades-plugins/api-core) for upgrade safety validations, which are run by default during deployments and upgrades. If you want to be able to run upgrade safety validations, the following are needed: 1. Install [Node.js](https://nodejs.org/) . 2. Configure your `foundry.toml` to enable ffi, ast, build info and storage layout: [profile.default] ffi = true ast = true build_info = true extra_output = ["storageLayout"] 1. If you are upgrading your contract from a previous version, add the `@custom:oz-upgrades-from ` annotation to the new version of your contract according to [Define Reference Contracts](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-reference-contracts) or specify the `referenceContract` option when calling the library’s functions. 2. Run `forge clean` before running your Foundry script or tests, or include the `--force` option when running `forge script` or `forge test`. If you do not want to run upgrade safety validations, you can skip the above steps and use the [`unsafeSkipAllChecks` option](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Options) when calling the `Upgrades` library’s functions, or use the `UnsafeUpgrades` library instead. Note that these are dangerous options meant to be used as a last resort. ### [Optional: Custom output directory](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#optional-custom-output-directory) By default, this library assumes your Foundry output directory is set to "out". If you want to use a custom output directory, set it in your `foundry.toml` and provide read permissions for the directory. For example (replace `my-output-dir` with the directory that you want to use): [profile.default] out = "my-output-dir" fs_permissions = [{ access = "read", path = "my-output-dir" }] Then in a `.env` at your project root, set the `FOUNDRY_OUT` environment variable to match the custom output directory, for example: FOUNDRY_OUT=my-output-dir ### [Windows environments](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#windows-environments) If you are using Windows, set the `OPENZEPPELIN_BASH_PATH` environment variable to the fully qualified path of the `bash` executable. For example, if you are using [Git for Windows](https://gitforwindows.org/) , add the following line in the `.env` file of your project (using forward slashes): OPENZEPPELIN_BASH_PATH="C:/Program Files/Git/bin/bash" [Usage](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#usage) --------------------------------------------------------------------------------------- Depending on which major version of OpenZeppelin Contracts you are using, and whether you want to run upgrade safety validations and/or use OpenZeppelin Defender, use the table below to determine which library to import: | | OpenZeppelin Contracts v5 | OpenZeppelin Contracts v4 | | --- | --- | --- | | **Runs validations, supports Defender** | `import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";` | `import {Upgrades} from "openzeppelin-foundry-upgrades/LegacyUpgrades.sol";` | | **No validations, does not support Defender** | `import {UnsafeUpgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";` | `import {UnsafeUpgrades} from "openzeppelin-foundry-upgrades/LegacyUpgrades.sol";` | Import one of the above libraries in your Foundry scripts or tests, for example: import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; Also import the implementation contract that you want to validate, deploy, or upgrade to, for example: import {MyToken} from "src/MyToken.sol"; Then call functions from the imported library to run validations, deployments, or upgrades. [Examples](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#examples) --------------------------------------------------------------------------------------------- The following examples assume you are using OpenZeppelin Contracts v5 and want to run upgrade safety validations. ### [Deploy a proxy](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#deploy-a-proxy) Deploy a UUPS proxy: address proxy = Upgrades.deployUUPSProxy( "MyContract.sol", abi.encodeCall(MyContract.initialize, ("arguments for the initialize function")) ); Deploy a transparent proxy: address proxy = Upgrades.deployTransparentProxy( "MyContract.sol", INITIAL_OWNER_ADDRESS_FOR_PROXY_ADMIN, abi.encodeCall(MyContract.initialize, ("arguments for the initialize function")) ); Deploy an upgradeable beacon and a beacon proxy: address beacon = Upgrades.deployBeacon("MyContract.sol", INITIAL_OWNER_ADDRESS_FOR_BEACON); address proxy = Upgrades.deployBeaconProxy( beacon, abi.encodeCall(MyContract.initialize, ("arguments for the initialize function")) ); ### [Use your contract](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#use-your-contract) Call your contract’s functions as normal, but remember to always use the proxy address: MyContract instance = MyContract(proxy); instance.myFunction(); ### [Upgrade a proxy or beacon](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#upgrade-a-proxy-or-beacon) Upgrade a transparent or UUPS proxy and call an arbitrary function (such as a reinitializer) during the upgrade process: Upgrades.upgradeProxy( transparentProxy, "MyContractV2.sol", abi.encodeCall(MyContractV2.foo, ("arguments for foo")) ); Upgrade a transparent or UUPS proxy without calling any additional function: Upgrades.upgradeProxy( transparentProxy, "MyContractV2.sol", "" ); Upgrade a beacon: Upgrades.upgradeBeacon(beacon, "MyContractV2.sol"); When upgrading a proxy or beacon, ensure that the new contract either has its `@custom:oz-upgrades-from ` annotation set to the name of the old implementation contract used by the proxy or beacon, or set it with the `referenceContract` option, for example: Options memory opts; opts.referenceContract = "MyContractV1.sol"; Upgrades.upgradeProxy(proxy, "MyContractV2.sol", "", opts); // or Upgrades.upgradeBeacon(beacon, "MyContractV2.sol", opts); If possible, keep the old version of the implementation contract’s source code somewhere in your project to use as a reference as above. This requires the new version to be in a different directory, Solidity file, or using a different contract name. Otherwise, if you want to use the same directory and name for the new version, keep the build info directory from the previous deployment (or build it from an older branch of your project repository) and reference it as follows: Options memory opts; opts.referenceBuildInfoDir = "/old-builds/build-info-v1"; opts.referenceContract = "build-info-v1:MyContract"; Upgrades.upgradeProxy(proxy, "MyContract.sol", "", opts); // or Upgrades.upgradeBeacon(beacon, "MyContract.sol", opts); [Coverage Testing](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#coverage-testing) ------------------------------------------------------------------------------------------------------------- To enable code coverage reports with `forge coverage`, use the following deployment pattern in your tests: instantiate your implementation contracts directly and use the `UnsafeUpgrades` library. For example: address implementation = address(new MyContract()); address proxy = UnsafeUpgrades.deployUUPSProxy( implementation, abi.encodeCall(MyContract.initialize, ("arguments for the initialize function")) ); `UnsafeUpgrades` is not recommended for use in Forge scripts. It does not validate whether your contracts are upgrade safe or whether new implementations are compatible with previous ones. Ensure you run validations before any actual deployments or upgrades, such as by using the `Upgrades` library in scripts. [Deploying and Verifying](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#deploying-and-verifying) --------------------------------------------------------------------------------------------------------------------------- Run your script with `forge script` to broadcast and deploy. See Foundry’s [Solidity Scripting](https://book.getfoundry.sh/guides/scripting-with-solidity) guide. Include the `--sender
` flag for the `forge script` command when performing upgrades, specifying an address that owns the proxy or proxy admin. Otherwise, `OwnableUnauthorizedAccount` errors will occur. Include the `--verify` flag for the `forge script` command if you want to verify source code such as on Etherscan. This will verify your implementation contracts along with any proxy contracts as part of the deployment. [Usage with Defender](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#usage-with-defender) ------------------------------------------------------------------------------------------------------------------- If you are using OpenZeppelin Defender, see [OpenZeppelin Defender with Foundry](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-defender) for how to use it for deployments. [API](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#api) ----------------------------------------------------------------------------------- See [Foundry Upgrades API](https://docs.openzeppelin.com/upgrades-plugins/foundry/api) for the full API documentation. ### On this page [Installation](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#installation) [Using OpenZeppelin Contracts v5](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#using-openzeppelin-contracts-v5) [Using OpenZeppelin Contracts v4](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#using-openzeppelin-contracts-v4) [Optional: Alternative installation methods](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#optional-alternative-installation-methods) [NPM](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#npm) [Soldeer](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#soldeer) [Foundry Requirements](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#foundry-requirements) [Before Running](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#before-running) [Optional: Custom output directory](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#optional-custom-output-directory) [Windows environments](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#windows-environments) [Usage](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#usage) [Examples](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#examples) [Deploy a proxy](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#deploy-a-proxy) [Use your contract](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#use-your-contract) [Upgrade a proxy or beacon](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#upgrade-a-proxy-or-beacon) [Coverage Testing](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#coverage-testing) [Deploying and Verifying](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#deploying-and-verifying) [Usage with Defender](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#usage-with-defender) [API](https://docs.openzeppelin.com/upgrades-plugins/foundry/foundry-upgrades#api) --- # Networks | OpenZeppelin Docs UI Builder Networks ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Supported Networks](https://docs.openzeppelin.com/ui-builder/networks#supported-networks) ------------------------------------------------------------------------------------------- Currently the Contracts UI Builder supports the following EVM networks **Mainnet** * Ethereum * Arbitrum One * Base * Polygon * Polygon zkEVM * BNB Smart Chain * OP Mainnet * Avalanche C-Chain * Linea * Scroll * ZkSync Era **Testnet** * Sepolia * Arbitrum Sepolia * Base Sepolia * Polygon Amoy * Polygon zkEVM Cardona * BSC Testnet * OP Sepolia * Avalanche Fuji C-Chain * Linea Sepolia * Scroll Sepolia * ZkSync Era Sepolia Midnight, Stellar, and Solana are planned to be supported in the future [Network Configs](https://docs.openzeppelin.com/ui-builder/networks#network-configs) ------------------------------------------------------------------------------------- Each network can be configured to use custom RPCs, Explorers, and Explorer APIs. To open the network configuration modal, click on the settings icon on the right side of a network. ![Networks config button](https://docs.openzeppelin.com/ui-builder/networks-config-button.png) In this modal you can configure a custom RPC URL which can include path API key authorization ![Networks RPC settings](https://docs.openzeppelin.com/ui-builder/networks-rpc-settings.png) Under the explorer tab you can configure block explorers like Etherscan. By default the Contracts UI Builder uses public APIs that can be rate limited, so be sure to provide your own API key if that becomes an issue. ![Networks explorer settings](https://docs.openzeppelin.com/ui-builder/networks-explorer-settings.png) You can also toggle advance settings to use a custom block explorer setup. ![Networks advance settings](https://docs.openzeppelin.com/ui-builder/networks-advance-settings.png) ### On this page [Supported Networks](https://docs.openzeppelin.com/ui-builder/networks#supported-networks) [Network Configs](https://docs.openzeppelin.com/ui-builder/networks#network-configs) --- # OpenZeppelin Foundry Upgrades API | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) OpenZeppelin Foundry Upgrades API ================================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Contract name formats](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#contract-name-formats) ---------------------------------------------------------------------------------------------------------- Contract names must be provided in specific formats depending on context. The following are the required formats for each context: ### [Foundry artifact format](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#foundry-artifact-format) Contexts: * `contractName` parameter * `referenceContract` option if `referenceBuildInfoDir` option is not set Can be in any of the following forms according to Foundry's [getCode](https://book.getfoundry.sh/cheatcodes/get-code) cheatcode: * the Solidity file name, e.g. `ContractV1.sol` * the Solidity file name and the contract name, e.g. `ContractV1.sol:ContractV1` * the artifact path relative to the project root directory, e.g. `out/ContractV1.sol/ContractV1.json` ### [Annotation format](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#annotation-format) Contexts: * `@custom:oz-upgrades-from ` annotation * `referenceContract` option if `referenceBuildInfoDir` option is set Can be in any of the following forms according to the [OpenZeppelin Upgrades CLI](https://docs.openzeppelin.com/upgrades-plugins/api-core#define-reference-contracts) : * the contract name, e.g. `ContractV1` * fully qualified contract name, e.g. `contracts/tokens/ContractV1.sol:ContractV1` If the `referenceBuildInfoDir` option is set, include the build info directory short name as a prefix, resulting in one of the following forms: * the build info directory short name and the contract name, e.g. `build-info-v1:ContractV1` * the build info directory short name and the fully qualified contract name, e.g. `build-info-v1:contracts/tokens/ContractV1.sol:ContractV1` [Core Libraries](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#core-libraries) -------------------------------------------------------------------------------------------- ### [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#upgrades) [Upgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Upgrades) Library for deploying and managing upgradeable contracts from Forge scripts or tests. Requires OpenZeppelin Contracts v5 or higher. ### [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#legacyupgrades) [LegacyUpgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/LegacyUpgrades) Library for managing upgradeable contracts from Forge scripts or tests. Only for upgrading existing deployments using OpenZeppelin Contracts v4. ### [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#defender) [Defender](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Defender) Library for interacting with OpenZeppelin Defender from Forge scripts or tests. ### [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#options) [Options](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Options) Configuration options and structs used throughout the Upgrades libraries. ### On this page [Contract name formats](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#contract-name-formats) [Foundry artifact format](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#foundry-artifact-format) [Annotation format](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#annotation-format) [Core Libraries](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#core-libraries) [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#upgrades) [Upgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Upgrades) [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#legacyupgrades) [LegacyUpgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/LegacyUpgrades) [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#defender) [Defender](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Defender) [](https://docs.openzeppelin.com/upgrades-plugins/foundry/api#options) [Options](https://docs.openzeppelin.com/upgrades-plugins/foundry/api/Options) --- # Confidential Contracts | OpenZeppelin Docs Confidential Contracts ====================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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](https://docs.openzeppelin.com/confidential-contracts#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](https://docs.openzeppelin.com/cdn-cgi/l/email-protection#d6a5b3b5a3a4bfa2af96b9a6b3b8acb3a6a6b3babfb8f8b9a4b1) . 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. ### On this page [Security](https://docs.openzeppelin.com/confidential-contracts#security) --- # Loading Contracts | OpenZeppelin Docs UI Builder Loading Contracts ================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) After you have selected your chain you can paste in the deployed contract address. After providing the contract address the UI Builder will try to use public block explorer APIs to fetch the contract ABIs. This will only work if the contract is verified. If you experience rate or usage limits with the public block explorers [configure the network to use an API key](https://docs.openzeppelin.com/ui-builder/networks) ![Contracts ABI auto loading](https://docs.openzeppelin.com/ui-builder/contracts-abi-auto.png) If your contract is not verified you can still provide the ABI manually. ![Contracts ABI manual input](https://docs.openzeppelin.com/ui-builder/contracts-abi-manual.png) Once a contract and it’s ABI is loaded the UI Builder will automatically fetch the state of the contract, which can be toggled if you wish to hide it ![Contracts state display](https://docs.openzeppelin.com/ui-builder/contracts-state.png) --- # Upgrades | OpenZeppelin Docs Upgrades ======== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) OpenZeppelin provides tooling for deploying and securing upgradeable smart contracts. * [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) to deploy upgradeable contracts with automated security checks. * [Upgradeable Contracts](https://docs.openzeppelin.com/contracts/5.x/upgradeable) to build your contract using our Solidity components. Find all of our resources related to upgradeability below. If you don't know where to start we suggest to start with [**Learn: Upgrading Smart Contracts**](https://docs.openzeppelin.com/contracts/5.x/learn/upgrading-smart-contracts) . [Resources](https://docs.openzeppelin.com/upgrades#resources) -------------------------------------------------------------- [### Writing Upgradeable Contracts\ \ When working with upgradeable contracts using OpenZeppelin Upgrades, there are a few minor caveats to keep in mind when writing your Solidity code.](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable) [### Proxy Contracts\ \ A complete list of all available proxy contracts and related utilities, with documentation relevant for low-level use without Upgrades Plugins.](https://docs.openzeppelin.com/contracts/5.x/api/proxy) [### The State of Smart Contract Upgrades\ \ A survey of upgrade patterns, and good practices and recommendations for upgrades management and governance.](https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades) [### Transparent vs UUPS Proxies\ \ Explaining the differences between the Transparent Proxy Pattern and the newly available UUPS Proxies.](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups-proxies) [### UUPS Proxies\ \ A tutorial on using the UUPS proxy pattern: what the Solidity code should look like, and how to use the Upgrades Plugins with this new proxy pattern.](https://forum.openzeppelin.com/t/uups-proxies-tutorial-solidity-javascript/7786) ### On this page [Resources](https://docs.openzeppelin.com/upgrades#resources) --- # Quick Start Guide | OpenZeppelin Docs Relayer Quick Start Guide ================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This guide provides step-by-step instructions for setting up OpenZeppelin Relayer. It includes prerequisites, installation, and configuration examples. [Prerequisites](https://docs.openzeppelin.com/relayer/quickstart#prerequisites) -------------------------------------------------------------------------------- * Rust 2021, version `1.86` or later. * Redis * Docker (optional, for containerized deployment) * Node.js, typescript and ts-node (optional, for plugins) [Configuration](https://docs.openzeppelin.com/relayer/quickstart#configuration) -------------------------------------------------------------------------------- ### [Step 1: Clone the Repository](https://docs.openzeppelin.com/relayer/quickstart#step-1-clone-the-repository) Clone the repository and navigate to the project directory: git clone https://github.com/OpenZeppelin/openzeppelin-relayer cd openzeppelin-relayer ### [Step 2: Create Configuration Files](https://docs.openzeppelin.com/relayer/quickstart#step-2-create-configuration-files) Create environment configuration: cp .env.example .env These files are already partially configured. We will add missing data in next steps. Ready-to-Use Example Configurations For quick setup with various configurations, check the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository: ### [Step 3: Create a Signer](https://docs.openzeppelin.com/relayer/quickstart#step-3-create-a-signer) Generate a new signer keystore for the basic example: cargo run --example create_key -- \ --password \ --output-dir examples/basic-example/config/keys \ --filename local-signer.json Replace `` with a strong password. Your password must contain at least: * 12 characters * One uppercase letter * One lowercase letter * One number * One special character Next, update the `KEYSTORE_PASSPHRASE` in `.env` with the password you used above. ### [Step 4: Configure Notifications](https://docs.openzeppelin.com/relayer/quickstart#step-4-configure-notifications) #### [Configure Webhook URL](https://docs.openzeppelin.com/relayer/quickstart#configure-webhook-url) Edit the file `config/config.json` and update the `notifications[0].url` field with your webhook URL. For a quick test, you can use a temporary URL from [Webhook.site](https://webhook.site/) . #### [Configure Webhook Signing Key](https://docs.openzeppelin.com/relayer/quickstart#configure-webhook-signing-key) Generate a webhook signing key: cargo run --example generate_uuid Alternatively, you can use any online UUID generator tool if you don’t want to run the included command. Copy the generated UUID and update the `WEBHOOK_SIGNING_KEY` entry in `.env`. ### [Step 5: Configure API Key](https://docs.openzeppelin.com/relayer/quickstart#step-5-configure-api-key) Generate an API key signing key for development: cargo run --example generate_uuid You can also use UUID generator with a simple command on your terminal. uuidgen Alternatively, you can use any online UUID generator tool. Copy the generated UUID and update the `API_KEY` entry in `.env`. ### [Step 6: Run the Service](https://docs.openzeppelin.com/relayer/quickstart#step-6-run-the-service) #### [Local](https://docs.openzeppelin.com/relayer/quickstart#local) Run Redis container: docker run --name openzeppelin-redis \ -p 6379:6379 \ -d redis:latest Run Relayer service: cargo run #### [Docker](https://docs.openzeppelin.com/relayer/quickstart#docker) Building and Running the docker image: docker compose up -d By default docker compose command uses `Dockerfile.development` to build the image. If you want to use `Dockerfile.production`, you can use the following command: DOCKERFILE=Dockerfile.production docker compose up -d ### [Step 7: Test the Relayer](https://docs.openzeppelin.com/relayer/quickstart#step-7-test-the-relayer) Verify the service by sending a GET request: curl -X GET http://localhost:8080/api/v1/relayers \ -H "Content-Type: application/json" \ -H "AUTHORIZATION: Bearer YOUR_API_KEY" Replace `YOUR_API_KEY` with the API key you configured in your `.env` file. Expected Result: A successful request should return an HTTP 200 status code along with the list of relayers. [Using the relayer through the API](https://docs.openzeppelin.com/relayer/quickstart#using-the-relayer-through-the-api) ------------------------------------------------------------------------------------------------------------------------ For detailed API usage, refer to the [API Reference](https://docs.openzeppelin.com/relayer/api) page. [Using the relayer through the SDK](https://docs.openzeppelin.com/relayer/quickstart#using-the-relayer-through-the-sdk) ------------------------------------------------------------------------------------------------------------------------ For documentation and examples on how to consume Relayer service via SDK check [SDK documentation](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk) . [Additional Resources and Troubleshooting](https://docs.openzeppelin.com/relayer/quickstart#additional-resources-and-troubleshooting) -------------------------------------------------------------------------------------------------------------------------------------- Troubleshooting: If you encounter issues during setup or deployment, verify your environment variables, check container logs, and review your configuration files for syntax errors. [Overview\ \ Previous Page](https://docs.openzeppelin.com/relayer) [Overview\ \ Next Page](https://docs.openzeppelin.com/relayer/configuration) ### On this page [Prerequisites](https://docs.openzeppelin.com/relayer/quickstart#prerequisites) [Configuration](https://docs.openzeppelin.com/relayer/quickstart#configuration) [Step 1: Clone the Repository](https://docs.openzeppelin.com/relayer/quickstart#step-1-clone-the-repository) [Step 2: Create Configuration Files](https://docs.openzeppelin.com/relayer/quickstart#step-2-create-configuration-files) [Step 3: Create a Signer](https://docs.openzeppelin.com/relayer/quickstart#step-3-create-a-signer) [Step 4: Configure Notifications](https://docs.openzeppelin.com/relayer/quickstart#step-4-configure-notifications) [Configure Webhook URL](https://docs.openzeppelin.com/relayer/quickstart#configure-webhook-url) [Configure Webhook Signing Key](https://docs.openzeppelin.com/relayer/quickstart#configure-webhook-signing-key) [Step 5: Configure API Key](https://docs.openzeppelin.com/relayer/quickstart#step-5-configure-api-key) [Step 6: Run the Service](https://docs.openzeppelin.com/relayer/quickstart#step-6-run-the-service) [Local](https://docs.openzeppelin.com/relayer/quickstart#local) [Docker](https://docs.openzeppelin.com/relayer/quickstart#docker) [Step 7: Test the Relayer](https://docs.openzeppelin.com/relayer/quickstart#step-7-test-the-relayer) [Using the relayer through the API](https://docs.openzeppelin.com/relayer/quickstart#using-the-relayer-through-the-api) [Using the relayer through the SDK](https://docs.openzeppelin.com/relayer/quickstart#using-the-relayer-through-the-sdk) [Additional Resources and Troubleshooting](https://docs.openzeppelin.com/relayer/quickstart#additional-resources-and-troubleshooting) --- # Creating ERC-20 Supply | OpenZeppelin Docs OpenZeppelin Contracts[Tokens](https://docs.openzeppelin.com/contracts/5.x/tokens) [ERC-20](https://docs.openzeppelin.com/contracts/5.x/erc20) Creating ERC-20 Supply ====================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) In this guide, you will learn how to create an ERC-20 token with a custom supply mechanism. We will showcase two idiomatic ways to use OpenZeppelin Contracts for this purpose that you will be able to apply to your smart contract development practice. The standard interface implemented by tokens built on Ethereum is called ERC-20, and Contracts includes a widely used implementation of it: the aptly named [`ERC20`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20) contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try to deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply? The way that supply is created is not defined in the ERC-20 document. Every token is free to experiment with its own mechanisms, ranging from the most decentralized to the most centralized, from the most naive to the most researched, and more. [Fixed Supply](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#fixed-supply) -------------------------------------------------------------------------------------- Let’s say we want a token with a fixed supply of 1000, initially allocated to the account that deploys the contract. If you’ve used Contracts v1, you may have written code like the following: contract ERC20FixedSupply is ERC20 { constructor() { totalSupply += 1000; balances[msg.sender] += 1000; } } Starting with Contracts v2, this pattern is not only discouraged, but disallowed. The variables `totalSupply` and `balances` are now private implementation details of `ERC20`, and you can’t directly write to them. Instead, there is an internal [`_mint`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-_mint-address-uint256-) function that will do exactly this: contract ERC20FixedSupply is ERC20 { constructor() ERC20("Fixed", "FIX") { _mint(msg.sender, 1000); } } Encapsulating state like this makes it safer to extend contracts. For instance, in the first example we had to manually keep the `totalSupply` in sync with the modified balances, which is easy to forget. In fact, we omitted something else that is also easily forgotten: the `Transfer` event that is required by the standard, and which is relied on by some clients. The second example does not have this bug, because the internal `_mint` function takes care of it. [Rewarding Miners](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#rewarding-miners) ---------------------------------------------------------------------------------------------- The internal [`_mint`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-_mint-address-uint256-) function is the key building block that allows us to write ERC-20 extensions that implement a supply mechanism. The mechanism we will implement is a token reward for the miners that produce Ethereum blocks. In Solidity, we can access the address of the current block’s miner in the global variable `block.coinbase`. We will mint a token reward to this address whenever someone calls the function `mintMinerReward()` on our token. The mechanism may sound silly, but you never know what kind of dynamic this might result in, and it’s worth analyzing and experimenting with! contract ERC20WithMinerReward is ERC20 { constructor() ERC20("Reward", "RWD") {} function mintMinerReward() public { _mint(block.coinbase, 1000); } } As we can see, `_mint` makes it super easy to do this correctly. [Automating the Reward](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#automating-the-reward) -------------------------------------------------------------------------------------------------------- So far our supply mechanism was triggered manually, but `ERC20` also allows us to extend the core functionality of the token through the [`_update`](https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#ERC20-_update-address-address-uint256-) function. Adding to the supply mechanism from the previous section, we can use this function to mint a miner reward for every token transfer that is included in the blockchain. // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract ERC20WithAutoMinerReward is ERC20 { constructor() ERC20("Reward", "RWD") { _mintMinerReward(); } function _mintMinerReward() internal { _mint(block.coinbase, 1000); } function _update(address from, address to, uint256 value) internal virtual override { if (!(from == address(0) && to == block.coinbase)) { _mintMinerReward(); } super._update(from, to, value); } } [Wrapping Up](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#wrapping-up) ------------------------------------------------------------------------------------ We’ve seen how to implement an ERC-20 supply mechanism: internally through `_mint`. Hopefully this has helped you understand how to use OpenZeppelin Contracts and some of the design principles behind it, and you can apply them to your own smart contracts. [Overview\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/erc20) [ERC-721\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/erc721) ### On this page [Fixed Supply](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#fixed-supply) [Rewarding Miners](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#rewarding-miners) [Automating the Reward](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#automating-the-reward) [Wrapping Up](https://docs.openzeppelin.com/contracts/5.x/erc20-supply#wrapping-up) --- # Functions | OpenZeppelin Docs UI Builder Functions ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Once you have provided your contract information you can choose which function you would like to build a form for. At the moment forms are limited to a single function. Since contract state is included by default only write functions are available for forms. ![Functions select interface](https://docs.openzeppelin.com/ui-builder/functions-select.png) By using the information from the ABI the UI Builder will preview what functions are available and what the parameters are for each of them. If you don’t see your function listed be sure to check the ABI and the original contract --- # Customization | OpenZeppelin Docs UI Builder Customization ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Once you have selected the function you want to build a form for, you can finally customize the experience the form will take. [General Settings](https://docs.openzeppelin.com/ui-builder/customization#general-settings) -------------------------------------------------------------------------------------------- In the general settings you can update the name of the form and a custom description to help clarify it’s purpose ![Customization general settings](https://docs.openzeppelin.com/ui-builder/customization-general.png) [Fields](https://docs.openzeppelin.com/ui-builder/customization#fields) ------------------------------------------------------------------------ The fields section will let you customize how someone might interact with your form. This can be incredibly useful if you need to provide a better UX for values to fill in. You can also make certain fields or values hard coded into the form and only give users the option to execute the function. All of these are available so you can craft an experience for yourself or for someone who is non-technical and might need guidance on what to add. ![Customization fields](https://docs.openzeppelin.com/ui-builder/customization-fields.png) [Execution Method](https://docs.openzeppelin.com/ui-builder/customization#execution-method) -------------------------------------------------------------------------------------------- When it comes to how the form is executed as a transaction there are several options. These execution method restrictions only apply on the client form, NOT the contract itself. Make sure your contract has secure access controls in place! ### [EOA](https://docs.openzeppelin.com/ui-builder/customization#eoa) The EOA method allows a user to connect their wallet and execute on the form. You can also specify if anyone can connect or just one specific address. ![Customization EOA settings](https://docs.openzeppelin.com/ui-builder/customization-eoa.png) ### [OpenZeppelin Relayer](https://docs.openzeppelin.com/ui-builder/customization#openzeppelin-relayer) Forms can also be configured to be executed by an OpenZeppelin Relayer by providing the service URL and an API key for the relayer. From there you can select which of the available relayers to use. ![Customization relayer settings](https://docs.openzeppelin.com/ui-builder/customization-relayer.png) [Multisig (coming soon)](https://docs.openzeppelin.com/ui-builder/customization#multisig-coming-soon) ------------------------------------------------------------------------------------------------------ Multisig services like Safe, Squads, etc. will be available in the near future! ![Customization multisig settings](https://docs.openzeppelin.com/ui-builder/customization-multisig.png) [Wallet UI Kit](https://docs.openzeppelin.com/ui-builder/customization#wallet-ui-kit) -------------------------------------------------------------------------------------- If you are using an EOA execution method you can customize the wallet connection experience. You can do this by using the OpenZeppelin setup which requires no additional configuration: ![Customization wallet UI settings](https://docs.openzeppelin.com/ui-builder/customization-wallet-ui.png) Of you can use RainbowKit which will require the additional RainbowKit config to be added to your final app. ![Customization Rainbow Kit settings](https://docs.openzeppelin.com/ui-builder/customization-rainbow.png) [Form Previews](https://docs.openzeppelin.com/ui-builder/customization#form-previews) -------------------------------------------------------------------------------------- At any time during the customization phase you can open up the preview for your form to see what the final product will look like. ![Customization preview button](https://docs.openzeppelin.com/ui-builder/customization-preview-button.png) In the preview you can also test the interaction by connecting your wallet and using it! ![Customization preview usage](https://docs.openzeppelin.com/ui-builder/customization-preview-usage.png) ![Customization preview transaction](https://docs.openzeppelin.com/ui-builder/customization-preview-tx.png) ### On this page [General Settings](https://docs.openzeppelin.com/ui-builder/customization#general-settings) [Fields](https://docs.openzeppelin.com/ui-builder/customization#fields) [Execution Method](https://docs.openzeppelin.com/ui-builder/customization#execution-method) [EOA](https://docs.openzeppelin.com/ui-builder/customization#eoa) [OpenZeppelin Relayer](https://docs.openzeppelin.com/ui-builder/customization#openzeppelin-relayer) [Multisig (coming soon)](https://docs.openzeppelin.com/ui-builder/customization#multisig-coming-soon) [Wallet UI Kit](https://docs.openzeppelin.com/ui-builder/customization#wallet-ui-kit) [Form Previews](https://docs.openzeppelin.com/ui-builder/customization#form-previews) --- # Exporting and History | OpenZeppelin Docs UI Builder Exporting and History ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Once you have completed customizing your form it’s ready to ship! There are a few ways you can export and save previous UIs. [Exporting](https://docs.openzeppelin.com/ui-builder/exporting-and-history#exporting) -------------------------------------------------------------------------------------- On the last step of the UI builder you can click the export button to download a zip file of your form as a VIte + React project. ![Exporting export button](https://docs.openzeppelin.com/ui-builder/exporting-export-button.png) After the download is complete, unzip the project and install dependencies and build the project. pnpm install && pnpm build Once the build is complete run the dev server to see the form locally. pnpm dev [History](https://docs.openzeppelin.com/ui-builder/exporting-and-history#history) ---------------------------------------------------------------------------------- As you use the Contracts UI Builder the app will store a local history of all the forms you’ve built which can be see in the sidebar. ![Exporting history contracts](https://docs.openzeppelin.com/ui-builder/exporting-history-contracts.png) By clicking on the three small dots you can rename, duplicate, download, or delete templates from your history. There is also the ability to backup and restore histories as JSON files by clicking on the `Download` button on the sidebar. ![Exporting history save configs](https://docs.openzeppelin.com/ui-builder/exporting-history-save-configs.png) ### On this page [Exporting](https://docs.openzeppelin.com/ui-builder/exporting-and-history#exporting) [History](https://docs.openzeppelin.com/ui-builder/exporting-and-history#history) --- # Transaction Proposals | OpenZeppelin Docs DefenderModules Transaction Proposals ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Transaction Proposals are very similar to actions, but instead of having to write the javascript code, you can use a form-based editor to define the transaction parameters. This low-code format is very useful for non technical users and simple scenarios, but lacks the flexibility of the Actions. If you need to invoke external APIs or contracts, or perform more complex logic, you should use the [Actions](https://docs.openzeppelin.com/defender/module/actions) instead. [General Information](https://docs.openzeppelin.com/defender/module/transaction-proposals#general-information) --------------------------------------------------------------------------------------------------------------- To create a Transaction Proposal from Defender, you need to define a few parameters: * Title: A descriptive name for the proposal. This will be latter shown in the proposal list. * Description(optional): A longer description of the proposal. This will be shown in the proposal details. * Target Contract: The smart contract that you want to run the transaction on. If you have trouble connecting your wallet to Defender, there may be a conflict between wallet extensions if multiple are installed. [Function](https://docs.openzeppelin.com/defender/module/transaction-proposals#function) ----------------------------------------------------------------------------------------- Define the function that you want to call on the target contract. You can select from a list of functions that are available on the contract interface. If the function has parameters, you can define them here. [Approval Process](https://docs.openzeppelin.com/defender/module/transaction-proposals#approval-process) --------------------------------------------------------------------------------------------------------- Define how you want the transaction to be executed. You can choose from any of the [transaction approval processes](https://docs.openzeppelin.com/defender/settings#approval-processes) available in Defender that you have previously configured or you can optionally create a new one. [Actions\ \ Previous Page](https://docs.openzeppelin.com/defender/module/actions) [Address Book\ \ Next Page](https://docs.openzeppelin.com/defender/module/address-book) ### On this page [General Information](https://docs.openzeppelin.com/defender/module/transaction-proposals#general-information) [Function](https://docs.openzeppelin.com/defender/module/transaction-proposals#function) [Approval Process](https://docs.openzeppelin.com/defender/module/transaction-proposals#approval-process) --- # Building New Adapters | OpenZeppelin Docs UI Builder Building New Adapters ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document provides a comprehensive overview of the Contracts UI Builder’s architecture, with a focus on the patterns and requirements for creating new ecosystem adapters. It’s intended for developers tasked with extending the platform to support new blockchains. [Core Architecture: The Adapter Pattern](https://docs.openzeppelin.com/ui-builder/building-adapters#core-architecture-the-adapter-pattern) ------------------------------------------------------------------------------------------------------------------------------------------- The entire system is built around a **domain-driven adapter pattern**. The goal is to keep the main application (`packages/builder`) and the UI rendering library (`packages/renderer`) completely **chain-agnostic**. They have no direct knowledge of how to interact with a specific blockchain like EVM or Solana. This decoupling is achieved through the `ContractAdapter` interface, defined in `packages/types/src/adapters/base.ts`. Each supported blockchain ecosystem must have its own package (e.g., `packages/adapter-evm`) that exports a class implementing this interface. **Key Principles:** * **Separation of Concerns**: Chain-specific logic is entirely encapsulated within its adapter package. * **Shared Type System**: `packages/types` serves as the single source of truth for all shared data structures, ensuring type safety across the entire monorepo. * **Network-Aware Adapters**: An adapter instance is not generic; it is **instantiated with a specific `NetworkConfig` object**. This makes the instance aware of its target network (e.g., Ethereum Mainnet vs. Sepolia Testnet), including its RPC endpoints, explorer URLs, and chain identifiers. The adapter stores this `networkConfig` internally and uses it for all network-dependent operations. [The `ContractAdapter` Interface: Your Implementation Contract](https://docs.openzeppelin.com/ui-builder/building-adapters#the-contractadapter-interface-your-implementation-contract) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The `ContractAdapter` interface is the most critical file for an adapter developer. Your new adapter class **must** implement every method defined here. The methods can be grouped by functionality: ### [Contract Definition & Schema Handling](https://docs.openzeppelin.com/ui-builder/building-adapters#contract-definition--schema-handling) These methods handle loading and interpreting a contract’s interface (like an ABI or IDL). * `getContractDefinitionInputs()`: Must return a `FormFieldType[]` array that defines the inputs your adapter needs to locate a contract (e.g., an address field, an optional ABI/IDL textarea). * `loadContract(artifacts)`: Takes the form values from `getContractDefinitionInputs` and returns a `ContractSchema`. This is your main entry point for fetching and parsing the contract’s interface. You’ll handle logic here like: "If a manual ABI is provided, parse it. If not, use the address to fetch it from a block explorer." * `loadContractWithMetadata(artifacts)`: An enhanced version of `loadContract` that also returns metadata about the source (`fetched` or `manual`), proxy information (`ProxyInfo`), and definition details (`ContractDefinitionMetadata`). This is used for advanced features like ABI comparison and proxy detection. * `validateContractDefinition(definition)` & `hashContractDefinition(definition)`: (Optional) Implement these to support ABI/IDL validation and version comparison features. The EVM adapter provides a reference implementation in `abi/comparison.ts`. ### [Form Generation & Type Mapping](https://docs.openzeppelin.com/ui-builder/building-adapters#form-generation--type-mapping) These methods bridge the gap between blockchain-specific types and the generic form fields used by the UI. * `mapParameterTypeToFieldType(parameterType)`: A simple mapping from a blockchain type string (e.g., ’uint256'`) to a default` FieldType `(e.g., ’number'`). * `getCompatibleFieldTypes(parameterType)`: Returns an array of all `FieldType`s that could be used for a given blockchain type. For example, a ’bool' `might be compatible with ’checkbox'`, ’select'`, and ’radio'`. * `generateDefaultField(parameter)`: Creates a complete `FormFieldType` object for a given `FunctionParameter`, including a default label, placeholder, and validation rules. ### [Transaction Execution](https://docs.openzeppelin.com/ui-builder/building-adapters#transaction-execution) This is the core of state-changing interactions. The system uses an **Execution Strategy Pattern** to support multiple ways of sending a transaction (e.g., EOA, Relayer). * `getSupportedExecutionMethods()`: Returns a list of supported methods (`ExecutionMethodDetail`) for your ecosystem (e.g., EOA, Multisig). * `validateExecutionConfig(config)`: Validates a user’s `ExecutionConfig` for a specific method. For example, for an EOA with a specific address, it checks that the connected wallet matches. * `formatTransactionData(...)`: This crucial method takes the raw `submittedInputs` from the UI form and transforms them into the data payload your blockchain’s client library expects. The EVM adapter’s implementation in `transaction/formatter.ts` shows how to parse strings into `BigInt`, checksum addresses, and structure complex tuples. * `signAndBroadcast(...)`: The main function to execute a transaction. It receives the data from `formatTransactionData` and an `ExecutionConfig`. Your implementation should use a factory pattern to select the correct **Execution Strategy** (e.g., `EoaExecutionStrategy`, `RelayerExecutionStrategy`) based on `executionConfig.method`. * `waitForTransactionConfirmation?(txHash)`: (Optional) Implement this to allow the UI to wait for a transaction to be finalized. ### [Read-Only Queries](https://docs.openzeppelin.com/ui-builder/building-adapters#read-only-queries) These methods handle fetching data from the blockchain without creating a transaction. * `isViewFunction(functionDetails)`: A simple utility to check if a function is read-only. * `queryViewFunction(...)`: Fetches data from a read-only function. It should use the `networkConfig` to connect to the correct RPC endpoint. The EVM adapter implementation in `query/handler.ts` provides a robust example of creating a public client and handling various scenarios (e.g., using the wallet’s provider vs. a fallback provider). * `formatFunctionResult(...)`: Formats the raw data returned from `queryViewFunction` into a human-readable string for display in the UI. This should handle `BigInt`, arrays, and complex objects. ### [Wallet Interaction & UI Facilitation](https://docs.openzeppelin.com/ui-builder/building-adapters#wallet-interaction--ui-facilitation) These methods allow the adapter to provide a rich, ecosystem-specific wallet experience. The EVM adapter has a very sophisticated implementation for this, designed to be extensible with UI kits like RainbowKit. **For simpler ecosystems, your implementation can be much more direct.** * `supportsWalletConnection()`: Return `true` if your ecosystem has wallets. * `getAvailableConnectors()`: Return a list of wallet connectors the user can choose from. * `connectWallet(connectorId)`: Logic to initiate a connection with the chosen wallet. * `disconnectWallet()`: Logic to disconnect. * `getWalletConnectionStatus()`: Return the current status (`isConnected`, `address`, `chainId`). * `onWalletConnectionChange?(callback)`: (Optional) An event listener for status changes. **Advanced UI Facilitation (The "UI Kit" Pattern):** This optional but powerful pattern allows an adapter to provide React components and hooks that integrate with its ecosystem’s native wallet libraries (e.g., `wagmi` for EVM). * `configureUiKit(config, options)`: The entry point for the application to tell the adapter which UI kit to use (e.g., ’rainbowkit'`, ’custom'`) and provide configuration. * `getEcosystemReactUiContextProvider()`: Must return a stable React Component that provides the necessary context for your wallet library (e.g., for EVM, this is `` and ``). See `EvmWalletUiRoot.tsx` for a reference implementation that avoids UI flicker. * `getEcosystemReactHooks()`: Must return an object of facade hooks (e.g., `useAccount`, `useSwitchChain`). These hooks should wrap the native library’s hooks. **Crucially, your implementation must map the return values to a conventional format** to ensure UI components remain chain-agnostic (e.g., map the underlying library’s `isLoading` property to `isPending`). * `getEcosystemWalletComponents()`: Must return an object of standardized UI components (`ConnectButton`, `AccountDisplay`, etc.) for the configured UI kit. For a deep dive into this advanced pattern, study the EVM adapter’s wallet module (`packages/adapter-evm/src/wallet/`) and the `ADDING_NEW_UI_KITS.md` guide. [Standardized Adapter Package Structure](https://docs.openzeppelin.com/ui-builder/building-adapters#standardized-adapter-package-structure) -------------------------------------------------------------------------------------------------------------------------------------------- To ensure consistency, new adapter packages (`packages/adapter-`) should follow this directory structure: adapter-/ └── src/ ├── adapter.ts // Main Adapter class implementing ContractAdapter ├── networks/ // Network configurations for your chain │ ├── mainnet.ts │ ├── testnet.ts │ └── index.ts ├── [chain-def]/ // e.g., idl/ (Solana), abi/ (EVM) - For loading contracts │ ├── loader.ts │ └── transformer.ts ├── mapping/ // Type mapping and default field generation │ ├── type-mapper.ts │ └── field-generator.ts ├── transform/ // Data serialization/deserialization │ ├── input-parser.ts │ └── output-formatter.ts ├── transaction/ // Transaction execution (with strategy pattern) │ ├── execution-strategy.ts │ ├── eoa.ts // Example strategy │ └── ... ├── query/ // View function querying │ ├── handler.ts │ └── view-checker.ts ├── wallet/ // Wallet connection & UI facilitation logic ├── configuration/ // Explorer URLs, execution method validation ├── types.ts // Internal types specific to this adapter ├── utils/ // Adapter-specific utilities └── index.ts // Main package export [Configuration Management](https://docs.openzeppelin.com/ui-builder/building-adapters#configuration-management) ---------------------------------------------------------------------------------------------------------------- A robust adapter must handle runtime configuration overrides. The project provides utility services for this: `appConfigService`, `userRpcConfigService`, and `userExplorerConfigService`. Your adapter logic should follow a clear priority order when resolving settings like RPC URLs or explorer API keys: 1. **User-Provided Config**: Check the `user...ConfigService` first. This is for settings configured by the end-user in the UI and stored in `localStorage`. 2. **Application Config**: If no user config is found, check `appConfigService`. This is for settings provided by the application deployer in `app.config.json` or environment variables. 3. **Default Config**: If neither of the above is present, fall back to the default value in the `NetworkConfig` object your adapter was instantiated with. The functions `resolveRpcUrl` and `resolveExplorerConfig` in the EVM adapter provide excellent reference implementations of this layered pattern. [Step-by-Step Guide to Creating a New Adapter](https://docs.openzeppelin.com/ui-builder/building-adapters#step-by-step-guide-to-creating-a-new-adapter) -------------------------------------------------------------------------------------------------------------------------------------------------------- 1. **Create Package**: In the `packages/` directory, create `adapter-`. 2. **Define `package.json`**: Add dependencies on `@openzeppelin/contracts-ui-builder-types` and any chain-specific SDKs. Set up standard build scripts (copy from an existing adapter). 3. **Implement `NetworkConfig`**: In `src/networks/`, define your chain’s specific `...NetworkConfig` interface (extending `BaseNetworkConfig`) and create configuration objects for its mainnets and testnets. Export them and a combined list (e.g., `export const myChainNetworks = [...]`). 4. **Implement `ContractAdapter`**: Create `src/adapter.ts` and begin implementing the `ContractAdapter` interface, delegating logic to the modular subdirectories as described above. Start with the core methods and tackle the optional UI/wallet methods last. 5. **Register in Builder**: Open `packages/builder/src/core/ecosystemManager.ts` and: * Add your ecosystem to the `Ecosystem` type. * Add an entry to the `ecosystemRegistry`, providing the `networksExportName` (e.g., ’myChainNetworks'`) and the` AdapterClass\`. * Add a case to `loadAdapterPackageModule` to enable dynamic importing of your new package. 6. **Build and Test**: Build your new package and the main builder app. Add unit and integration tests to ensure your adapter functions correctly within the larger system. ### On this page [Core Architecture: The Adapter Pattern](https://docs.openzeppelin.com/ui-builder/building-adapters#core-architecture-the-adapter-pattern) [The `ContractAdapter` Interface: Your Implementation Contract](https://docs.openzeppelin.com/ui-builder/building-adapters#the-contractadapter-interface-your-implementation-contract) [Contract Definition & Schema Handling](https://docs.openzeppelin.com/ui-builder/building-adapters#contract-definition--schema-handling) [Form Generation & Type Mapping](https://docs.openzeppelin.com/ui-builder/building-adapters#form-generation--type-mapping) [Transaction Execution](https://docs.openzeppelin.com/ui-builder/building-adapters#transaction-execution) [Read-Only Queries](https://docs.openzeppelin.com/ui-builder/building-adapters#read-only-queries) [Wallet Interaction & UI Facilitation](https://docs.openzeppelin.com/ui-builder/building-adapters#wallet-interaction--ui-facilitation) [Standardized Adapter Package Structure](https://docs.openzeppelin.com/ui-builder/building-adapters#standardized-adapter-package-structure) [Configuration Management](https://docs.openzeppelin.com/ui-builder/building-adapters#configuration-management) [Step-by-Step Guide to Creating a New Adapter](https://docs.openzeppelin.com/ui-builder/building-adapters#step-by-step-guide-to-creating-a-new-adapter) --- # Solana Integration | OpenZeppelin Docs Relayer Solana Integration ================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/relayer/solana#overview) ------------------------------------------------------------------ OpenZeppelin Relayer provides robust support for Solana networks, enabling secure transaction relaying, automated token swaps, gasless transactions, and advanced fee management. This page covers everything you need to get started and make the most of Solana-specific features. [Features](https://docs.openzeppelin.com/relayer/solana#features) ------------------------------------------------------------------ * Automated token swaps via Jupiter DEX (mainnet-beta only) * Gasless transactions (user or relayer pays fees) * Secure transaction signing with multiple signer backends * Transaction status monitoring and nonce management * Custom RPC endpoints and network policies * Metrics and observability [Supported Networks](https://docs.openzeppelin.com/relayer/solana#supported-networks) -------------------------------------------------------------------------------------- Solana networks are defined via JSON configuration files, providing flexibility to: * Configure standard Solana clusters: `mainnet-beta`, `devnet`, `testnet` * Set up custom Solana-compatible networks with specific RPC endpoints * Create network variants using inheritance from base configurations Example Solana network configurations: { "networks": [\ {\ "type": "solana",\ "network": "solana-mainnet",\ "rpc_urls": ["https://api.mainnet-beta.solana.com"],\ "explorer_urls": ["https://explorer.solana.com"],\ "is_testnet": false,\ "tags": ["mainnet", "solana"]\ },\ {\ "type": "solana",\ "network": "solana-devnet",\ "rpc_urls": ["https://api.devnet.solana.com"],\ "explorer_urls": ["https://explorer.solana.com?cluster=devnet"],\ "is_testnet": true,\ "tags": ["devnet", "solana"]\ },\ {\ "type": "solana",\ "network": "solana-custom",\ "rpc_urls": ["https://your-custom-solana-rpc.example.com"],\ "tags": ["custom", "solana"]\ }\ ] } For detailed network configuration options, see the [Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration) guide. [Supported Signers](https://docs.openzeppelin.com/relayer/solana#supported-signers) ------------------------------------------------------------------------------------ * `vault_transit` (hosted) * `turnkey` (hosted) * `google_cloud_kms` (hosted) * `local` (local) * `vault` (local) In production systems, hosted signers are recommended for the best security model. [Quickstart](https://docs.openzeppelin.com/relayer/solana#quickstart) ---------------------------------------------------------------------- For a step-by-step setup, see [Quick Start Guide](https://docs.openzeppelin.com/relayer/quickstart) . Key prerequisites: * Rust 2021, version `1.86` or later * Redis * Docker (optional) Example configuration for a Solana relayer: { "id": "solana-example", "name": "Solana Example", "network": "devnet", "paused": false, "notification_id": "notification-example", "signer_id": "local-signer", "network_type": "solana", "custom_rpc_urls": [\ {\ "url": "https://primary-solana-rpc.example.com",\ "weight": 100\ },\ {\ "url": "https://backup-solana-rpc.example.com",\ "weight": 100\ }\ ], "policies": { "fee_payment_strategy": "user", "min_balance": 0, "allowed_tokens": [\ {\ "mint": "So111...",\ "max_allowed_fee": 100000000\ }\ ], "swap_config": { "strategy": "jupiter-swap", "cron_schedule": "0 0 * * * *", "min_balance_threshold": 1000000, "jupiter_swap_options": { "dynamic_compute_unit_limit": true, "priority_level": "high", "priority_fee_max_lamports": 1000000000 } } } } For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) . [Configuration](https://docs.openzeppelin.com/relayer/solana#configuration) ---------------------------------------------------------------------------- ### [Relayer Policies](https://docs.openzeppelin.com/relayer/solana#relayer-policies) In addition to standard relayer configuration and policies, Solana relayers support additional options: * `fee_payment_strategy`: `"user"` or `"relayer"` (who pays transaction fees) * `allowed_tokens`: List of SPL tokens supported for swaps and fee payments * `allowed_programs`, `allowed_accounts`, `disallowed_accounts`: Restrict relayer operations to specific programs/accounts * `swap_config`: Automated token swap settings (see below) You can check all options in [User Documentation - Relayers](https://docs.openzeppelin.com/relayer#3-relayers) . ### [Automated token swap configuration options:](https://docs.openzeppelin.com/relayer/solana#automated-token-swap-configuration-options) * `strategy`: The swap engine to use. Supported values: `"jupiter-swap"` (Jupiter Swap API), `"jupiter-ultra"` (Jupiter Ultra API). * `cron_schedule`: Cron expression defining how often scheduled swaps should run (e.g., `"0 0 * * * *"` for every hour). * `min_balance_threshold`: Minimum token balance (in lamports) that triggers a swap. If the relayer’s balance drops below this, a swap is attempted. * `jupiter_swap_options`: Advanced options for Jupiter swaps, such as: * `dynamic_compute_unit_limit`: If `true`, dynamically adjusts compute units for swap transactions. * `priority_level`: Priority for the swap transaction. Supported values: `"medium"`, `"high"`, `"veryHigh"`. * `priority_fee_max_lamports`: Maximum priority fee (in lamports) to pay for a swap transaction. * Per-token swap limits: * `min_amount`: Minimum amount of a token to swap in a single operation. * `max_amount`: Maximum amount of a token to swap in a single operation. * `retain_min_amount`: Minimum amount of a token to retain in the relayer account after a swap (prevents swapping the entire balance). [Automated Token Swaps](https://docs.openzeppelin.com/relayer/solana#automated-token-swaps) -------------------------------------------------------------------------------------------- The relayer can perform automated token swaps on Solana when user fee\_payment\_strategy is used for relayer using: * _**jupiter-swap**_ – via the Jupiter Swap API * _**jupiter-ultra**_ – via the Jupiter Ultra API Swaps can be set to work as: * _**Scheduled Swaps**_: Background jobs run swaps based on your cron schedule. * _**On-Demand Swaps**_: If a transaction fails due to insufficient funds, the relayer attempts a swap before returning an error. [API Reference](https://docs.openzeppelin.com/relayer/solana#api-reference) ---------------------------------------------------------------------------- The Solana API conforms to the [Paymaster spec](https://docs.google.com/document/d/1lweO5WH12QJaSAu5RG_wUistyk_nFeT6gy1CdvyCEHg/edit?tab=t.0#heading=h.4yldgprkuvav) . Common endpoints: * `POST /api/v1/relayers//rpc` Methods: * `feeEstimate`, * `prepareTransaction`, * `transferTransaction`, * `signTransaction`, * `signAndSendTransaction`, * `getSupportedTokens` * `getSupportedFeatures` Example: Estimate fee for a transaction curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/rpc' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "method": "feeEstimate", "params": { "transaction": "", "fee_token": "" }, "id": 1 }' See [API Reference](https://release-v1-0-0--openzeppelin-relayer.netlify.app/api_docs.html) and [SDK examples](https://github.com/OpenZeppelin/openzeppelin-relayer-sdk/tree/main/examples/solana) for full details and examples. [Security](https://docs.openzeppelin.com/relayer/solana#security) ------------------------------------------------------------------ * Do not expose the relayer directly to the public internet. * Deploy behind a secure backend (reverse proxy, firewall). * Use hosted signers in production systems. [Troubleshooting](https://docs.openzeppelin.com/relayer/solana#troubleshooting) -------------------------------------------------------------------------------- * Check environment variables and configuration files for errors * Review container logs for issues [Roadmap](https://docs.openzeppelin.com/relayer/solana#roadmap) ---------------------------------------------------------------- * See [Project Roadmap](https://docs.openzeppelin.com/relayer/roadmap) for upcoming features [Support](https://docs.openzeppelin.com/relayer/solana#support) ---------------------------------------------------------------- For help, join our [Telegram](https://t.me/openzeppelin_tg/2) or open an issue on GitHub. [License](https://docs.openzeppelin.com/relayer/solana#license) ---------------------------------------------------------------- This project is licensed under the GNU Affero General Public License v3.0. [EVM Integration\ \ Previous Page](https://docs.openzeppelin.com/relayer/evm) [Overview\ \ Next Page](https://docs.openzeppelin.com/relayer/api) ### On this page [Overview](https://docs.openzeppelin.com/relayer/solana#overview) [Features](https://docs.openzeppelin.com/relayer/solana#features) [Supported Networks](https://docs.openzeppelin.com/relayer/solana#supported-networks) [Supported Signers](https://docs.openzeppelin.com/relayer/solana#supported-signers) [Quickstart](https://docs.openzeppelin.com/relayer/solana#quickstart) [Configuration](https://docs.openzeppelin.com/relayer/solana#configuration) [Relayer Policies](https://docs.openzeppelin.com/relayer/solana#relayer-policies) [Automated token swap configuration options:](https://docs.openzeppelin.com/relayer/solana#automated-token-swap-configuration-options) [Automated Token Swaps](https://docs.openzeppelin.com/relayer/solana#automated-token-swaps) [API Reference](https://docs.openzeppelin.com/relayer/solana#api-reference) [Security](https://docs.openzeppelin.com/relayer/solana#security) [Troubleshooting](https://docs.openzeppelin.com/relayer/solana#troubleshooting) [Roadmap](https://docs.openzeppelin.com/relayer/solana#roadmap) [Support](https://docs.openzeppelin.com/relayer/solana#support) [License](https://docs.openzeppelin.com/relayer/solana#license) --- # OpenZeppelin Relayer Roadmap | OpenZeppelin Docs Relayer OpenZeppelin Relayer Roadmap ============================ Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document outlines the planned development roadmap for the OpenZeppelin Relayer project. Please note that priorities and timelines may shift based on community feedback, security considerations, and emerging blockchain ecosystem needs. This roadmap represents our current plans and is subject to change. We will update this document regularly to reflect our progress and any changes in direction. [General Roadmap](https://docs.openzeppelin.com/relayer/roadmap#general-roadmap) --------------------------------------------------------------------------------- * **Stability Improvements** * Enhanced error handling and recovery mechanisms: Implement robust exception management and failover processes to minimize downtime. * Improved background job processing: Optimize task scheduling and queuing systems to ensure smooth and reliable asynchronous operations. * Comprehensive test coverage: Extend unit, integration, and regression tests across all components. * End-to-End (E2E) testing: Simulate real-world scenarios to verify complete system functionality. * Performance optimizations: Enhance throughput and reduce latency for high-demand scenarios. * Stress and load testing: Identify and address performance bottlenecks under extreme conditions. * **Security Enhancements** * External security audit: Engage third-party experts to identify and remediate vulnerabilities. * Continuous security monitoring: Implement ongoing surveillance and incident response protocols to swiftly address threats. * **Developer Experience** * SDK improvements: Expand SDK capabilities, add multi-language support, and simplify integration processes. * Enhanced documentation: Develop interactive guides, detailed API references, and comprehensive troubleshooting tips. * Additional examples and best practices: Provide real-world usage scenarios and community-contributed tutorials to ease onboarding. * **Features** * Redis storage integration: Leverage Redis for fast, scalable data storage across all system components. * Enhanced relayer balance management: Implement real-time monitoring and alerts to maintain optimal balance status. * Dynamic gas price updates: Regularly fetch and update gas prices from multiple reliable sources to ensure accurate fee estimations. * **Scaling Improvements** * Horizontal scaling capabilities: Design the system architecture to seamlessly distribute workloads across multiple instances. [Network-Specific Roadmap](https://docs.openzeppelin.com/relayer/roadmap#network-specific-roadmap) --------------------------------------------------------------------------------------------------- ### [EVM Networks (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#evm-networks-%EF%B8%8F-in-progress) #### [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status) * Basic Transaction Submission * Fee Estimation * Transaction Status Tracking * Flexible Network Configuration System (any EVM-compatible network via JSON configuration) * Hosted signers support (AWS KMS, GCP, Turnkey) * Custom RPC Endpoints * RPC Retries and Failover Mechanisms #### [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features) * L2 improvements * SDK client improvements * Full CRUD API support ### [Solana (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#solana-%EF%B8%8F-in-progress) #### [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status-1) * Solana Paymaster Specification Support * Fee estimation * Gasless transactions * Hosted Signer Integrations (Vault, GCP, Turnkey) * Custom RPC Endpoints * RPC Retries and Failover Mechanisms #### [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features-1) * Extended RPC Methods * Improved Transaction Status Checks * Full CRUD API support ### [Stellar (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#stellar-%EF%B8%8F-in-progress) #### [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status-2) * Supports payment and InvokeHostFunction operations, pre-built XDR transactions, and fee bump transactions, * Advanced transaction status logic * Stellar-specific endpoints * Expanded signer support * Transaction lifecycle management logic * Custom RPC Endpoints * RPC Retries and Failover Mechanisms #### [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features-2) * Relayer security policies: Transaction amount limits, destination whitelisting, time bound and limit operations * Hosted signers * Full CRUD API support [Community and Documentation](https://docs.openzeppelin.com/relayer/roadmap#community-and-documentation) --------------------------------------------------------------------------------------------------------- ### [Continuous](https://docs.openzeppelin.com/relayer/roadmap#continuous) * **Documentation** * Comprehensive API reference * Tutorials and guides * Integration examples * **Community Engagement** * Contributing guidelines * Support for community-driven improvements [Notes on Prioritization](https://docs.openzeppelin.com/relayer/roadmap#notes-on-prioritization) ------------------------------------------------------------------------------------------------- Our development priorities are influenced by several factors: 1. **Security**: Security enhancements always take precedence 2. **Stability**: Ensuring reliable operation across all supported networks 3. **Community Feedback**: Features requested by the community 4. **Ecosystem Developments**: Adapting to changes in blockchain protocols This roadmap is a living document and will be updated regularly to reflect changing priorities and completed milestones. We welcome community input on our direction and priorities. To contribute to discussions about the roadmap, please join our community channels or open an issue on our GitHub repository with your suggestions. [Project Structure\ \ Previous Page](https://docs.openzeppelin.com/relayer/structure) [Plugins\ \ Next Page](https://docs.openzeppelin.com/relayer/plugins) ### On this page [General Roadmap](https://docs.openzeppelin.com/relayer/roadmap#general-roadmap) [Network-Specific Roadmap](https://docs.openzeppelin.com/relayer/roadmap#network-specific-roadmap) [EVM Networks (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#evm-networks-%EF%B8%8F-in-progress) [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status) [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features) [Solana (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#solana-%EF%B8%8F-in-progress) [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status-1) [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features-1) [Stellar (🏗️ In Progress)](https://docs.openzeppelin.com/relayer/roadmap#stellar-%EF%B8%8F-in-progress) [Current Status](https://docs.openzeppelin.com/relayer/roadmap#current-status-2) [Upcoming Features](https://docs.openzeppelin.com/relayer/roadmap#upcoming-features-2) [Community and Documentation](https://docs.openzeppelin.com/relayer/roadmap#community-and-documentation) [Continuous](https://docs.openzeppelin.com/relayer/roadmap#continuous) [Notes on Prioritization](https://docs.openzeppelin.com/relayer/roadmap#notes-on-prioritization) --- # Project Structure | OpenZeppelin Docs Relayer Project Structure ================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document provides detailed information about each directory in the OpenZeppelin Relayer project. [Source Code Organization](https://docs.openzeppelin.com/relayer/structure#source-code-organization) ----------------------------------------------------------------------------------------------------- ### [`src/` Directory](https://docs.openzeppelin.com/relayer/structure#src-directory) The main source code directory contains the core implementation files organized into several modules: * `api/`: Route and controllers logic * Manages HTTP routing and delegates incoming requests to controllers * `bootstrap/`: Service initialization * Bootstraps and initializes application services * `config/`: Configuration management * Handles system configuration and environment settings * `constants/`: Global constants * Provides static values used across the application * `domain/`: Business domain logic * Encapsulates core business rules and domain-specific functionality * `jobs/`: Asynchronous job processing * Manages background task queueing and execution * `logging/`: Logging and file rotation * Implements logging functionalities and log file management * `metrics/`: Metrics collection * Collects and reports application performance and usage metrics * `models/`: Core data models and types * Defines data structures and type definitions for the system * `repositories/`: Configuration storage * Provides interfaces for storing and retrieving configuration data * `services/`: Business service logic * Implements core business functionalities and service operations * `utils/`: Utility functions * Offers helper functions and common utilities for the application [Documentation](https://docs.openzeppelin.com/relayer/structure#documentation) ------------------------------------------------------------------------------- ### [`docs/` Directory](https://docs.openzeppelin.com/relayer/structure#docs-directory) Project documentation: * User guides * API documentation * Configuration examples * Architecture diagrams [Configuration](https://docs.openzeppelin.com/relayer/structure#configuration) ------------------------------------------------------------------------------- ### [`config/` Directory](https://docs.openzeppelin.com/relayer/structure#config-directory) Houses system configuration file and keys: * `config.json` configuration file * keystore files referenced from config.json file [Tests](https://docs.openzeppelin.com/relayer/structure#tests) --------------------------------------------------------------- ### [`test/` Directory](https://docs.openzeppelin.com/relayer/structure#test-directory) Includes comprehensive testing suites to ensure system reliability: * End-to-end tests that simulate real-world user scenarios [Scripts](https://docs.openzeppelin.com/relayer/structure#scripts) ------------------------------------------------------------------- ### [`scripts/` Directory](https://docs.openzeppelin.com/relayer/structure#scripts-directory) Utility scripts. [Examples](https://docs.openzeppelin.com/relayer/structure#examples) --------------------------------------------------------------------- ### [`examples/` Directory](https://docs.openzeppelin.com/relayer/structure#examples-directory) Provides practical examples and sample configurations to help users get started: * Demonstrates typical service configurations for various environments * Acts as a quick-start guide for customizing and deploying the relayer * Serves as a reference for best practices in configuration and deployment [Development Tools](https://docs.openzeppelin.com/relayer/structure#development-tools) --------------------------------------------------------------------------------------- ### [Pre-commit Hooks](https://docs.openzeppelin.com/relayer/structure#pre-commit-hooks) Located in the project root: * Code formatting checks * Linting rules * Commit message validation ### [Build Configuration](https://docs.openzeppelin.com/relayer/structure#build-configuration) Core build files: * `Cargo.toml`: Project dependencies and metadata * `rustfmt.toml`: Code formatting rules * `rust-toolchain.toml`: Rust version and components [Docker Support](https://docs.openzeppelin.com/relayer/structure#docker-support) --------------------------------------------------------------------------------- The project includes Docker configurations for different environments: * `Dockerfile.development`: Development container setup * `Dockerfile.production`: Production-ready container For detailed information about running the relayers in containers, see the Docker deployment section in the main documentation. [Health\ \ Previous Page](https://docs.openzeppelin.com/relayer/api/health) [Project Roadmap\ \ Next Page](https://docs.openzeppelin.com/relayer/roadmap) ### On this page [Source Code Organization](https://docs.openzeppelin.com/relayer/structure#source-code-organization) [`src/` Directory](https://docs.openzeppelin.com/relayer/structure#src-directory) [Documentation](https://docs.openzeppelin.com/relayer/structure#documentation) [`docs/` Directory](https://docs.openzeppelin.com/relayer/structure#docs-directory) [Configuration](https://docs.openzeppelin.com/relayer/structure#configuration) [`config/` Directory](https://docs.openzeppelin.com/relayer/structure#config-directory) [Tests](https://docs.openzeppelin.com/relayer/structure#tests) [`test/` Directory](https://docs.openzeppelin.com/relayer/structure#test-directory) [Scripts](https://docs.openzeppelin.com/relayer/structure#scripts) [`scripts/` Directory](https://docs.openzeppelin.com/relayer/structure#scripts-directory) [Examples](https://docs.openzeppelin.com/relayer/structure#examples) [`examples/` Directory](https://docs.openzeppelin.com/relayer/structure#examples-directory) [Development Tools](https://docs.openzeppelin.com/relayer/structure#development-tools) [Pre-commit Hooks](https://docs.openzeppelin.com/relayer/structure#pre-commit-hooks) [Build Configuration](https://docs.openzeppelin.com/relayer/structure#build-configuration) [Docker Support](https://docs.openzeppelin.com/relayer/structure#docker-support) --- # Changelog | OpenZeppelin Docs OpenZeppelin Contracts Changelog ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v540---2025-07-17) [v5.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.4.0) - 2025-07-17 ============================================================================================================================================================================== ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes) * Update minimum pragma to 0.8.24 in `SignatureChecker`, `Governor` and Governor's extensions. ([#5716](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5716) ). ### [Pragma changes](https://docs.openzeppelin.com/contracts/5.x/changelog#pragma-changes) * Reduced pragma requirement of interface files ### [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category) #### [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account) * `Account`: Added a simple ERC-4337 account implementation with minimal logic to process user operations. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) * `AccountERC7579`: Extension of `Account` that implements support for ERC-7579 modules of type executor, validator, and fallback handler. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) * `AccountERC7579Hooked`: Extension of `AccountERC7579` that implements support for ERC-7579 hook modules. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) * `EIP7702Utils`: Add a library for checking if an address has an EIP-7702 delegation in place. ([#5587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5587) ) * `IERC7821`, `ERC7821`: Interface and logic for minimal batch execution. No support for additional `opData` is included. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) #### [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance) * `GovernorNoncesKeyed`: Extension of `Governor` that adds support for keyed nonces when voting by sig. ([#5574](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5574) ) #### [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens) * `ERC20Bridgeable`: Implementation of ERC-7802 that makes an ERC-20 compatible with crosschain bridges. ([#5739](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5739) ) #### [Cryptography](https://docs.openzeppelin.com/contracts/5.x/changelog#cryptography) ##### [Signers](https://docs.openzeppelin.com/contracts/5.x/changelog#signers) * `AbstractSigner`, `SignerECDSA`, `SignerP256`, and `SignerRSA`: Add an abstract contract and various implementations for contracts that deal with signature verification. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) * `SignerERC7702`: Implementation of `AbstractSigner` for Externally Owned Accounts (EOAs). Useful with ERC-7702. ([#5657](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5657) ) * `SignerERC7913`: Abstract signer that verifies signatures using the ERC-7913 workflow. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659) ) * `MultiSignerERC7913`: Implementation of `AbstractSigner` that supports multiple ERC-7913 signers with a threshold-based signature verification system. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659) ) * `MultiSignerERC7913Weighted`: Extension of `MultiSignerERC7913` that supports assigning different weights to each signer, enabling more flexible governance schemes. ([#5741](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5741) ) ##### [Verifiers](https://docs.openzeppelin.com/contracts/5.x/changelog#verifiers) * `ERC7913P256Verifier` and `ERC7913RSAVerifier`: Ready to use ERC-7913 verifiers that implement key verification for P256 (secp256r1) and RSA keys. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659) ) ##### [Other](https://docs.openzeppelin.com/contracts/5.x/changelog#other) * `SignatureChecker`: Add support for ERC-7913 signatures alongside existing ECDSA and ERC-1271 signature verification. ([#5659](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5659) ) * `ERC7739`: An abstract contract to validate signatures following the rehashing scheme from `ERC7739Utils`. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664) ) * `ERC7739Utils`: Add a library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on the ERC-7739. ([#5664](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5664) ) #### [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures) * `EnumerableMap`: Add support for `BytesToBytesMap` type. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658) ) * `EnumerableMap`: Add `keys(uint256,uint256)` that returns a subset (slice) of the keys in the map. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713) ) * `EnumerableSet`: Add support for `StringSet` and `BytesSet` types. ([#5658](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5658) ) * `EnumerableSet`: Add `values(uint256,uint256)` that returns a subset (slice) of the values in the set. ([#5713](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5713) ) #### [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils) * `Arrays`: Add `unsafeAccess`, `unsafeMemoryAccess` and `unsafeSetLength` for `bytes[]` and `string[]`. ([#5568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5568) ) * `Blockhash`: Add a library that provides access to historical block hashes using EIP-2935's history storage, extending the standard 256-block limit to 8191 blocks. ([#5642](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5642) ) * `Bytes`: Fix `lastIndexOf(bytes,byte,uint256)` with empty buffers and finite position to correctly return `type(uint256).max` instead of accessing uninitialized memory sections. ([#5797](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5797) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.3.0...v5.4.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v530---2025-04-09) [v5.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.3.0) - 2025-04-09 ============================================================================================================================================================================== ### [Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-1) * Replace `GovernorCountingOverridable.VoteReceipt` struct parameter member names `hasOverriden` and `overridenWeight` for `hasOverridden` and `overriddenWeight` respectively. #### [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes) * Replace `GovernorAlreadyOverridenVote` with `GovernorAlreadyOverriddenVote`. * Replace `GovernorOnlyProposer` with `GovernorUnableToCancel`. ### [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-1) #### [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account-1) * `ERC4337Utils`: Update the `hash` function to call `getUserOpHash` on the specified entrypoint and add an `ENTRYPOINT_V08` constant. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614) ) * `ERC7579Utils`: Add ABI decoding checks on calldata bounds within `decodeBatch`. ([#5371](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5371) ) * `ERC7579Utils`: Replace `address(0)` with `address(this)` during execution for calldata compression efficiency. ([#5614](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5614) ) #### [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-1) * `IGovernor`: Add the `getProposalId` function to the governor interface. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290) ) * `GovernorProposalGuardian`: Add a governance extension that defines a proposal guardian who can cancel proposals at any stage in their lifecycle. ([#5303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5303) ) * `GovernorSequentialProposalId`: Adds a `Governor` extension that sequentially numbers proposal ids instead of using the hash. ([#5290](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5290) ) * `GovernorSuperQuorum`: Add a governance extension to support a super quorum. Proposals that meet the super quorum (and have a majority of for votes) advance to the `Succeeded` state before the proposal deadline. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `GovernorVotesSuperQuorumFraction`: Add a variant of the `GovernorSuperQuorum` extensions where the super quorum is expressed as a fraction of the total supply. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `TimelockController`: Receive function is now virtual. ([#5509](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5509) ) #### [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures-1) * `EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486) ) * `EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map. ([#5486](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5486) ) * `MerkleTree`: Add an update function that replaces a previously inserted leaf with a new value, updating the tree root along the way. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) #### [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-1) * `ERC4626`: Use the `asset` getter in `totalAssets`, `_deposit` and `_withdraw`. ([#5322](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5322) ) * `IERC6909`: Add the interface for ERC-6909. ([#5343](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5343) ) * `ERC6909`: Add a standard implementation of ERC6909. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394) ) * `ERC6909TokenSupply`: Add an extension of ERC6909 which tracks total supply for each token id. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394) ) * `ERC6909Metadata`: Add an extension of ERC6909 which adds metadata functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394) ) * `ERC6909ContentURI`: Add an extension of ERC6909 which adds content URI functionality. ([#5394](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5394) ) * `SafeERC20`: Add `trySafeTransfer` and `trySafeTransferFrom` that do not revert and return false if the transfer is not successful. ([#5483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5483) ) #### [Other](https://docs.openzeppelin.com/contracts/5.x/changelog#other-1) * `Address`: bubble up revert data on `sendValue` failed call. ([#5379](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5379) ) * `Calldata`: Library with `emptyBytes` and `emptyString` functions to generate empty `bytes` and `string` calldata types. ([#5422](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5422) ) * `ERC2771Forwarder`: Expose the `_isTrustedByTarget` internal function to check whether a target trusts the forwarder. ([#5416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5416) ) * `Hashes`: Expose `efficientKeccak256` for hashing non-commutative pairs of bytes32 without allocating extra memory. ([#5442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5442) ) * `Initializable`: Add `_initializableStorageSlot` function that returns a pointer to the storage struct. The function allows customizing with a custom storage slot with an `override`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `Math`: Add `add512`, `mul512` and `mulShr`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `Math`: Add saturating arithmetic operations `saturatingAdd`, `saturatingSub` and `saturatingMul`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `MessageHashUtils`: Add `toDataWithIntendedValidatorHash(address, bytes32)`. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) * `P256`: Adjust precompile detection in `verifyNative` to consider empty `returndata` on invalid verification. Previously, invalid signatures would've reverted with a `MissingPrecompile` error in chains with RIP-7212 support. ([#5620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5620) ) * `Pausable`: Stop explicitly setting `paused` to `false` during construction. ([#5448](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5448) ) * `Strings`: Add `espaceJSON` that escapes special characters in JSON strings. ([#5526](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5526) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.2.0...v5.3.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v520---2025-01-09) [v5.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.2.0) - 2025-01-09 ============================================================================================================================================================================== ### [Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-2) #### [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes-1) This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: * Replace `Errors.FailedCall` with a bubbled-up revert reason in `Address.sendValue`. ### [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-2) #### [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general) * Update some pragma directives to ensure that all file requirements match that of the files they import. ([#5273](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5273) ) #### [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account-2) * `ERC4337Utils`: Add a reusable library to manipulate user operations and interact with ERC-4337 contracts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274) ) * `ERC7579Utils`: Add a reusable library to interact with ERC-7579 modular accounts ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274) ) #### [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-2) * `GovernorCountingOverridable`: Add a governor counting module that enables token holders to override the vote of their delegate. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192) ) * `VotesExtended`: Create an extension of `Votes` which checkpoints balances and delegates. ([#5192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5192) ) ### [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy) * `Clones`: Add `cloneWithImmutableArgs` and `cloneDeterministicWithImmutableArgs` variants that create clones with per-instance immutable arguments. The immutable arguments can be retrieved using `fetchCloneArgs`. The corresponding `predictDeterministicWithImmutableArgs` function is also included. ([#5109](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5109) ) ### [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-2) * `ERC1363Utils`: Add helper similar to the existing `ERC721Utils` and `ERC1155Utils` ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133) ) ### [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-1) * `Address`: bubble up revert data on `sendValue` failed call ([#5418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5418) ) * `Bytes`: Add a library of common operations that operate on `bytes` objects. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252) ) * `CAIP2` and `CAIP10`: Add libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers. ([#5252](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5252) ) * `NoncesKeyed`: Add a variant of `Nonces` that implements the ERC-4337 entrypoint nonce system. ([#5272](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5272) ) * `Packing`: Add variants for packing `bytes10` and `bytes22` ([#5274](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5274) ) * `Strings`: Add `parseUint`, `parseInt`, `parseHexUint` and `parseAddress` to parse strings into numbers and addresses. Also provide variants of these functions that parse substrings, and `tryXxx` variants that do not revert on invalid input. ([#5166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5166) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.1.0...v5.2.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v510---2024-10-23) [v5.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.1.0) - 2024-10-23 ============================================================================================================================================================================== ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-3) * `ERC1967Utils`: Removed duplicate declaration of the `Upgraded`, `AdminChanged` and `BeaconUpgraded` events. These events are still available through the `IERC1967` interface located under the `contracts/interfaces/` directory. Minimum pragma version is now 0.8.21. * `Governor`, `GovernorCountingSimple`: The `_countVote` virtual function now returns an `uint256` with the total votes casted. This change allows for more flexibility for partial and fractional voting. Upgrading users may get a compilation error that can be fixed by adding a return statement to the `_countVote` function. #### [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes-2) This version comes with changes to the custom error identifiers. Contracts previously depending on the following errors should be replaced accordingly: * Replace `Address.FailedInnerCall` with `Errors.FailedCall` * Replace `Address.AddressInsufficientBalance` with `Errors.InsufficientBalance` * Replace `Clones.Create2InsufficientBalance` with `Errors.InsufficientBalance` * Replace `Clones.ERC1167FailedCreateClone` with `Errors.FailedDeployment` * Replace `Clones.Create2FailedDeployment` with `Errors.FailedDeployment` * `SafeERC20`: Replace `Address.AddressEmptyCode` with `SafeERC20FailedOperation` if there is no code at the token's address. * `SafeERC20`: Replace generic `Error(string)` with `SafeERC20FailedOperation` if the returned data can't be decoded as `bool`. * `SafeERC20`: Replace generic `SafeERC20FailedOperation` with the revert message from the contract call if it fails. ### [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-3) #### [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general-1) * `AccessManager`, `VestingWallet`, `TimelockController` and `ERC2771Forwarder`: Added a public `initializer` function in their corresponding upgradeable variants. ([#5008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5008) ) #### [Access](https://docs.openzeppelin.com/contracts/5.x/changelog#access) * `AccessControlEnumerable`: Add a `getRoleMembers` method to return all accounts that have `role`. ([#4546](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4546) ) * `AccessManager`: Allow the `onlyAuthorized` modifier to restrict functions added to the manager. ([#5014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5014) ) #### [Finance](https://docs.openzeppelin.com/contracts/5.x/changelog#finance) * `VestingWalletCliff`: Add an extension of the `VestingWallet` contract with an added cliff. ([#4870](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4870) ) #### [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-3) * `GovernorCountingFractional`: Add a governor counting module that allows distributing voting power amongst 3 options (For, Against, Abstain). ([#5045](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5045) ) * `Votes`: Set `_moveDelegateVotes` visibility to internal instead of private. ([#5007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5007) ) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy-1) * `Clones`: Add version of `clone` and `cloneDeterministic` that support sending value at creation. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936) ) * `TransparentUpgradeableProxy`: Make internal `_proxyAdmin()` getter have `view` visibility. ([#4688](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4688) ) * `ProxyAdmin`: Fixed documentation for `UPGRADE_INTERFACE_VERSION` getter. ([#5031](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5031) ) #### [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-3) * `ERC1363`: Add implementation of the token payable standard allowing execution of contract code after transfers and approvals. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631) ) * `ERC20TemporaryApproval`: Add an ERC-20 extension that implements temporary approval using transient storage, based on ERC7674 (draft). ([#5071](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5071) ) * `SafeERC20`: Add "relaxed" function for interacting with ERC-1363 functions in a way that is compatible with EOAs. ([#4631](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4631) ) * `SafeERC20`: Document risks of `safeIncreaseAllowance` and `safeDecreaseAllowance` when associated with ERC-7674. ([#5262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5262) ) * `ERC721Utils` and `ERC1155Utils`: Add reusable libraries with functions to perform acceptance checks on `IERC721Receiver` and `IERC1155Receiver` implementers. ([#4845](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4845) ) * `ERC1363Utils`: Add helper similar to the existing ERC721Utils and ERC1155Utils. ([#5133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5133) ) #### [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-2) * `Arrays`: add a `sort` functions for `address[]`, `bytes32[]` and `uint256[]` memory arrays. ([#4846](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4846) ) * `Arrays`: add new functions `lowerBound`, `upperBound`, `lowerBoundMemory` and `upperBoundMemory` for lookups in sorted arrays with potential duplicates. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842) ) * `Arrays`: deprecate `findUpperBound` in favor of the new `lowerBound`. ([#4842](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4842) ) * `Base64`: Add `encodeURL` following section 5 of RFC4648 for URL encoding ([#4822](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4822) ) * `Comparator`: A library of comparator functions, useful for customizing the behavior of the Heap structure. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084) ) * `Create2`: Bubbles up returndata from a deployed contract that reverted during construction. ([#5052](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5052) ) * `Create2`, `Clones`: Mask `computeAddress` and `cloneDeterministic` outputs to produce a clean value for an `address` type (i.e. only use 20 bytes) ([#4941](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4941) ) * `Errors`: New library of common custom errors. ([#4936](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4936) ) * `Hashes`: A library with commonly used hash functions. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617) ) * `Packing`: Added a new utility for packing, extracting and replacing bytesXX values. ([#4992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4992) ) * `Panic`: Add a library for reverting with panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298) ) * `ReentrancyGuardTransient`: Added a variant of `ReentrancyGuard` that uses transient storage. ([#4988](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4988) ) * `Strings`: Added a utility function for converting an address to checksummed string. ([#5067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5067) ) * `SlotDerivation`: Add a library of methods for derivating common storage slots. ([#4975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4975) ) * `TransientSlot`: Add primitives for operating on the transient storage space using a typed-slot representation. ([#4980](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4980) ) ##### [Cryptography](https://docs.openzeppelin.com/contracts/5.x/changelog#cryptography-1) * `SignatureChecker`: refactor `isValidSignatureNow` to avoid validating ECDSA signatures if there is code deployed at the signer's address. ([#4951](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4951) ) * `MerkleProof`: Add variations of `verify`, `processProof`, `multiProofVerify` and `processMultiProof` (and equivalent calldata version) with support for custom hashing functions. ([#4887](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4887) ) * `P256`: Library for verification and public key recovery of P256 (aka secp256r1) signatures. ([#4881](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4881) ) * `RSA`: Library to verify signatures according to RFC 8017 Signature Verification Operation ([#4952](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4952) ) #### [Math](https://docs.openzeppelin.com/contracts/5.x/changelog#math) * `Math`: add an `invMod` function to get the modular multiplicative inverse of a number in Z/nZ. ([#4839](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4839) ) * `Math`: Add `modExp` function that exposes the `EIP-198` precompile. Includes `uint256` and `bytes memory` versions. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298) ) * `Math`: Custom errors replaced with native panic codes. ([#3298](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298) ) * `Math`, `SignedMath`: Add a branchless `ternary` function that computes`cond ? a : b` in constant gas cost. ([#4976](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4976) ) * `SafeCast`: Add `toUint(bool)` for operating on `bool` values as `uint256`. ([#4878](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4878) ) #### [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures-2) * `CircularBuffer`: Add a data structure that stores the last `N` values pushed to it. ([#4913](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4913) ) * `DoubleEndedQueue`: Custom errors replaced with native panic codes. ([#4872](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4872) ) * `EnumerableMap`: add `UintToBytes32Map`, `AddressToAddressMap`, `AddressToBytes32Map` and `Bytes32ToAddressMap`. ([#4843](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4843) ) * `Heap`: A data structure that implements a heap-based priority queue. ([#5084](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5084) ) * `MerkleTree`: A data structure that allows inserting elements into a merkle tree and updating its root hash. ([#3617](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3617) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.0.2...v5.1.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v502---2024-02-29) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.2) - 2024-02-29 ============================================================================================================================================================================== * `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4926) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.6...v5.0.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v496---2024-02-29) [v4.9.6](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.6) - 2024-02-29 ============================================================================================================================================================================== * `Base64`: Fix issue where dirty memory located just after the input buffer is affecting the result. ([#4929](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4929) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.5...v4.9.6) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v495---2023-12-08) [v4.9.5](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.5) - 2023-12-08 ============================================================================================================================================================================== * `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. Patch duplicated `Address.functionDelegateCall` in v4.9.4 (removed). [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.0.1...v4.9.5) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v501---2023-12-07) [v5.0.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.1) - 2023-12-07 ============================================================================================================================================================================== * `ERC2771Context` and `Context`: Introduce a `_contextPrefixLength()` getter, used to trim extra information appended to `msg.data`. * `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.4...v5.0.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v494---2023-12-07) [v4.9.4](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.4) - 2023-12-07 ============================================================================================================================================================================== * `ERC2771Context` and `Context`: Introduce a `_contextPrefixLength()` getter, used to trim extra information appended to `msg.data`. * `Multicall`: Make aware of non-canonical context (i.e. `msg.sender` is not `_msgSender()`), allowing compatibility with `ERC2771Context`. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v5.0.0...v4.9.4) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v500---2023-10-05) [v5.0.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.0) - 2023-10-05 ============================================================================================================================================================================== ### [Additions Summary](https://docs.openzeppelin.com/contracts/5.x/changelog#additions-summary) The following contracts and libraries were added: * `AccessManager`: A consolidated system for managing access control in complex systems. * `AccessManaged`: A module for connecting a contract to an authority in charge of its access control. * `GovernorTimelockAccess`: An adapter for time-locking governance proposals using an `AccessManager`. * `AuthorityUtils`: A library of utilities for interacting with authority contracts. * `GovernorStorage`: A Governor module that stores proposal details in storage. * `ERC2771Forwarder`: An ERC2771 forwarder for meta transactions. * `ERC1967Utils`: A library with ERC1967 events, errors and getters. * `Nonces`: An abstraction for managing account nonces. * `MessageHashUtils`: A library for producing digests for ECDSA operations. * `Time`: A library with helpers for manipulating time-related objects. ### [Removals Summary](https://docs.openzeppelin.com/contracts/5.x/changelog#removals-summary) The following contracts, libraries, and functions were removed: * `Address.isContract` (because of its ambiguous nature and potential for misuse) * `Checkpoints.History` * `Counters` * `ERC20Snapshot` * `ERC20VotesComp` * `ERC165Storage` (in favor of inheritance based approach) * `ERC777` * `ERC1820Implementer` * `GovernorVotesComp` * `GovernorProposalThreshold` (deprecated since 4.4) * `PaymentSplitter` * `PullPayment` * `SafeMath` * `SignedSafeMath` * `Timers` * `TokenTimelock` (in favor of `VestingWallet`) * All escrow contracts (`Escrow`, `ConditionalEscrow` and `RefundEscrow`) * All cross-chain contracts, including `AccessControlCrossChain` and all the vendored bridge interfaces * All presets in favor of [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/) These removals were implemented in the following PRs: [#3637](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3637) , [#3880](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3880) , [#3945](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3945) , [#4258](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4258) , [#4276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4276) , [#4289](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4289) ### [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-4) #### [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general-2) * Replaced revert strings and require statements with custom errors. ([#4261](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4261) ) * Bumped minimum compiler version required to 0.8.20 ([#4288](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4288) ) * Use of `abi.encodeCall` in place of `abi.encodeWithSelector` and `abi.encodeWithSignature` for improved type-checking of parameters ([#4293](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4293) ) * Replaced some uses of `abi.encodePacked` with clearer alternatives (e.g. `bytes.concat`, `string.concat`). ([#4504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4504) ) ([#4296](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4296) ) * Overrides are now used internally for a number of functions that were previously hardcoded to their default implementation in certain locations: `ERC1155Supply.totalSupply`, `ERC721.ownerOf`, `ERC721.balanceOf` and `ERC721.totalSupply` in `ERC721Enumerable`, `ERC20.totalSupply` in `ERC20FlashMint`, and `ERC1967._getImplementation` in `ERC1967Proxy`. ([#4299](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4299) ) * Removed the `override` specifier from functions that only override a single interface function. ([#4315](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4315) ) * Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported. ([#4399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4399) ) * `Governor`, `Initializable`, and `UUPSUpgradeable`: Use internal functions in modifiers to optimize bytecode size. ([#4472](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4472) ) * Upgradeable contracts now use namespaced storage (EIP-7201). ([#4534](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4534) ) * Upgradeable contracts no longer transpile interfaces and libraries. ([#4628](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4628) ) #### [Access](https://docs.openzeppelin.com/contracts/5.x/changelog#access-1) * `Ownable`: Added an `initialOwner` parameter to the constructor, making the ownership initialization explicit. ([#4267](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4267) ) * `Ownable`: Prevent using address(0) as the initial owner. ([#4531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4531) ) * `AccessControl`: Added a boolean return value to the internal `_grantRole` and `_revokeRole` functions indicating whether the role was granted or revoked. ([#4241](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4241) ) * `access`: Moved `AccessControl` extensions to a dedicated directory. ([#4359](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4359) ) * `AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location. ([#4121](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4121) ) * `AccessManager`, `AccessManaged`, `GovernorTimelockAccess`: Ensure that calldata shorter than 4 bytes is not padded to 4 bytes. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624) ) * `AccessManager`: Use named return parameters in functions that return multiple values. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624) ) * `AccessManager`: Make `schedule` and `execute` more conservative when delay is 0. ([#4644](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4644) ) #### [Finance](https://docs.openzeppelin.com/contracts/5.x/changelog#finance-1) * `VestingWallet`: Fixed revert during 1 second time window when duration is 0. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502) ) * `VestingWallet`: Use `Ownable` instead of an immutable `beneficiary`. ([#4508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4508) ) #### [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-4) * `Governor`: Optimized use of storage for proposal data ([#4268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4268) ) * `Governor`: Added validation in ERC1155 and ERC721 receiver hooks to ensure Governor is the executor. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314) ) * `Governor`: Refactored internals to implement common queuing logic in the core module of the Governor. Added `queue` and `_queueOperations` functions that act at different levels. Modules that implement queuing via timelocks are expected to override `_queueOperations` to implement the timelock-specific logic. Added `_executeOperations` as the equivalent for execution. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360) ) * `Governor`: Added `voter` and `nonce` parameters in signed ballots, to avoid forging signatures for random addresses, prevent signature replay, and allow invalidating signatures. Add `voter` as a new parameter in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4378](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4378) ) * `Governor`: Added support for casting votes with ERC-1271 signatures by using a `bytes memory signature` instead of `r`, `s` and `v` arguments in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4418) ) * `Governor`: Added a mechanism to restrict the address of the proposer using a suffix in the description. * `GovernorStorage`: Added a new governor extension that stores the proposal details in storage, with an interface that operates on `proposalId`, as well as proposal enumerability. This replaces the old `GovernorCompatibilityBravo` module. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360) ) * `GovernorTimelockAccess`: Added a module to connect a governor with an instance of `AccessManager`, allowing the governor to make calls that are delay-restricted by the manager using the normal `queue` workflow. ([#4523](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4523) ) * `GovernorTimelockControl`: Clean up timelock id on execution for gas refund. ([#4118](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4118) ) * `GovernorTimelockControl`: Added the Governor instance address as part of the TimelockController operation `salt` to avoid operation id collisions between governors using the same TimelockController. ([#4432](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4432) ) * `TimelockController`: Changed the role architecture to use `DEFAULT_ADMIN_ROLE` as the admin for all roles, instead of the bespoke `TIMELOCK_ADMIN_ROLE` that was used previously. This aligns with the general recommendation for `AccessControl` and makes the addition of new roles easier. Accordingly, the `admin` parameter and timelock will now be granted `DEFAULT_ADMIN_ROLE` instead of `TIMELOCK_ADMIN_ROLE`. ([#3799](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3799) ) * `TimelockController`: Added a state getter that returns an `OperationState` enum. ([#4358](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4358) ) * `Votes`: Use Trace208 for checkpoints. This enables EIP-6372 clock support for keys but reduces the max supported voting power to uint208. ([#4539](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4539) ) #### [Metatx](https://docs.openzeppelin.com/contracts/5.x/changelog#metatx) * `ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`. ([#4346](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4346) ) * `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481) ) * `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484) ) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy-2) * `ProxyAdmin`: Removed `getProxyAdmin` and `getProxyImplementation` getters. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820) ) * `TransparentUpgradeableProxy`: Removed `admin` and `implementation` getters, which were only callable by the proxy owner and thus not very useful. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820) ) * `ERC1967Utils`: Refactored the `ERC1967Upgrade` abstract contract as a library. ([#4325](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4325) ) * `TransparentUpgradeableProxy`: Admin is now stored in an immutable variable (set during construction) to avoid unnecessary storage reads on every proxy call. This removed the ability to ever change the admin. Transfer of the upgrade capability is exclusively handled through the ownership of the `ProxyAdmin`. ([#4354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4354) ) * Moved the logic to validate ERC-1822 during an upgrade from `ERC1967Utils` to `UUPSUpgradeable`. ([#4356](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4356) ) * `UUPSUpgradeable`, `TransparentUpgradeableProxy` and `ProxyAdmin`: Removed `upgradeTo` and `upgrade` functions, and made `upgradeToAndCall` and `upgradeAndCall` ignore the data argument if it is empty. It is no longer possible to invoke the receive function (or send value with empty data) along with an upgrade. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382) ) * `BeaconProxy`: Reject value in initialization unless a payable function is explicitly invoked. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382) ) * `Proxy`: Removed redundant `receive` function. ([#4434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4434) ) * `BeaconProxy`: Use an immutable variable to store the address of the beacon. It is no longer possible for a `BeaconProxy` to upgrade by changing to another beacon. ([#4435](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4435) ) * `Initializable`: Use the namespaced storage pattern to avoid putting critical variables in slot 0. Allow reinitializer versions greater than 256. ([#4460](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4460) ) * `Initializable`: Use intermediate variables to improve readability. ([#4576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4576) ) #### [Token](https://docs.openzeppelin.com/contracts/5.x/changelog#token) * `ERC20`, `ERC721`, `ERC1155`: Deleted `_beforeTokenTransfer` and `_afterTokenTransfer` hooks, added a new internal `_update` function for customizations, and refactored all extensions using those hooks to use `_update` instead. ([#3838](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3838) , [#3876](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3876) , [#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377) ) * `ERC20`: Removed `Approval` event previously emitted in `transferFrom` to indicate that part of the allowance was consumed. With this change, allowances are no longer reconstructible from events. See the code for guidelines on how to re-enable this event if needed. ([#4370](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4370) ) * `ERC20`: Removed the non-standard `increaseAllowance` and `decreaseAllowance` functions. ([#4585](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4585) ) * `ERC20Votes`: Changed internal vote accounting to reusable `Votes` module previously used by `ERC721Votes`. Removed implicit `ERC20Permit` inheritance. Note that the `DOMAIN_SEPARATOR` getter was previously guaranteed to be available for `ERC20Votes` contracts, but is no longer available unless `ERC20Permit` is explicitly used; ERC-5267 support is included in `ERC20Votes` with `EIP712` and is recommended as an alternative. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816) ) * `SafeERC20`: Refactored `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens. ([#4260](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4260) ) * `SafeERC20`: Removed `safePermit` in favor of documentation-only `permit` recommendations. Based on recommendations from [@trust1995](https://github.com/trust1995) ([#4582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4582) ) * `ERC721`: `_approve` no longer allows approving the owner of the tokenId. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/4377) ) `_setApprovalForAll` no longer allows setting address(0) as an operator. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377) ) * `ERC721`: Renamed `_requireMinted` to `_requireOwned` and added a return value with the current owner. Implemented `ownerOf` in terms of `_requireOwned`. ([#4566](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4566) ) * `ERC721Consecutive`: Added a `_firstConsecutiveId` internal function that can be overridden to change the id of the first token minted through `_mintConsecutive`. ([#4097](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4097) ) * `ERC721URIStorage`: Allow setting the token URI prior to minting. ([#4559](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4559) ) * `ERC721URIStorage`, `ERC721Royalty`: Stop resetting token-specific URI and royalties when burning. ([#4561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4561) ) * `ERC1155`: Optimized array allocation. ([#4196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4196) ) * `ERC1155`: Removed check for address zero in `balanceOf`. ([#4263](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4263) ) * `ERC1155`: Optimized array accesses by skipping bounds checking when unnecessary. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300) ) * `ERC1155`: Bubble errors triggered in the `onERC1155Received` and `onERC1155BatchReceived` hooks. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314) ) * `ERC1155Supply`: Added a `totalSupply()` function that returns the total amount of token circulating, this change will restrict the total tokens minted across all ids to 2\*\*256-1 . ([#3962](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3962) ) * `ERC1155Receiver`: Removed in favor of `ERC1155Holder`. ([#4450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4450) ) #### [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-3) * `Address`: Removed the ability to customize error messages. A common custom error is always used if the underlying revert reason cannot be bubbled up. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502) ) * `Arrays`: Added `unsafeMemoryAccess` helpers to read from a memory array without checking the length. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300) ) * `Arrays`: Optimized `findUpperBound` by removing redundant SLOAD. ([#4442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4442) ) * `Checkpoints`: Library moved from `utils` to `utils/structs` ([#4275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4275) ) * `DoubleEndedQueue`: Refactored internal structure to use `uint128` instead of `int128`. This has no effect on the library interface. ([#4150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4150) ) * `ECDSA`: Use unchecked arithmetic for the `tryRecover` function that receives the `r` and `vs` short-signature fields separately. ([#4301](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4301) ) * `EIP712`: Added internal getters for the name and version strings ([#4303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4303) ) * `Math`: Makes `ceilDiv` to revert on 0 division even if the numerator is 0 ([#4348](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4348) ) * `Math`: Optimized stack operations in `mulDiv`. ([#4494](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4494) ) * `Math`: Renamed members of `Rounding` enum, and added a new rounding mode for "away from zero". ([#4455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4455) ) * `MerkleProof`: Use custom error to report invalid multiproof instead of reverting with overflow panic. ([#4564](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4564) ) * `MessageHashUtils`: Added a new library for creating message digest to be used along with signing or recovery such as ECDSA or ERC-1271. These functions are moved from the `ECDSA` library. ([#4430](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4430) ) * `Nonces`: Added a new contract to keep track of user nonces. Used for signatures in `ERC20Permit`, `ERC20Votes`, and `ERC721Votes`. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816) ) * `ReentrancyGuard`, `Pausable`: Moved to `utils` directory. ([#4551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4551) ) * `Strings`: Renamed `toString(int256)` to `toStringSigned(int256)`. ([#4330](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4330) ) * Optimized `Strings.equal` ([#4262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4262) ) ### [How to migrate from 4.x](https://docs.openzeppelin.com/contracts/5.x/changelog#how-to-migrate-from-4x) #### [ERC20, ERC721, and ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#erc20-erc721-and-erc1155) These breaking changes will require modifications to ERC20, ERC721, and ERC1155 contracts, since the `_afterTokenTransfer` and `_beforeTokenTransfer` functions were removed. Thus, any customization made through those hooks should now be done overriding the new `_update` function instead. Minting and burning are implemented by `_update` and customizations should be done by overriding this function as well. `_transfer`, `_mint` and `_burn` are no longer virtual (meaning they are not overridable) to guard against possible inconsistencies. For example, a contract using `ERC20`'s `_beforeTokenTransfer` hook would have to be changed in the following way. -function _beforeTokenTransfer( +function _update( address from, address to, uint256 amount ) internal virtual override { - super._beforeTokenTransfer(from, to, amount); require(!condition(), "ERC20: wrong condition"); + super._update(from, to, amount); } #### [More about ERC721](https://docs.openzeppelin.com/contracts/5.x/changelog#more-about-erc721) In the case of `ERC721`, the `_update` function does not include a `from` parameter, as the sender is implicitly the previous owner of the `tokenId`. The address of this previous owner is returned by the `_update` function, so it can be used for a posteriori checks. In addition to `to` and `tokenId`, a third parameter (`auth`) is present in this function. This parameter enabled an optional check that the caller/spender is approved to do the transfer. This check cannot be performed after the transfer (because the transfer resets the approval), and doing it before `_update` would require a duplicate call to `_ownerOf`. In this logic of removing hidden SLOADs, the `_isApprovedOrOwner` function was removed in favor of a new `_isAuthorized` function. Overrides that used to target the `_isApprovedOrOwner` should now be performed on the `_isAuthorized` function. Calls to `_isApprovedOrOwner` that preceded a call to `_transfer`, `_burn` or `_approve` should be removed in favor of using the `auth` argument in `_update` and `_approve`. This is showcased in `ERC721Burnable.burn` and in `ERC721Wrapper.withdrawTo`. The `_exists` function was removed. Calls to this function can be replaced by `_ownerOf(tokenId) != address(0)`. #### [More about ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#more-about-erc1155) Batch transfers will now emit `TransferSingle` if the batch consists of a single token, while in previous versions the `TransferBatch` event would be used for all transfers initiated through `safeBatchTransferFrom`. Both behaviors are compliant with the ERC-1155 specification. #### [ERC165Storage](https://docs.openzeppelin.com/contracts/5.x/changelog#erc165storage) Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do so so by overriding the `supportsInterface` function as seen below: function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } #### [SafeMath](https://docs.openzeppelin.com/contracts/5.x/changelog#safemath) Methods in SafeMath superseded by native overflow checks in Solidity 0.8.0 were removed along with operations providing an interface for revert strings. The remaining methods were moved to `utils/Math.sol`. - import "@openzeppelin/contracts/utils/math/SafeMath.sol"; + import "@openzeppelin/contracts/utils/math/Math.sol"; function tryOperations(uint256 x, uint256 y) external view { - (bool overflowsAdd, uint256 resultAdd) = SafeMath.tryAdd(x, y); + (bool overflowsAdd, uint256 resultAdd) = Math.tryAdd(x, y); - (bool overflowsSub, uint256 resultSub) = SafeMath.trySub(x, y); + (bool overflowsSub, uint256 resultSub) = Math.trySub(x, y); - (bool overflowsMul, uint256 resultMul) = SafeMath.tryMul(x, y); + (bool overflowsMul, uint256 resultMul) = Math.tryMul(x, y); - (bool overflowsDiv, uint256 resultDiv) = SafeMath.tryDiv(x, y); + (bool overflowsDiv, uint256 resultDiv) = Math.tryDiv(x, y); // ... } #### [Adapting Governor modules](https://docs.openzeppelin.com/contracts/5.x/changelog#adapting-governor-modules) Custom Governor modules that override internal functions may require modifications if migrated to v5. In particular, the new internal functions `_queueOperations` and `_executeOperations` may need to be used. If assistance with this migration is needed reach out via the [OpenZeppelin Support Forum](https://forum.openzeppelin.com/c/support/contracts/18) . #### [ECDSA and MessageHashUtils](https://docs.openzeppelin.com/contracts/5.x/changelog#ecdsa-and-messagehashutils) The `ECDSA` library is now focused on signer recovery. Previously it also included utility methods for producing digests to be used with signing or recovery. These utilities have been moved to the `MessageHashUtils` library and should be imported if needed: import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; contract Verifier { using ECDSA for bytes32; + using MessageHashUtils for bytes32; function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) { return data .toEthSignedMessageHash() .recover(signature) == account; } } #### [Interfaces and libraries in upgradeable contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#interfaces-and-libraries-in-upgradeable-contracts) The upgradeable version of the contracts library used to include a variant suffixed with `Upgradeable` for every contract. These variants, which are produced automatically, mainly include changes for dealing with storage that don't apply to libraries and interfaces. The upgradeable library no longer includes upgradeable variants for libraries and interfaces. Projects migrating to 5.0 should replace their library and interface imports with their corresponding non-upgradeable version: // Libraries -import {AddressUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; // Interfaces -import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/interfaces/IERC20.sol'; +import {IERC20} from '@openzeppelin/contracts/interfaces/IERC20.sol'; #### [Offchain Considerations](https://docs.openzeppelin.com/contracts/5.x/changelog#offchain-considerations) Some changes may affect offchain systems if they rely on assumptions that are changed along with these new breaking changes. These cases are: ##### [Relying on revert strings for processing errors](https://docs.openzeppelin.com/contracts/5.x/changelog#relying-on-revert-strings-for-processing-errors) A concrete example is AccessControl, where it was previously advised to catch revert reasons using the following regex: /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ Instead, contracts now revert with custom errors. Systems that interact with smart contracts outside of the network should consider reliance on revert strings and possibly support the new custom errors. ##### [Relying on storage locations for retrieving data](https://docs.openzeppelin.com/contracts/5.x/changelog#relying-on-storage-locations-for-retrieving-data) After 5.0, the storage location of some variables were changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storaged locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.3...v5.0.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v493---2023-07-28) [v4.9.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.3) - 2023-07-28 ============================================================================================================================================================================== > **Note** This release contains a fix for [GHSA-g4vp-m682-qqmp](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-g4vp-m682-qqmp) > . * `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481) ) * `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.2...v4.9.3) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v492---2023-06-16) [v4.9.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.2) - 2023-06-16 ============================================================================================================================================================================== > **Note** This release contains a fix for [GHSA-wprv-93r4-jj2p](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p) > . * `MerkleProof`: Fix a bug in `processMultiProof` and `processMultiProofCalldata` that allows proving arbitrary leaves if the tree contains a node with value 0 at depth 1. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.1...v4.9.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v491---2023-06-07) [v4.9.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.1) - 2023-06-07 ============================================================================================================================================================================== > **Note** This release contains a fix for [GHSA-5h3x-9wvq-w4m2](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-5h3x-9wvq-w4m2) > . * `Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.9.0...v4.9.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v490---2023-05-23) [v4.9.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.0) - 2023-05-23 ============================================================================================================================================================================== * `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714) ) * `ERC721Wrapper`: add a new extension of the `ERC721` token which wraps an underlying token. Deposit and withdraw guarantee that the ownership of each token is backed by a corresponding underlying token with the same identifier. ([#3863](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3863) ) * `EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920) ) * `Governor`: add a public `cancel(uint256)` function. ([#3983](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3983) ) * `Governor`: Enable timestamp operation for blockchains without a stable block time. This is achieved by connecting a Governor's internal clock to match a voting token's EIP-6372 interface. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934) ) * `Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774) ) * `IERC5313`: Add an interface for EIP-5313 that is now final. ([#4013](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4013) ) * `IERC4906`: Add an interface for ERC-4906 that is now Final. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012) ) * `StorageSlot`: Add support for `string` and `bytes`. ([#4008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4008) ) * `Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934) ) * `ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. ([#3979](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979) ) * `Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773) ) * `ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. ([#4029](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4029) ) * `EIP712`: add EIP-5267 support for better domain discovery. ([#3969](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3969) ) * `AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. ([#4009](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4009) ) * `SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. ([#3932](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3932) ) * `SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. ([#4067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4067) ) * `ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971) ) * `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. ([#4100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4100) ) * `ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. ([#3853](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3853) ) * `ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012) ) * `ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. ([#4023](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4023) ) * `SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. ([#4038](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4038) ) * `UUPSUpgradeable`: added granular `oz-upgrades-unsafe-allow-reachable` annotation to improve upgrade safety checks on latest version of the Upgrades Plugins (starting with `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) `). ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971) ) * `Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787) ) * `Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960) ) * `UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo` and `upgradeToAndCall` from `external` to `public`. ([#3959](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3959) ) * `TimelockController`: Add the `CallSalt` event to emit on operation schedule. ([#4001](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4001) ) * Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898) ) * `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745) ) * `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748) ) * `Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961) ) * `ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality ([#4007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4007) ) * `ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. ([#4063](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4063) ) * `MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745) ) ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-4) * `EIP712`: Addition of ERC5267 support requires support for user defined value types, which was released in Solidity version 0.8.8. This requires a pragma change from `^0.8.0` to `^0.8.8`. * `EIP712`: Optimization of the cache for the upgradeable version affects the way `name` and `version` are set. This is no longer done through an initializer, and is instead part of the implementation's constructor. As a consequence, all proxies using the same implementation will necessarily share the same `name` and `version`. Additionally, an implementation upgrade risks changing the EIP712 domain unless the same `name` and `version` are used when deploying the new implementation contract. ### [Deprecations](https://docs.openzeppelin.com/contracts/5.x/changelog#deprecations) * `ERC20Permit`: Added the file `IERC20Permit.sol` and `ERC20Permit.sol` and deprecated `draft-IERC20Permit.sol` and `draft-ERC20Permit.sol` since [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) is no longer a Draft. Developers are encouraged to update their imports. ([#3793](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3793) ) * `Timers`: The `Timers` library is now deprecated and will be removed in the next major release. ([#4062](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4062) ) * `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066) ) * `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.8.3...v4.9.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v483---2023-04-13) [v4.8.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.3) - 2023-04-13 ============================================================================================================================================================================== > **Note** This release contains fixes for [https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-mx2q-35m2-x2rh](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-mx2q-35m2-x2rh) > and [https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-93hq-5wgc-jc82](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-93hq-5wgc-jc82) > . * `GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing. * `TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. ([#4154](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4154) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.8.2...v4.8.3) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v482---2023-03-02) [v4.8.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.2) - 2023-03-02 ============================================================================================================================================================================== > **Note** This release contains a fix for [https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-878m-3g6q-594q](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-878m-3g6q-594q) > . * `ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`. ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-5) * `ERC721`: The internal function `_beforeTokenTransfer` no longer updates balances, which it previously did when `batchSize` was greater than 1. This change has no consequence unless a custom ERC721 extension is explicitly invoking `_beforeTokenTransfer`. Balance updates in extensions must now be done explicitly using `__unsafe_increaseBalance`, with a name that indicates that there is an invariant that has to be manually verified. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.8.1...v4.8.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v481---2023-01-13) [v4.8.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.1) - 2023-01-13 ============================================================================================================================================================================== * `ERC4626`: Use staticcall instead of call when fetching underlying ERC-20 decimals. ([#3943](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3943) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.8.0...v4.8.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v480---2022-11-08) [v4.8.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.0) - 2022-11-08 ============================================================================================================================================================================== > **Note** Don't miss the section on **Breaking changes** at the end. * `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722) ) * `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598) ) * `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339) ) * `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468) ) * `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469) ) * `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730) ) * `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506) ) * `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513) ) * `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673) ) * `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551) ) * `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639) ) * `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639) ) * `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481) ) * `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538) ) * `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611) ) * `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524) ) * `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311) ) * `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515) ) * `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565) ) * `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591) ) * `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580) ) * `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605) ) * `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665) ) * `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600) ) * `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640) ) * `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589) ) * `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589) ) * `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589) ) * `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573) ) * `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620) ) * `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679) ) * `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670) ) * Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692) ) ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-6) * `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides: function _beforeTokenTransfer( address from, address to, uint256 tokenId, + uint256 batchSize ) internal virtual override * `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior. * `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role. ### [Deprecations](https://docs.openzeppelin.com/contracts/5.x/changelog#deprecations-1) * `EIP712`: Added the file `EIP712.sol` and deprecated `draft-EIP712.sol` since the EIP is no longer a Draft. Developers are encouraged to update their imports. ([#3621](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3621) ) -import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; +import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; * `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699) ) -import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; ### [ERC-721 Compatibility Note](https://docs.openzeppelin.com/contracts/5.x/changelog#erc-721-compatibility-note) ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case. With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.7.3...v4.8.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v473---2022-08-10) [v4.7.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.3) - 2022-08-10 ============================================================================================================================================================================== :warning: This is a patch for a high severity issue. For more information [visit the security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h) . ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-7) * `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.7.2...v4.7.3) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v472---2022-07-28) [v4.7.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.2) - 2022-07-28 ============================================================================================================================================================================== :warning: This is a patch for three issues, including a high severity issue in `GovernorVotesQuorumFraction`. For more information visit the security advisories ([1](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-xrc4-737v-9q75) , [2](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-7grf-83vw-6f5x) , [3](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-9j3m-g383-29qr) ). 1. `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561) ) 2. `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587) ) 3. `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.7.1...v4.7.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v471---2022-07-20) [v4.7.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.1) - 2022-07-20 ============================================================================================================================================================================== :warning: This is a patch for a medium severity issue affecting `SignatureChecker` and a high severity issue affecting `ERC165Checker`. For more information visit the security advisories ([1](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4g63-c64m-25w9) , [2](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-qh9x-gcfh-pcrw) ). * `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552) ) * `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.7.0...v4.7.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v470---2022-06-30) [v4.7.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.0) - 2022-06-30 ============================================================================================================================================================================== * `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317) ) * `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380) ) * `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327) ) * `ERC4626`: add an extension of `ERC20` that implements the ERC4626 Tokenized Vault Standard. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171) ) * `SafeERC20`: add `safePermit` as mitigation against phantom permit functions. ([#3280](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3280) ) * `Math`: add a `mulDiv` function that can round the result either up or down. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171) ) * `Math`: Add a `sqrt` function to compute square roots of integers, rounding either up or down. ([#3242](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3242) ) * `Strings`: add a new overloaded function `toHexString` that converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. ([#3403](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3403) ) * `EnumerableMap`: add new `UintToUintMap` map type. ([#3338](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3338) ) * `EnumerableMap`: add new `Bytes32ToUintMap` map type. ([#3416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3416) ) * `SafeCast`: add support for many more types, using procedural code generation. ([#3245](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3245) ) * `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276) ) * `MerkleProof`: add calldata versions of the functions to avoid copying input arrays to memory and save gas. ([#3200](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3200) ) * `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254) , ([#3438](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3438) )) * `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434) ) * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350) ) * `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450) ) * `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455) ) ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-8) * `Initializable`: functions decorated with the modifier `reinitializer(1)` may no longer invoke each other. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.6.0...v4.7.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v460---2022-04-29) [v4.6.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.6.0) - 2022-04-29 ============================================================================================================================================================================== * `crosschain`: Add a new set of contracts for cross-chain applications. `CrossChainEnabled` is a base contract with instantiations for several chains and bridges, and `AccessControlCrossChain` is an extension of access control that allows cross-chain operation. ([#3183](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3183) ) * `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137) ) * `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150) ) * `EnumerableMap`: add new `Bytes32ToBytes32Map` map type. ([#3192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3192) ) * `ERC20FlashMint`: support infinite allowance when paying back a flash loan. ([#3226](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3226) ) * `ERC20Wrapper`: the `decimals()` function now tries to fetch the value from the underlying token instance. If that calls revert, then the default value is used. ([#3259](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3259) ) * `draft-ERC20Permit`: replace `immutable` with `constant` for `_PERMIT_TYPEHASH` since the `keccak256` of string literals is treated specially and the hash is evaluated at compile time. ([#3196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3196) ) * `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166) ) * `ERC1155URIStorage`: add a new extension that implements a `_setURI` behavior similar to ERC721's `_setTokenURI`. ([#3210](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3210) ) * `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153) ) * `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147) ) * `Governor`: Add a way to parameterize votes. This can be used to implement voting systems such as fractionalized voting, ERC721 based voting, or any number of other systems. The `params` argument added to `_countVote` method, and included in the newly added `_getVotes` method, can be used by counting and voting modules respectively for such purposes. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043) ) * `Governor`: rewording of revert reason for consistency. ([#3275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3275) ) * `Governor`: fix an inconsistency in data locations that could lead to invalid bytecode being produced. ([#3295](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3295) ) * `Governor`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by governors. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230) ) * `TimelockController`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by timelocks. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230) ) * `TimelockController`: Add a separate canceller role for the ability to cancel. ([#3165](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3165) ) * `Initializable`: add a reinitializer modifier that enables the initialization of new modules, added to already initialized contracts through upgradeability. ([#3232](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3232) ) * `Initializable`: add an Initialized event that tracks initialized version numbers. ([#3294](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3294) ) * `ERC2981`: make `royaltiInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305) ) ### [Upgradeability notice](https://docs.openzeppelin.com/contracts/5.x/changelog#upgradeability-notice) * `TimelockController`: **(Action needed)** The upgrade from `<4.6 to >=4.6` introduces a new `CANCELLER_ROLE` that requires set up to be assignable. After the upgrade, only addresses with this role will have the ability to cancel. Proposers will no longer be able to cancel. Assigning cancellers can be done by an admin (including the timelock itself) once the role admin is set up. To do this, we recommend upgrading to the `TimelockControllerWith46MigrationUpgradeable` contract and then calling the `migrateTo46` function. ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-9) * `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043) ) * `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043) ) * `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043) ) * `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.5.0...v4.6.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v450---2022-02-09) [v4.5.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.5.0) - 2022-02-09 ============================================================================================================================================================================== * `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012) ) * `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977) ) * Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) . ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986) ) * `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926) ) * `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973) ) * `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975) ) * `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944) ) * `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944) ) * `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917) ) * `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884) ) * `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056) ) * `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085) ) * `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170) ) * `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170) ) * `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085) ) * `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170) ) * `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686) ) * `SignedMath`: add a `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984) ) * `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021) ) * `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021) ) * Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. ### [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-10) * `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above. * `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.4.2...v4.5.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v442---2022-01-11) [v4.4.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.2) - 2022-01-11 ============================================================================================================================================================================== :warning: This is a patch for a medium severity issue. For more information [visit the security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-m6w8-fq7v-ph4m) . * `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#3100) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.4.1...v4.4.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v441---2021-12-14) [v4.4.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.1) - 2021-12-14 ============================================================================================================================================================================== :warning: This is a patch for a low severity vulnerability. For more information [visit the security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-9c22-pwxw-p6hx) . * `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006) ) ### [Breaking change](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-change) It is no longer possible to call an `initializer`\-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way: contract A { - function initialize() public initializer { ... } + function initialize() internal onlyInitializing { ... } } contract B is A { function initialize() public initializer { A.initialize(); } } [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.4.0...v4.4.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v440---2021-11-25) [v4.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.0) - 2021-11-25 ============================================================================================================================================================================== Check out the first [**OpenZeppelin Community Call**](https://www.youtube.com/watch?v=ed96DWbfliQ) where the team discussed everything that is included in this release. And if you missed it, we recently announced an official **bug bounty program** for OpenZeppelin Contracts. [Check it out!](https://forum.openzeppelin.com/t/openzeppelin-contracts-bug-bounty-program-on-immunefi/19279) * `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568) ) * `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568) ) * `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568) ) * `AccessControlEnumerable`: hook into `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2946](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2946) ) * `EIP712`: cache `address(this)` to immutable storage to avoid potential issues if a vanilla contract is used in a delegatecall context. ([#2852](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2852) ) * Add internal `_setApprovalForAll` to `ERC721` and `ERC1155`. ([#2834](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2834) ) * `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2892) ) * `GovernorCompatibilityBravo`: consider quorum an inclusive rather than exclusive minimum to match Compound's GovernorBravo. ([#2974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2974) ) * `GovernorSettings`: a new governor module that manages voting settings updatable through governance actions. ([#2904](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2904) ) * `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2858) ) * `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865) ) * `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841) ) * `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748) ) * `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849) ) * `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.3.3...v4.4.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v433---2021-11-15) [v4.3.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.3) - 2021-11-15 ============================================================================================================================================================================== :warning: This is a security patch. For more information visit the [security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wmpv-c2jp-j2xg) . * `ERC1155Supply`: Handle `totalSupply` changes by hooking into `_beforeTokenTransfer` to ensure consistency of balances and supply during `IERC1155Receiver.onERC1155Received` calls. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.3.2...v4.3.3) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v432---2021-09-14) [v4.3.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.2) - 2021-09-14 ============================================================================================================================================================================== :warning: This is a security patch. For more information visit the [security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-5vp3-v4hc-gx76) . * `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.3.1...v4.3.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v431---2021-08-26) [v4.3.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.1) - 2021-08-26 ============================================================================================================================================================================== :warning: This is a security patch. For more information visit the [security advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-fg47-3c2x-m2wr) . * `TimelockController`: Add additional isOperationReady check. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.4.2-solc-0.7...v4.3.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v342-solc-07---2021-08-26) [v3.4.2-solc-0.7](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.2-solc-0.7) - 2021-08-26 ======================================================================================================================================================================================================== * `TimelockController`: Add additional isOperationReady check. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.4.2...v3.4.2-solc-0.7) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v342---2021-08-26) [v3.4.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.2) - 2021-08-26 ============================================================================================================================================================================== * `TimelockController`: Add additional isOperationReady check. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.3.0...v3.4.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v430---2021-08-17) [v4.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.0) - 2021-08-17 ============================================================================================================================================================================== **Visit our blog for the full [4.3 announcement](https://blog.openzeppelin.com/openzeppelin-contracts-4-3/) as well as [Governor announcement](https://blog.openzeppelin.com/governor-smart-contract//) !** * `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754) ) * `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768) ) * `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672) ) * Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517) ) * `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661) ) * `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.2.0...v4.3.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v420---2021-06-30) [v4.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.2.0) - 2021-06-30 ============================================================================================================================================================================== **Read the full announcement [in the blog](https://blog.openzeppelin.com/openzeppelin-contracts-4-2/) !** * * * * `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632) ) * `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706) ) * `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633) ) * Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. * Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. * `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678) ) * Tokens: Wrap definitely safe subtractions in `unchecked` blocks. * `Math`: Add a `ceilDiv` method for performing ceiling division. * `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593) ) * `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710) ) ### [Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-11) * `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673) )) **How to update:** Change your import paths by removing the `draft-` prefix from `@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20FlashMint.sol`. > See [Releases and Stability: Drafts](https://docs.openzeppelin.com/contracts/4.x/releases-stability#drafts) > . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.1.0...v4.2.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v410---2021-04-30) [v4.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.1.0) - 2021-04-30 ============================================================================================================================================================================== Read the full announcement [in the blog](https://blog.openzeppelin.com/openzeppelin-contracts-4-1/) or check out the [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#410-2021-04-29) . * `IERC20Metadata`: add a new extended interface that includes the optional `name()`, `symbol()` and `decimals()` functions. ([#2561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2561) ) * `ERC777`: make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552) ) * `ERC20Permit`: add a `_useNonce` to enable further usage of ERC712 signatures. ([#2565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2565) ) * `ERC20FlashMint`: add an implementation of the ERC3156 extension for flash-minting ERC20 tokens. ([#2543](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2543) ) * `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532) ) * `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608) ) * `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582) ) * `AccessControl`: add a `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609) ) * `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542) ) * UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v4.0.0...v4.1.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v400---2021-03-24) [v4.0.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.0.0) - 2021-03-24 ============================================================================================================================================================================== Read the full announcement [in the blog](https://blog.openzeppelin.com/openzeppelin-contracts-4-0/) or check out the [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#400-2021-03-23) . [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog) ----------------------------------------------------------------------------- * Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin. * `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492) ) * `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502) ) * `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504) ) * `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518) ) * `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521) ) * `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505) ) * `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531) ) * `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511) ) * `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512) ) * Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508) ) * Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503) ) * `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524) ) * Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547) ) * `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551) ) * `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555) ) * `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562) ) * `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576) ) ### [How to upgrade from 3.x](https://docs.openzeppelin.com/contracts/5.x/changelog#how-to-upgrade-from-3x) Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: npx openzeppelin-contracts-migrate-imports Make sure you're using git or another version control system to be able to recover from any potential error in our script. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.4.0...v4.0.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v340---2021-02-03) [v3.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.0) - 2021-02-03 ============================================================================================================================================================================== Read the full announcement [in the blog](https://blog.openzeppelin.com/openzeppelin-contracts-4-0/) or check out the [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#340-2021-02-02) . ### [Security Fixes](https://docs.openzeppelin.com/contracts/5.x/changelog#security-fixes) * `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) ) If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to [\[email protected\]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection#d2a1b7b1a7a0bba6ab92bda2b7bca8b7a2a2b7bebbbcfcb1bdbf) . [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.3.0...v3.4.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v330---2020-11-27) [v3.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.3.0) - 2020-11-27 ============================================================================================================================================================================== Read the full announcement [in the forum](https://forum.openzeppelin.com/t/openzeppelin-contracts-3-3/4804) or check out the [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#330-2020-11-26) . * Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings. * `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354) ) * `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333) ) * `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.2.1-solc-0.7...v3.3.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v321-for-solidity-07-v321-solc-07---2020-09-15) [v3.2.1 for Solidity 0.7 (v3.2.1-solc-0.7)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.2.1-solc-0.7) - 2020-09-15 ======================================================================================================================================================================================================================================================= This is a special release for Solidity 0.7 that gets rid of a warning in `ERC777` using one of the new features of the language. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2327) ) Note: The variant for Solidity 0.7 can be installed using `npm install @openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) `. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.2.0...v3.2.1-solc-0.7) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v320---2020-09-11) [v3.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.2.0) - 2020-09-11 ============================================================================================================================================================================== Welcome to a new release of OpenZeppelin Contracts! :dancers: The big feature in this release is that we’ve migrated our proxy contracts from OpenZeppelin SDK into the Contracts project. We hope this will make more people aware of upgrades in Ethereum, and we also think the contracts will benefit greatly from the continued scrutiny by all of you in the community. This was also a migration of the proxies from Solidity 0.5 to 0.6, which we know some users have been waiting for. > For Solidity 0.7 users, a reminder that we have support for the newer compiler version published on npm under the tag `solc-0.7`, the latest release being `3.2.0-solc-0.7`. We’re considering officially switching to 0.7 for the release after this one. There is additionally a small breaking change in `ERC20Snapshot` that may affect some of its users. If you’re one of them please take a look at [the changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#320-2020-09-10) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.1.0...v3.2.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v310---2020-06-29) [v3.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.1.0) - 2020-06-29 ============================================================================================================================================================================== This is the first release since [v3.0, our last major release](https://forum.openzeppelin.com/t/openzeppelin-contracts-v3-0/2695) . It includes the long-awaited **ERC1155 token** and helpers for **safe calls and downcasts**, as well as a number of minor improvements. To install this release, run: npm install --save-dev @openzeppelin/contracts [ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#erc1155) ------------------------------------------------------------------------- This is a new [token standard](https://eips.ethereum.org/EIPS/eip-1155) developed by the gaming industry, focusing on gas efficiency. It's key difference is that it is a _multi-token_ contract: a single ERC1155 can be used to represent an arbitrary number of tokens, which is very useful in applications that require many tokens by removing the high gas costs associated with deploying them. Check out our new [documentation page](https://docs.openzeppelin.com/contracts/3.x/erc1155) to learn more!. [More Replacements for `call`](https://docs.openzeppelin.com/contracts/5.x/changelog#more-replacements-for-call) ----------------------------------------------------------------------------------------------------------------- The low-level `call` primitive can be hard to use correctly and is often considered unsafe. With the addition of [`sendValue`](https://docs.openzeppelin.com/contracts/3.x/api/utils#Address-sendValue-address-payable-uint256-) in Contracts and `try-catch` in Solidity, there's only a few scenarios in which `call` is still needed, the most troublesome one being forwarding calls. The new [`functionCall`](https://docs.openzeppelin.com/contracts/3.x/api/utils#Address-functionCall-address-bytes-) helpers can forward call data to a recipient contract while imitating Solidity's function call semantics, such as bubbling up revert reasons and rejecting calls to EOAs. We expect the addition of these functions to greatly reduce the need to rely on `call`. [Using `SafeMath` on Small Signed Integers](https://docs.openzeppelin.com/contracts/5.x/changelog#using-safemath-on-small-signed-integers) ------------------------------------------------------------------------------------------------------------------------------------------- We've expanded the scope of the [`SafeCast`](https://docs.openzeppelin.com/contracts/3.x/api/utils#SafeCast) library to also include signed integer downcasting, which allows for users that need small types (such as `int8` or `int32`) to perform checked arithmetic on them by using `SafeMath`, and then downcast the result to the intended size. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.0.1...v3.1.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-301-v301---2020-04-27) [OpenZeppelin Contracts 3.0.1 (v3.0.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.0.1) - 2020-04-27 ======================================================================================================================================================================================================================================== This is a small bugfix release, addressing an issue that allowed for some `internal` functions in ERC777 to be called with the zero address as one of their arguments. This was reported in [#2208](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2208) , fixed in [#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212) for the v2.5 branch, and ported to the v3.0 branch in [#2213](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2213) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.5.1...v3.0.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-251-v251---2020-04-27) [OpenZeppelin Contracts 2.5.1 (v2.5.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.5.1) - 2020-04-27 ======================================================================================================================================================================================================================================== This is a small bugfix release, addressing an issue that allowed for some `internal` functions in ERC777 to be called with the zero address as one of their arguments. This was reported in [#2208](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2208) and fixed in [#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v3.0.0...v2.5.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-30-v300---2020-04-20) [OpenZeppelin Contracts 3.0 (v3.0.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.0.0) - 2020-04-20 ===================================================================================================================================================================================================================================== We're thrilled to finally announce the **release of OpenZeppelin Contracts v3.0** :sparkles: Among other things, this release features the **migration to Solidity v0.6**, as well as a **revamped access control system**, **streamlined token contracts**, and new libraries for **enumerable mappings**. To install this latest release, run: npm install --save-dev @openzeppelin/contracts [What's New](https://docs.openzeppelin.com/contracts/5.x/changelog#whats-new) ------------------------------------------------------------------------------ * All contracts were migrated to Solidity v0.6. * `AccessControl` was designed [with help from the community](https://forum.openzeppelin.com/t/redesigning-accesscontrol-for-the-openzeppelin-contracts/2177) and has replaced `Roles` contracts (such as `MinterRole` and `PauserRole`), which were removed. * Crowdsales were removed: we'll continue to provide support for security issues on the v2.5 release, but will not bring them over to v3.0. * We've added **hooks**, a new feature of the library that will make extending it easier than ever. * `ERC20` and `ERC721` were simplified and streamlined, including all optional parts of the standard by default, and simplifying some of our own custom extensions. * Support for better `mapping` types that let you efficiently iterate over all keys using `EnumerableSet` and `EnumerableMap` * Many, _many_ breaking changes with small improvements. We've also moved some contracts around (e.g. `Ownable` is now found under the `access` directory) and deleted some that were not being used. Head to our [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md) to see the full list. [Compiling v0.6 Contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#compiling-v06-contracts) ---------------------------------------------------------------------------------------------------------- You can use the [**OpenZeppelin CLI**](https://docs.openzeppelin.com/cli) to compile any Solidity v0.6 contract: just update the `pragma` statement on your source code and you'll be good to go! pragma solidity ^0.6.0; Note that you will need to use the [v2.7 release of the CLI](https://forum.openzeppelin.com/t/openzeppelin-cli-2-7/2252) or newer to have Solidity v0.6 support. For detailed information about using the CLI compiler, head to its [documenation](https://docs.openzeppelin.com/cli/compiling) . [Revamped Access Control](https://docs.openzeppelin.com/contracts/5.x/changelog#revamped-access-control) --------------------------------------------------------------------------------------------------------- One of our most widely-used contracts is [`Ownable`](https://docs.openzeppelin.com/contracts/3.x/api/access#Ownable) , providing a simple authorization scheme. However, this fell short in complex systems with [multiple permissions](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/366) . The v3.0 release introduces `AccessControl`, a one-stop-shop for all authorization needs. It lets you easily define multiple **roles with different permissions**, as well as **which accounts are allowed to grant and revoke** each role. It also boosts transparency by enabling **enumeration of all privileged accounts** in a system. `AccessControl` was designed with a security-first mindset, [receiving input from a wide array of users](https://forum.openzeppelin.com/t/redesigning-accesscontrol-for-the-openzeppelin-contracts/2177) and incorporating best practices in the field. Head to [our Access Control guide](https://docs.openzeppelin.com/contracts/3.x/access-control#role-based-access-control) for more information! [Preset Contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#preset-contracts) ------------------------------------------------------------------------------------------- OpenZeppelin Contracts shine when you need the building blocks to get to the right feature set, but that's not all they can do! We've added a new family of **Preset** contracts starting with ERC20 and ERC721 tokens that you can quickly deploy as-is **without having to write any Solidity code**. Check out [their documentation!](https://docs.openzeppelin.com/contracts/3.x/api/presets) [Migrating From OpenZeppelin Contracts v2.5](https://docs.openzeppelin.com/contracts/5.x/changelog#migrating-from-openzeppelin-contracts-v25) ---------------------------------------------------------------------------------------------------------------------------------------------- Other than the moved and deleted contracts mentioned above, the library API is pretty much the same as in the [v2.5 release](https://forum.openzeppelin.com/t/openzeppelin-contracts-v2-5/2155) , so the migration should be straightforward. For instructions on how to update your Solidity v0.5 contracts to v0.6, refer to the [official documentation](https://solidity.readthedocs.io/en/v0.6.2/060-breaking-changes.html#how-to-update-your-code) . If you're using the `ERC20` or `ERC721` tokens however, you'll have to remove all references to optional extensions (`ERC20Detailed`, `ERC721Enumerable`, etc.) - these have been included in the base contracts. The other exception to this are contracts that use the [**Gas Station Network (GSN)**](https://docs.openzeppelin.com/contracts/3.x/gsn) : if you're inheriting from `GSNRecipient` or one of the other GSN contracts, you'll need to add the following snippet to your contracts: function _msgSender() internal view override(Context, GSNRecipient) returns (address payable) { return GSNRecipient._msgSender(); } function _msgData() internal view override(Context, GSNRecipient) returns (bytes memory) { return GSNRecipient._msgData(); } [Using Hooks](https://docs.openzeppelin.com/contracts/5.x/changelog#using-hooks) --------------------------------------------------------------------------------- To improve library flexibility, we're introducing **hooks**: functions that are called at specific moments during a contract's operation that you can use to _hook_ into the internals and extend as you wish. For example, the `_beforeTokenTransfer` hook in ERC20, ERC721 and ERC777 makes it very easy to add additional checks or actions to execute whenever tokens are transferred, minted or burned, regardless of what prompted it. // Tokens can only be transferred, minted or burned if the contract is not paused contract ERC20Pausable is ERC20, Pausable { function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { super._beforeTokenTransfer(from, to, amount); require(!paused(), "ERC20Pausable: token transfer while paused"); } } As an additional benefit, using hooks will allow you to side-step some of the [edge-cases product of the new `override` keyword](https://github.com/ethereum/solidity/issues/8141) . Head over to our [brand new guide on Extending the OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/3.x/extending-contracts) to learn more! [What's Next](https://docs.openzeppelin.com/contracts/5.x/changelog#whats-next) -------------------------------------------------------------------------------- We've started work in some exciting features for the upcoming releases, including **fixed-point arithmetic** and the **ERC1155 token standard**. To read more and find out how you can contribute, check out our [Q2 2020 roadmap](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2207) ! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.5.0...v3.0.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-25-v250---2020-02-05) [OpenZeppelin Contracts 2.5 (v2.5.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.5.0) - 2020-02-05 ===================================================================================================================================================================================================================================== We're very happy the announce the release of **OpenZeppelin Contracts v2.5**! This new release features: * **`EnumerableSet`**: similar to Solidity's `mapping`, but that lets you retrieve all the keys! Useful for dapps that need to display a set of accounts with some property, and cannot rely on events alone. * **`Create2`**: a simple library for using the [CREATE2 opcode](https://eips.ethereum.org/EIPS/eip-1014) , allowing for deployment and pre-computation of addresses when using it. _To learn more about all the cool things you can do with it, head to [Getting the Most out of CREATE2](https://blog.openzeppelin.com/getting-the-most-out-of-create2/) _ * **`ERC721Metadata.baseURI`**: a neat extension for _massive_ gas savings when the token URIs share a prefix, like `https://my.cool.app/token/` There are also some minor improvements, such as gas optimizations for `ReentrancyGuard` and additional extensibility of `ERC777`, among others. _For the complete list of changes, head to our [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md) ._ To install the new release, run: $ npm install @openzeppelin/contracts@latest [New Documentation :books:](https://docs.openzeppelin.com/contracts/5.x/changelog#new-documentation-books) ----------------------------------------------------------------------------------------------------------- We've also recently done some some improvements to our [documentation website](https://forum.openzeppelin.com/t/revamped-documentation-site/2056) , including [new detailed guides](https://docs.openzeppelin.com/learn/) and documentation for our other tools, such as the [**Test Helpers**](https://docs.openzeppelin.com/test-helpers/0.5/) , our blazing-fast [**Test Environment**](https://docs.openzeppelin.com/test-environment/0.1/) and the [**OpenZeppelin Command Line Interface**](https://docs.openzeppelin.com/cli/2.6/) . Check them out for a radically better development experience! [Saying Goodbye to Solidity v0.5 :wave:](https://docs.openzeppelin.com/contracts/5.x/changelog#saying-goodbye-to-solidity-v05-wave) ------------------------------------------------------------------------------------------------------------------------------------ December 2019 saw the [release of Solidity v0.6](https://github.com/ethereum/solidity/releases/tag/v0.6.0) . This new version of the language has major improvements, and we're already underway to **release the next version of OpenZeppelin Contracts with support for Solidity v0.6**. However, it also includes _a lot_ of breaking changes, making it difficult to support both v0.5 and v0.6 code at the same time. For this reason, we've decided OpenZeppelin Contracts v2.5 will be the **last version supporting Solidity v0.5**. The exciting good news it that the next OpenZeppelin Contracts release will be v3.0, where we'll get to redesign some quirky bits of the library, improving ease of use and flexibility. Stay tuned! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.4.0...v2.5.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-24-v240---2019-11-01) [OpenZeppelin 2.4 (v2.4.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.4.0) - 2019-11-01 ================================================================================================================================================================================================================= In 2.4 we're releasing support for the Gas Station Network for user onboarding and metatransactions :fuelpump:, new functions to safeguard your contracts against the Istanbul hard fork, and improvements to error messages. Read the full announcement in the [OpenZeppelin Forum](https://forum.openzeppelin.com/t/openzeppelin-contracts-v2-4/1665) , and make sure to check out the details in the [changelog](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md#240-2019-10-29) ! Enjoy! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.3.0...v2.4.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-23-v230---2019-06-03) [OpenZeppelin 2.3 (v2.3.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.3.0) - 2019-06-03 ================================================================================================================================================================================================================= In 2.3 we're introducing **ERC777**, **revert reasons**, and **a new documentation site**. :fireworks: Take a look and tell us what you think in [the announcement thread](https://forum.zeppelin.solutions/t/openzeppelin-2-3/787) ! Take a look and tell us what you think! ### [ERC777](https://docs.openzeppelin.com/contracts/5.x/changelog#erc777) The long awaited sequel to ERC20. Its main additions are _transfer hooks_ and _operators_. Hooks let your contracts react to token transfers. In other words, running code when a contract receives tokens is a built-in feature: no more messing around with `approve` and `transferFrom`! The other special feature, operators, provides simpler and more flexible ways of delegating usage of your tokens to other people or contracts, like decentralized exchanges. All of this with full compatibility with ERC20! Start building on it and tell us what you think! We're looking for ideas for extensions, custom operators, or utilities. Share your ideas here or in a new thread. ### [Revert reasons](https://docs.openzeppelin.com/contracts/5.x/changelog#revert-reasons) Are you tired of running into cryptic errors like `VM Exception while processing transaction: revert`? All errors in OpenZeppelin now have proper error messages that will be displayed when you test your code! We've kept them succinct and to the point. Each error message is unique, so if you're having trouble figuring out exactly which `require` statement you've hit, it is easy to look up the error string in the source code, and look at the actual condition that is not being met. ### [Documentation site](https://docs.openzeppelin.com/contracts/5.x/changelog#documentation-site) We've revamped the docs, [take a look](https://docs.openzeppelin.org/) ! It'll be super helpful to both people looking to get started in smart contract development, and veteran OpenZeppelin users who just need to quickly recall a function signature. Among other improvements, we've bundled together related concepts, added overviews for each section, and added crosslinks to other contracts and functions to make exploring the docsite a breeze! Everything is automatically generated from the comments in the source code, so if you spot a typo or have a suggestion, simply open an issue or PR to get it sorted out in no time! _Some sections still require a bit of work to get them to where we want them to be, stay tuned!_ ### [More](https://docs.openzeppelin.com/contracts/5.x/changelog#more) Some more things are included in this release such as an implementation of ERC1820, and a fix for a bug in `PostDeliveryCrowdsale`. Take a look at the [changelog](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CHANGELOG.md#230-2019-05-27) ! We have revamped the documentation site infrastructure and feel, [take a look](https://docs.openzeppelin.org/) ! It'll be super helpful to both people looking to get started in smart contract development and OpenZeppelin, and veteran users who just need to quickly recall an API. Among other improvements, we've bundled together related concepts, added overviews for each section, and added crosslinks to other contracts and functions to make exploring the docsite a breeze! Everything is automatically generated from the comments in the source code, so if you spot a typo or have a suggestion, simply open an issue or PR to get it sorted out in no time! _Some sections still require a bit of work to get them to where we want them to be, stay tuned!_ ### [More](https://docs.openzeppelin.com/contracts/5.x/changelog#more-1) Some more things are included in this release such as an implementation of ERC1820, and a fix for a bug in `PostDeliveryCrowdsale`. Take a look at [the changelog](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CHANGELOG.md#230-2019-05-27) ! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.2.0...v2.3.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-22-v220---2019-03-14) [OpenZeppelin 2.2 (v2.2.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.2.0) - 2019-03-14 ================================================================================================================================================================================================================= _No changes from the release candidate for this one, we're ironing out the kinks in the release process! :no\_entry\_sign: :bug:_ This minor release includes a way to store token balances and supply so that they can be later queried in a gas-efficient manner :bookmark:, allows safe interaction with some old, non-compliant tokens :lock:, prevents user errors when using ECDSA signatures :memo: (the magic behind metatransactions! :sparkles:), and provides multiple minor additions and improvements to the API. To install the release run `npm install openzeppelin-solidity@latest`. We would love your help by reviewing newly added contracts, their interface and documentation so that we can make names clearer, features easier to use, and the library better as a whole! Your feedback is extremely useful to us :) [Highlights](https://docs.openzeppelin.com/contracts/5.x/changelog#highlights) ------------------------------------------------------------------------------- ### [New features](https://docs.openzeppelin.com/contracts/5.x/changelog#new-features) * `ERC20Snapshot`: this variant allows for snapshots to be created on demand, storing the current token balances and total supply so that they can be later retrieved in a gas-efficient manner and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617) ) * `SafeERC20`: the `ERC20` standard requires that all function calls (e.g. `transfer`, `approve`, etc.) return a boolean value indicating success. However, they are multiple widely used tokens out there that return no such value: they simply `revert` when encountering an error condition. Since Solidity v0.4.22, special code was needed to interact with this non-compliant tokens: now, all of `SafeERC20` can be used to safely call both compliant and non-compliant tokens, without the developer having to worry about it. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1655) ) * `TimedCrowdsale`: an internal `_extendTime(uint256 newClosingTime)` function was added (with a corresponding `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event) allowing for users to safely develop mechanisms to extend the durations of unclosed crowdsales. Note that due to it being internal, there's no out-of-the-box way to do it: this feature is opt-in and must be explicitly invoked by users. ### [Improvements](https://docs.openzeppelin.com/contracts/5.x/changelog#improvements) * `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). This helps prevent multiple issues when using signatures as unique identifiers. Read more about common ECDSA issues [here](https://yondon.blog/2019/01/01/how-not-to-use-ecdsa/) . ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622) ) * `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610) ) ### [Bugfixes:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfixes) * (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. This bug was reported independently by [@nikeshnazareth](https://github.com/nikeshnazareth) . Thanks a lot! ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647) ) ### [Breaking changes in drafts:](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-in-drafts) * `TokenMetadata` has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618) ) * The library `Counter` has been renamed to `Counters` and its API has been improved. See an example in `ERC721`, lines [17](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L17) and [204](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L204) . ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610) ) You can also see all details of this release in our [changelog](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CHANGELOG.md#220-2019-03-14) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.1.3...v2.2.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-213-v213---2019-02-26) [OpenZeppelin 2.1.3 (v2.1.3)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.3) - 2019-02-26 ==================================================================================================================================================================================================================== ### [Bugfix release :bug: :wrench:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfix-release-bug-wrench) A minor issue with `SafeERC20.safeApprove` was identified and reported independently by [@nikeshnazareth](https://github.com/nikeshnazareth) (thanks once again!), this release contains the correspondig fix: [OpenZeppelin/openzeppelin-solidity#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647) . This bug has been present since v2.0.0. Updating to this latest version is recommended, but no immediate emergency action should be required for production code using affected versions, due to the low severity of the issue. These independent reviews are a great way to keep our code secure and correct: we'll be making a push for a properly funded bug bounty during these next weeks to continue encouraging them. Stay tuned! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.0.1...v2.1.3) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-201-v201---2019-02-26) [OpenZeppelin 2.0.1 (v2.0.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.1) - 2019-02-26 ==================================================================================================================================================================================================================== ### [Bugfix release :bug: :wrench:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfix-release-bug-wrench-1) This is a backport of the 2.1.3 bugfix release for the 2.0.x line, which features Solidity v0.4.25 support: if you're still using OpenZeppelin v2.0.0, you can upgrade to this version instead of migrating to v2.1 and Solidity v0.5. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.1.2...v2.0.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-212-v212---2019-03-01) [OpenZeppelin 2.1.2 (v2.1.2)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.2) - 2019-03-01 ==================================================================================================================================================================================================================== This release was mostly the migration from Truffle 4 to Truffle 5, which should not affect end users. The only user facing change here is removing the tests and tests helpers from the npm package. If you used the test helpers, you will now find them in the [`openzeppelin-test-helpers`](https://github.com/OpenZeppelin/openzeppelin-test-helpers) package. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.1.1...v2.1.2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-21-v211---2019-01-04) [OpenZeppelin 2.1 (v2.1.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.1) - 2019-01-04 ================================================================================================================================================================================================================= ### [2.1 is finally out! :tada:](https://docs.openzeppelin.com/contracts/5.x/changelog#21-is-finally-out-tada) The most significant change is that OpenZeppelin now **works with Solidity 0.5.0**. This new release of the compiler introduced many breaking changes, and our old contracts were no longer compatible with it. After much discussion, we've decided to _drop the Solidity compiler version out of our stability guarantees_: in an attempt to both use the best possible tools and push the industry forward, our releases will target a recent compiler version, which may change between minor releases. This means that installing this new OpenZeppelin version will require you to upgrade your compiler to the 0.5.x line, which can be easily done with the recently released [`truffle v5.0.0`](https://github.com/trufflesuite/truffle/releases/tag/v5.0.0) . [The 2.0 release](https://github.com/OpenZeppelin/openzeppelin-solidity/releases/tag/v2.0.0) will be the last OpenZeppelin release with support for Solidity ^0.4.24, which we will still support in the form of bugfixes, if any are found. In general, if you're not sure whether you'll want to upgrade your compiler version, feel free to pin an OpenZeppelin version during installation: :pushpin: `npm install [[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) --save-exact` If you want to know more about our rationale behind this decision, and why we discarded other possible approaches, read [here](https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1498#issuecomment-449191611) . ### [Highlights](https://docs.openzeppelin.com/contracts/5.x/changelog#highlights-1) * Added `WhitelistCrowdsale`, a crowdsale where only whitelisted accounts (`WhitelistedRole`) can purchase tokens. Adding or removing accounts from the whitelist is done by whitelister admins (`WhitelistAdminRole`). Similar to the pre-2.0 `WhitelistedCrowdsale`. ([#1525](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1525) , [#1589](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1589) ) * `ERC20`'s `transferFrom` and `_burnFrom` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524) ) * `SignedSafeMath` now supports signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559) , [#1588](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1588) ) * `ERC20` and `ERC721` are now more gas efficient due to removed redundant `SSTORE`s and `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549) ) The first 2.1 release will be 2.1.1, due to a minor mishap that caused a conflict in the npm registry :man\_facepalming: :new: See the details in our brand new [CHANGELOG](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.1.1/CHANGELOG.md#210-2019-04-01) ! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v2.0.0...v2.1.1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-20-v200---2018-10-21) [OpenZeppelin 2.0 (v2.0.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.0) - 2018-10-21 ================================================================================================================================================================================================================= **OpenZeppelin 2.0 is finally here!!!** The major feature in this release is that we are now commiting to a stable API. In the process of stabilizing we've also reviewed a lot of the existing API in order to ensure a more straightforward experience for users. [Featuring...](https://docs.openzeppelin.com/contracts/5.x/changelog#featuring) -------------------------------------------------------------------------------- ### [Stable API](https://docs.openzeppelin.com/contracts/5.x/changelog#stable-api) So far OpenZeppelin's API has sometimes changed from release to release, in backwards-incompatible ways. This has enabled us to iterate on features and design ideas, but we're at a point now where we want to commit to having a stable API and delivering reliable updates. You can expect the external and internal API of contracts to remain stable. We're only making an exception to this for the contracts in the `drafts/` subdirectory; this is where ERCs in Draft status, as well as more experimental contracts will go, and might have breaking changes in minor versions. We'll be documenting exactly what stability guarantees we provide in the coming weeks. ### [Granular permissions](https://docs.openzeppelin.com/contracts/5.x/changelog#granular-permissions) Features which require permissions have used the almighty `Ownable` so far. We are now moving towards a more granular system of _roles_, like the [`MinterRole`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.0.0/contracts/access/roles/MinterRole.sol) . Just like `Ownable`, the creator of a contract is assigned all roles at first, but they can selectively give them out to other accounts. ### [Improved test suite](https://docs.openzeppelin.com/contracts/5.x/changelog#improved-test-suite) Although this is not visible to users, we have been improving the test suite, increasing coverage to 100%, and cleaning up all of our tests, which had diverged in style. This is part of a bigger effort towards making contributing easier and involving our amazing contributors more in the entire process of building OpenZeppelin. ### [A new audit](https://docs.openzeppelin.com/contracts/5.x/changelog#a-new-audit) The awesome [LevelK](https://www.levelk.io/) team audited our 2.0.0 Release Candidate and they found some severe issues and suggested many improvements. We fixed almost all the issues and notes they reported, leaving only a few minor details for 2.1.0. Check out the [LevelK Audit - OpenZeppelin 2.0 project](https://github.com/OpenZeppelin/openzeppelin-solidity/projects/2) for all the details. We want to thank [@cwhinfrey](https://github.com/cwhinfrey) , [@pcowgill](https://github.com/pcowgill) and [@shanefontaine](https://github.com/shanefontaine) for their very detailed reviews, high quality standards, and human support during the closing phase of this release. This audit gave us a great confidence boost on the code that we are now publishing. ### [Tons of community love](https://docs.openzeppelin.com/contracts/5.x/changelog#tons-of-community-love) Now hold your breath, because this release was only possible because of the contributions of many, many people from everywhere in the world, and we want to thank all of them: [@3sGgpQ8H](https://github.com/3sGgpQ8H) , [@Aniket-Engg](https://github.com/Aniket-Engg) , [@barakman](https://github.com/barakman) , [@BrendanChou](https://github.com/BrendanChou) , [@cardmaniac992](https://github.com/cardmaniac992) , [@dougiebuckets](https://github.com/dougiebuckets) , [@dwardu](https://github.com/dwardu) , [@facuspagnuolo](https://github.com/facuspagnuolo) , [@fulldecent](https://github.com/fulldecent) , [@glesaint](https://github.com/glesaint) , [@Glisch](https://github.com/Glisch) , [@jacobherrington](https://github.com/jacobherrington) , [@jbogacz](https://github.com/jbogacz) , [@jdetychey](https://github.com/jdetychey) , [@JeanoLee](https://github.com/JeanoLee) , [@k06a](https://github.com/k06a) , [@lamengao](https://github.com/lamengao) , [@ldub](https://github.com/ldub) , [@leonardoalt](https://github.com/leonardoalt) , [@Miraj98](https://github.com/Miraj98) , [@mswezey23](https://github.com/mswezey23) , [@pw94](https://github.com/pw94) , [@shishir99111](https://github.com/shishir99111) , [@sohkai](https://github.com/sohkai) , [@sweatyc](https://github.com/sweatyc) , [@tinchoabbate](https://github.com/tinchoabbate) , [@tinchou](https://github.com/tinchou) , [@urvalla](https://github.com/urvalla) , [@viquezclaudio](https://github.com/viquezclaudio) , [@vyomshm](https://github.com/vyomshm) , [@yaronvel](https://github.com/yaronvel) , [@ZumZoom](https://github.com/ZumZoom) . Also we would like to thank all the people who are constantly helping others in [our Slack channel](https://slack.openzeppelin.org/) , the ones who have given us feedback about the release, and the ones helping us triage and discuss our GitHub issues. If you are reading this wanting to jump in and make your first free software contributions, but you are unsure of where and how, talk to us! We can help you getting started, and we could use the extra hands. With ❤️ from the maintainers team of this release. -- [@shrugs](https://github.com/shrugs) , [@nventuro](https://github.com/nventuro) , [@frangio](https://github.com/frangio) and [@elopio](https://github.com/elopio) [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-1) ------------------------------------------------------------------------------- The changelog is pretty big. We are introducing new concepts and new designs, together with many renames and restructures. If you have problems, comments or suggestions, please join [our Slack channel](https://slack.openzeppelin.org/) . [https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.12.0...v2.0.0](https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.12.0...v2.0.0) * `Ownable` contracts have moved to role based access. ([#1291](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1291) , [#1302](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1302) , [#1303](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1303) ) * ERC contracts have all been renamed to follow the same convention. The interfaces are called `IERC##`, and their implementations are `ERC##`. Check out, for example, [`IERC20`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.0.0/contracts/token/ERC20/IERC20.sol) and [`ERC20`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.0.0/contracts/token/ERC20/ERC20.sol) . ([#1252](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1252) , [#1288](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1288) ) * All state variables are now `private`, which means that derived contracts cannot access them directly, but have to use getters. This is to increase encapsulation, to be able to reason better about the code. ([#1197](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1197) , [#1265](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1265) , [#1267](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1267) , [#1269](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1269) , [#1270](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1270) , [#1268](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1268) , [#1281](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1281) ) * Events have been changed to be consistently in the past tense except for those which are defined by an ERC. ([#1181](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1181) ) * Separated `ERC721` into the different optional interfaces, and introduced `ERC721Full` which implements all. ([#1304](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1304) ) * Added `ERC165Query` to query support for ERC165 interfaces. ([#1086](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1086) ) * Added an experimental contract for migration between ERC20 tokens. ([#1054](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1054) ) * Added `SafeMath.mod`. ([#915](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/915) ) * Added `Math.average`. ([#1170](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1170) ) * Added `ERC721Pausable`. ([#1154](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1154) ) * Changed `SafeMath` to use `require` instead of `assert`. ([#1187](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1187) , [#1120](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1120) , interesting discussion!) * Removed restriction on who can release funds in `PullPayments`, `PaymentSplitter`, `PostDeliveryCrowdsale`, `RefundableCrowdsale`. ([#1275](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1275) ) * Optimized `ReentrancyMutex` gas usage. ([#1155](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1155) ) * Made `ERC721.exists` internal. ([#1193](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1193) ) * Changed preconditions on `PaymentSplitter` constructor arguments. ([#1131](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1131) ) * Fixed `ERC721.getApproved` to be in compliance with spec. ([#1256](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1256) ) * Simplified interface of `IndividuallyCappedCrowdsale`. ([#1296](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1296) ) * Renamed `ERC20.decreaseApproval` to `decreaseAllowance`, and changed its semantics slightly to be more secure. ([#1293](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1293) ) * Renamed `MerkleProof.verifyProof` to `MerkleProof.verify`. ([#1294](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1294) ) * Renamed `ECRecovery` to `ECDSA`, and `AddressUtils` to `Address`. ([#1253](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1253) ) * Moved `ECDSA` and `MerkleProof` to a `cryptography/` subdirectory. ([#1253](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1253) ) * Moved `ReentrancyGuard`, and `Address` to a `utils/` subdirectory. ([#1253](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1253) ) * Renamed `proposals/` subdirectory to `drafts/`. ([#1271](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1271) ) * Moved `TokenVesting`, `SignatureBouncer` to `drafts/`. ([#1271](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1271) ) * Removed `ERC20Basic`, now there's only `ERC20`. ([#1125](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1125) ) * Removed `Math.min64` and `Math.max64`, left only the `uint256` variants. ([#1156](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1156) ) * Removed `Mint` and `Burn` events from `ERC20Mintable` and `ERC20Burnable`. ([#1305](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1305) ) * Removed underscores from event arguments. ([#1258](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1258) ) * Removed a few contracts that we thought were not generally secure enough: `LimitBalance`, `HasNoEther`, `HasNoTokens`, `HasNoContracts`, `NoOwner`, `Destructible`, `TokenDestructible`, `CanReclaimToken`. ([#1253](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1253) , [#1254](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1254) , [#1306](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1306) ) * Removed extensions of `Owable`: `Claimable`, `DelayedClaimable`, `Heritable`. ([#1274](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1274) ) * Renamed `AutoIncrementing` to `Counter` and moved it to `drafts\`. ((1307, [#1332](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1332) ) * Added events to roles on construction and when renouncing. ([#1329](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1329) ) * Separated `ERC721Mintable` into two contracts, one with metadata (token URI) and one without. ([#1365](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1365) ) * Added an ERC20 internal \_transfer function. ([#1370](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1370) ) * Added an `Arrays` library. ([#1375](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1375) ) * Improved the `OwnershipTransfer` event and removed `OwnershipRenounced`. ([#1397](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1397) ) * Removed the `BreakInvariantBounty` contract because of a front-running issue. ([#1424](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1424) ) * Improved encapsulation on `ERC165` making the `_supportedInterfaces` map private. ([#1379](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1379) ) * Renamed `RefundsEscrow` event to `RefundsClosed`. ([#1418](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1418) ) * Moved `Escrow` and `RefundsEscrow` to `contracts/payment/escrow/`. ([#1430](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1430) ) * Made private the `TokenVesting` functions `_releasableAmount` and `_vestedAmount`. ([#1427](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1427) ) * Made internal the constructors of contracts that should only be used inherited from others. ([#1433](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1433) , [#1439](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1439) ) * Renamed `ERC165` function `supportsInterfaces` to `_supportsAllInterfaces`. ([#1435](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1435) ) * Added the `address` to `Paused` and `Unpaused` events. ([#1410](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1410) ) * Renamed `SplitPayment` to `PaymentSplitter`, and added the events `PayeeAdded`, `PaymentReleased` and `PaymentReceived`. ([#1417](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1417) ) * Renamed the `TokenVesting` events to `TokensReleased` and `TokenVestingRevoked`. ([#1431](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1431) ) * Improved the `SafeERC20` allowance handling. ([#1407](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1407) ) * Made `getCurrentRate` from `IncreasingPriceCrowdsale` return 0 when the crowdsale is not open. ([#1442](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1442) ) * Made `tokenURI` from `ERC721Metadata` external, to match the specification. ([#1444](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1444) ) * Fixed a reentrancy issue on `FinalizableCrowdsale`. ([#1447](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1447) ) * Fixed how allowance crowdsale checks remaining tokens. ([#1449](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1449) ) * Added the nonReentrant safeguard for buyTokens in the Crowdsale contract. ([#1438](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1438) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.12.0...v2.0.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1120---2018-08-11) [v1.12.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.12.0) - 2018-08-11 ================================================================================================================================================================================= And thus concludes another release cycle of OpenZeppelin! :smile: Among other things, we have been busy enhancing the quality and consistency of the test suite. We think this will improve the experience for future contributors. Check it out! :bookmark\_tabs: :raised\_hands: This is the last release before our planned 2.0 release, which will mark a commitment to a stable API. Keep an eye out for it! :eye: [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-2) =============================================================================== [https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.11.0...v1.12.0](https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.11.0...v1.12.0) [Additions](https://docs.openzeppelin.com/contracts/5.x/changelog#additions) ----------------------------------------------------------------------------- * We now have a [code of conduct](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v1.12.0/CODE_OF_CONDUCT.md) ! ([#1061](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1061) ) * A small library with a `Counter` datatype. ([#1023](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1023) ) * A description in the README of the different categories of contracts we have and their organization. ([#1089](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1089) ) [Improvements](https://docs.openzeppelin.com/contracts/5.x/changelog#improvements-1) ------------------------------------------------------------------------------------- * Moved ERC165 interface IDs to interface contracts. ([#1070](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1070) ) * Moved `RBAC` contract to the `access` directory. ([#1114](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1114) ) * Fixed an inheritance order that was causing some contracts to fail linearization. ([#1128](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1128) ) * Lots of test improvements, including the removal of Babel. ([#1009](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1009) , [#1050](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1050) , [#1074](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1074) , [#1094](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1094) , [#1116](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1116) , [#1112](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1112) , [#1117](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1117) ) * Fix `assertRevert` test helper. ([#1123](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1123) ) * Some gas optimizations. ([#1043](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1043) , [#1063](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1063) , [#1030](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1030) , [#1017](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1017) , [#1057](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1057) ) * Removed unnecessary `payable` constructor from `Destructible`. ([#1107](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1107) ) * Documentation tidbits. ([#1035](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1035) , [#1082](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1082) , [#1084](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1084) , [#1083](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1083) , [#1060](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1060) , [#1101](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1101) ) * Made code style more consistent with prefix underscore in all arguments. ([#1133](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1133) ) * Fixes for Solidity 0.5.0. ([#1080](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1080) , [#1134](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1134) ) * Silenced a compilation warning in `HasNoTokens`. ([#1122](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1122) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.11.0...v1.12.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1110---2018-07-13) [v1.11.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.11.0) - 2018-07-13 ================================================================================================================================================================================= We hit our 1000th issue during this release cycle! Congrats to everyone and thank you for the hard work. :smile: [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-3) =============================================================================== [https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.10.0...v1.11.0](https://github.com/OpenZeppelin/openzeppelin-solidity/compare/v1.10.0...v1.11.0) [Added](https://docs.openzeppelin.com/contracts/5.x/changelog#added) --------------------------------------------------------------------- * :card\_file\_box: `Escrow`, a new class of contracts that we used to enhance the security of `PullPayments`. ([#1014](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1014) ) * :writing\_hand: `isValidSignatureAndData`, a new method of `SignatureBouncer` to validate signed function calls. ([#973](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/973) ) * :memo: Initial implementation of ERC1046. ([#933](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/933) ) [Changed](https://docs.openzeppelin.com/contracts/5.x/changelog#changed) ------------------------------------------------------------------------- * :volcano: Updated the ERC721 contracts to the final version of the protocol. ([#972](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/972) , [#993](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/993) , [#1047](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1047) ) * :shark: Updated minor things for the newer versions of Solidity. ([#951](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/951) , [#1002](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1002) , [#1008](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1008) , [#1033](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1033) ) * :shield: Fixed unchecked token transfer in `Crowdsale`. ([#1006](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1006) ) * :seat: Moved `Whitelist` to `access` directory. ([#994](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/994) ) [Removed](https://docs.openzeppelin.com/contracts/5.x/changelog#removed) ------------------------------------------------------------------------- * :warning: We removed the implementation of ERC827 due to concerns about its security ([#1044](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1044) ). The code was moved to [windingtree/erc827](https://github.com/windingtree/erc827) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.10.0...v1.11.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1100---2018-06-05) [v1.10.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.10.0) - 2018-06-05 ================================================================================================================================================================================= The release includes the new `constructor` syntax in Solidity (goodbye warnings :wave:). :tada: :tada: :tada: [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-4) =============================================================================== [https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.9.0...v1.10.0](https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.9.0...v1.10.0) * Updated contracts for Solidity 0.4.23 including the new `constructor` syntax ([OpenZeppelin/openzeppelin-solidity#921](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/921) ) * Added `renounceOwnership` to `Ownable` ([OpenZeppelin/openzeppelin-solidity#907](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/907) ) * Added `Superuser`, an extension of `Ownable` with an emergency mechanism ([OpenZeppelin/openzeppelin-solidity#952](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/952) , [OpenZeppelin/openzeppelin-solidity#978](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/978) ) * Added an `Ownable` "behavior" to test that your ownable contracts do not break the semantics ([OpenZeppelin/openzeppelin-solidity#929](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/929) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.9.0...v1.10.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v190---2018-04-27) [v1.9.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.9.0) - 2018-04-27 ============================================================================================================================================================================== :warning: Beginning with this release we're renaming the npm package to **openzeppelin-solidity**. Make sure to update your dependencies! The release includes the new `emit` keyword in Solidity, some new functionality, and other enhancements. Thanks everyone for participating! :tada: :tada: :tada: [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-5) =============================================================================== [https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.8.0...v1.9.0](https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.8.0...v1.9.0) * :ribbon: Updated our contracts for Solidity 0.4.21, including the new `emit` keyword ([#876](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/876) ) * :fire: Added `StandardBurnableToken` with a `burnFrom` function ([#870](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/870) ) * :woman\_teacher: Changed `MerkleProof` interface slightly ([#879](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/879) ) * :policewoman: Removed admin functionality from RBAC ([#836](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/836) ) * :memo: Changes to ERC827 ([#871](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/871) , [#838](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/838) ) * :wrench: Cleaned up the npm package files and dependencies ([#843](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/843) , [#904](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/904) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.8.0...v1.9.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v180---2018-03-23) [v1.8.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.8.0) - 2018-03-23 ============================================================================================================================================================================== This release contains the full implementation of EIP721, following the last details settled in the [recently closed EIP](https://github.com/ethereum/EIPs/blob/a235dd38b9434bd3f6a8eb4d71550a2f1ef0ce24/EIPS/eip-721.md) . Thanks to all the community for your contributions! 🚀 [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-6) =============================================================================== [https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.7.0...v1.8.0](https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.7.0...v1.8.0) * ✨ Final EIP721 implementation ([#803](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/803) ) * 🔥 Add `Transfer` event to [`BurnableToken`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.8.0/contracts/token/ERC20/BurnableToken.sol) ([#735](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/735) ) * 👨‍🏫 `ECRecovery` [`recover`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.8.0/contracts/ECRecovery.sol#L17) is now internal ([#818](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/818) ) * 💅 Documentation and tests enhancements [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.7.0...v1.8.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v170---2018-02-20) [v1.7.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.7.0) - 2018-02-20 ============================================================================================================================================================================== This release contains a big refactor of the `Crowdsale` contract, which allowed us to implement some really cool new crowdsale models. We also have a [shiny new documentation site](https://openzeppelin.org/api/docs/open-zeppelin.html) . Thanks to all the community for the awesome contributions! :rocket: [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-7) =============================================================================== [https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.6.0...v1.7.0](https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.6.0...v1.7.0) * :warning: Big `Crowdsale` refactor, including breaking changes ([OpenZeppelin/zeppelin-solidity#744](https://github.com/OpenZeppelin/zeppelin-solidity/pull/744) ) * :new: new crowdsale models ([OpenZeppelin/zeppelin-solidity#744](https://github.com/OpenZeppelin/zeppelin-solidity/pull/744) ) * [`WhitelistedCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/validation/WhitelistedCrowdsale.sol) * [`IndividuallyCappedCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol) , * [`PostDeliveryCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol) * [`AllowanceCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/emission/AllowanceCrowdsale.sol) * [`IncreasingPriceCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/price/IncreasingPriceCrowdsale.sol) * Original `Crowdsale` contract refactored into [`Crowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/Crowdsale.sol) , [`TimedCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/validation/TimedCrowdsale.sol) and [`MintedCrowdsale`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.7.0/contracts/crowdsale/emission/MintedCrowdsale.sol) . * :bow\_and\_arrow: Move token creation outside of `Crowdsale` contract ([OpenZeppelin/zeppelin-solidity#690](https://github.com/OpenZeppelin/zeppelin-solidity/pull/690) ) * :crown: `Heritable` improvements ([OpenZeppelin/zeppelin-solidity#702](https://github.com/OpenZeppelin/zeppelin-solidity/pull/702) ) [Project updates:](https://docs.openzeppelin.com/contracts/5.x/changelog#project-updates) ========================================================================================== * :blue\_book: [New documentation site](https://openzeppelin.org/api/docs/open-zeppelin.html) ! ([OpenZeppelin/zeppelin-solidity#750](https://github.com/OpenZeppelin/zeppelin-solidity/pull/750) ) * :octocat: Update GitHub Pull Request templates ([OpenZeppelin/zeppelin-solidity#699](https://github.com/OpenZeppelin/zeppelin-solidity/pull/699) ) * :wrench: Minor tweaks for test artifact imports ([OpenZeppelin/zeppelin-solidity#698](https://github.com/OpenZeppelin/zeppelin-solidity/pull/698) ) * :male\_detective: Improve test coverage ([OpenZeppelin/zeppelin-solidity#712](https://github.com/OpenZeppelin/zeppelin-solidity/pull/712) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.6.0...v1.7.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v160---2018-01-23) [v1.6.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.6.0) - 2018-01-23 ============================================================================================================================================================================== This time we bring you a new release, which includes the much hyped ERC721 for non-fungible tokens, to create your own digital collectibles and more. 🐈 🌍 🚀 🎉 During this release cycle the team has been very active improving the development process itself, and we're already seeing great results in the speed with which we respond to new issues and PRs. Take a peek at the status of development at [our waffle.io board](https://waffle.io/OpenZeppelin/zeppelin-solidity) . We'll be waiting for your contributions! [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-8) =============================================================================== [v1.5.0...v1.6.0](https://github.com/OpenZeppelin/zeppelin-solidity/compare/v1.5.0...v1.6.0) * 🆕 Added [`ERC721`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.6.0/contracts/token/ERC721/ERC721Token.sol) non-fungible token implementation ([#615](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/615) ) 🐈 * 🆕 Added [`ERC827`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.6.0/contracts/token/ERC827/ERC827Token.sol) token implementation provides `transfer`, `transferFrom` and `approve` methods which additionally perform a call to the recipients ([#518](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/518) ) * 🆕 Added [`Heritable`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.6.0/contracts/lifecycle/Heritable.sol) , an extension of `Ownable` with a designated heir ([#680](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/680) ) * Added [`getTokenAmount`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.6.0/contracts/crowdsale/Crowdsale.sol#L92-L95) for dynamic rate crowdsales ([#638](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/638) ) * Added the `totalSupply` function to the ERC20 interface ([#666](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/666) ) [Project changes](https://docs.openzeppelin.com/contracts/5.x/changelog#project-changes) ----------------------------------------------------------------------------------------- * Enhanced tests and documentation * Updated documentation for contributors ([#684](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/684) ) * Added Issue/PR templates ([#641](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/641) ) * Added linting configuration and Travis CI step ([#673](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/673) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.5.0...v1.6.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v150---2017-12-22) [v1.5.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.5.0) - 2017-12-22 ============================================================================================================================================================================== A small release this time to keep the release cycle going! 🚀 [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-9) =============================================================================== * 🆕 Added [`RBAC`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.5.0/contracts/ownership/rbac/RBAC.sol) to enable more complex access control patterns. ([#580](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/580) ) * Several enhancements to project quality. ([#581](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/581) ) * And a few small changes. 🙂 [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.4.0...v1.5.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v140---2017-11-23) [v1.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.4.0) - 2017-11-23 ============================================================================================================================================================================== Thanks to all members of the community that contributed to this release! 🎉 🚀 [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-10) ================================================================================ * 🆕 Added [`TokenVesting`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.4.0/contracts/token/TokenVesting.sol) which implements vesting of tokens. It replaces the old [`VestedToken`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.3.0/contracts/token/VestedToken.sol) with a more modular approach. ([#476](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/476) ) * 🆕 Added [`SplitPayment`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.4.0/contracts/payment/SplitPayment.sol) which implements distributing payments to multiple people proportionally to shares. ([#417](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/417) ) * 🆕 Added [`DetailedERC20`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.4.0/contracts/token/DetailedERC20.sol) which adds to a token state variables with the optional ERC20 metadata. ([#477](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/477) ) * 🆕 Added [`CappedToken`](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.4.0/contracts/token/CappedToken.sol) which is a `MintableToken` with capped supply. ([#515](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/515) ) * Made `MintableToken`'s `finishMinting` executable only once. ([#505](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/505) ) * Upgraded to Truffle 4.0.1 and Solidity 0.4.18. ([#573](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/573) , [#460](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/460) , [#576](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/576) , [#506](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/506) ) * Removed deprecated `claim()` from `TokenTimelock`. ([#469](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/469) ) And some additional changes to code style, tests, documentation and continuous integration. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.3.0...v1.4.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v130---2017-09-21) [v1.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.3.0) - 2017-09-21 ============================================================================================================================================================================== After a long wait, we're finally releasing version 1.3.0 of OpenZeppelin. This is a big release with a lot of small fixes, exciting new features, and enhancements to the developer experience. This release includes commits from 29 contributors! Huge thanks to all of you! 🎉 🎉 [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-11) -------------------------------------------------------------------------------- * Removed `MultisigWallet` in favor of [gnosis/MultiSigWallet](https://github.com/gnosis/MultiSigWallet) . ([#328](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/328) ) * Added [a directory](https://github.com/OpenZeppelin/zeppelin-solidity/blob/v1.3.0/contracts/examples) with examples. ([#333](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/333) , [#342](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/342) ) * Migrated the crowdsale contracts to timestamps instead of block numbers. ([#350](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/350) ) * Removed the call to `finishMinting` in `FinalizableCrowdsale`. ([#364](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/364) ) * Made `approve` pausable in `PausableToken`. ([#448](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/448) ) * Added an `OwnershipTransferred` event. ([#424](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/424) ) * Added the `BurnableToken` contract. ([#341](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/341) ) * Added the `CanReclaimToken` contract. ([#348](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/348) ) * Added the `SafeERC20` library for interaction with ERC20 tokens. ([#413](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/413) ) * Added the `MerkleProof` library for merkle proof verification. ([#260](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/260) ) * Fixed some small issues in ERC20 compliance. ([#345](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/345) , [#405](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/405) , [#446](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/446) ) * Fixed a bug in `transferFrom`. ([#377](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/377) ) * Fixed `transferOwnership` to `revert` on failure instead of silently failing. ([#323](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/323) ) * Fixed a bug in `TokenTimelock`. ([#430](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/430) ) * Several enhancements to tests and documentation. * Parallelized coverage and tests in Travis for faster test results in PRs. ([#369](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/369) ) * Removed the only production dependency (was actually a dev dependency). Now installing via `npm install --only=prod zeppelin-solidity` should install zero extra dependencies! ([#357](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/357) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.2.0...v1.3.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v120---2017-07-18) [v1.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.2.0) - 2017-07-18 ============================================================================================================================================================================== [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-12) ================================================================================ * Fix ERC20 interface and implementations to [conform to standard](https://github.com/ethereum/EIPs/pull/610) . * Rename `claim` to `release` in `TokenTimelock`. * Bugfixes in `VestedToken`. * Deprecated `throw` in favor of `require()`, `assert()` and `revert()`. * Small improvements on crowdsale contracts. * Added `ECRecovery` library. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.1.0...v1.2.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v110---2017-07-02) [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.1.0) - 2017-07-02 ============================================================================================================================================================================== [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-13) ================================================================================ * Add [Crowdsale contracts](https://github.com/OpenZeppelin/zeppelin-solidity/tree/f507a0ea29f44bebb1e3d94fcc97ea5808915dab/contracts/crowdsale) . * Add a [TokenTimelock contract](https://github.com/OpenZeppelin/zeppelin-solidity/blob/f507a0ea29f44bebb1e3d94fcc97ea5808915dab/contracts/token/TokenTimelock.sol) . * Add coveralls and move npm to yarn for TravisCI. * Upgrade to Truffle version 3.2.2 and Solidity version 0.4.11 * Other minor refactors and fixes. * Extract some functions of `SafeMath` into `Math`. * Remove all checks for short address attack (see: [OpenZeppelin/zeppelin-solidity#261](https://github.com/OpenZeppelin/zeppelin-solidity/issues/261) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.0.6...v1.1.0) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v106---2017-05-29) [v1.0.6](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.6) - 2017-05-29 ============================================================================================================================================================================== [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-14) ================================================================================ * Add external audit report to repo. * Minor improvements to `Destructible`. * Revert to usig npm as preferred installation method, as ethpm is still immature. * Add solidity-coverage * Add natspec documentation * Add revokability and burnablity options to `VestedToken` and general refactor and optimizations [Security](https://docs.openzeppelin.com/contracts/5.x/changelog#security) --------------------------------------------------------------------------- * Add fix for the `approve()` mitigation. * Protect `transferFrom` against short hand attack. * Fix attack on `VestedToken#grantVestedTokens()` Thanks to [@misteraverin](https://github.com/misteraverin) , [@miohtama](https://github.com/miohtama) , [@izqui](https://github.com/izqui) , [@cgewecke](https://github.com/cgewecke) , [@maurelian](https://github.com/maurelian) , [@JGcarv](https://github.com/JGcarv) and [@DavidKnott](https://github.com/DavidKnott) for your contributions to this release! [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.0.5...v1.0.6) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v105---2017-05-09) [v1.0.5](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.5) - 2017-05-09 ============================================================================================================================================================================== [Changelog:](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-15) ================================================================================= * Added new `TokenDestructible` lifecycle helper for contracts that want to transfer owned tokens when destroyed. * Decouple transferable logic from `VestedToken` as `LimitedTransferToken`. * Added new ownership helpers `HasNoEther`, `HasNoContracts`, `NoOwner`. * Added `ReentrancyGuard` to prevent contract from calling itself, directly or indirectly. * Several refactors and small fixes. * New `MintableToken` token with minting functions. * New `PausableToken` token with pausable transfers (it's a `Pausable` instance) * Make SafeMath a library. * External audit security fixes. (Audit link will be published soon). Thanks to [@Recmo](https://github.com/Recmo) , [@izqui](https://github.com/izqui) , [@demibrener](https://github.com/demibrener) , [@frangio](https://github.com/frangio) , [@roderik](https://github.com/roderik) , [@jdetychey](https://github.com/jdetychey) , [@DavidKnott](https://github.com/DavidKnott) , [@lastperson](https://github.com/lastperson) , [@tatiesmars](https://github.com/tatiesmars) , [@AugustoL](https://github.com/AugustoL) , [@ORBAT](https://github.com/ORBAT) for your contributions! This release wouldn't be the same without your work. [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/compare/v1.0.4...v1.0.5) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v104---2017-03-09) [v1.0.4](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.4) - 2017-03-09 ============================================================================================================================================================================== * Add integration and publish to [ethpm](https://www.ethpm.com/) . [Changes](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v1.0.4) [FAQ\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/faq) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/api) ### On this page [](https://docs.openzeppelin.com/contracts/5.x/changelog#v540---2025-07-17) [v5.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.4.0) - 2025-07-17[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes) [Pragma changes](https://docs.openzeppelin.com/contracts/5.x/changelog#pragma-changes) [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category) [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account) [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance) [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens) [Cryptography](https://docs.openzeppelin.com/contracts/5.x/changelog#cryptography) [Signers](https://docs.openzeppelin.com/contracts/5.x/changelog#signers) [Verifiers](https://docs.openzeppelin.com/contracts/5.x/changelog#verifiers) [Other](https://docs.openzeppelin.com/contracts/5.x/changelog#other) [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures) [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v530---2025-04-09) [v5.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.3.0) - 2025-04-09[Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-1) [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes) [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-1) [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account-1) [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-1) [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures-1) [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-1) [Other](https://docs.openzeppelin.com/contracts/5.x/changelog#other-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v520---2025-01-09) [v5.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.2.0) - 2025-01-09[Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-2) [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes-1) [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-2) [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general) [Account](https://docs.openzeppelin.com/contracts/5.x/changelog#account-2) [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-2) [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy) [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-2) [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v510---2024-10-23) [v5.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.1.0) - 2024-10-23[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-3) [Custom error changes](https://docs.openzeppelin.com/contracts/5.x/changelog#custom-error-changes-2) [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-3) [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general-1) [Access](https://docs.openzeppelin.com/contracts/5.x/changelog#access) [Finance](https://docs.openzeppelin.com/contracts/5.x/changelog#finance) [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-3) [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy-1) [Tokens](https://docs.openzeppelin.com/contracts/5.x/changelog#tokens-3) [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-2) [Cryptography](https://docs.openzeppelin.com/contracts/5.x/changelog#cryptography-1) [Math](https://docs.openzeppelin.com/contracts/5.x/changelog#math) [Structures](https://docs.openzeppelin.com/contracts/5.x/changelog#structures-2) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v502---2024-02-29) [v5.0.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.2) - 2024-02-29[](https://docs.openzeppelin.com/contracts/5.x/changelog#v496---2024-02-29) [v4.9.6](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.6) - 2024-02-29[](https://docs.openzeppelin.com/contracts/5.x/changelog#v495---2023-12-08) [v4.9.5](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.5) - 2023-12-08[](https://docs.openzeppelin.com/contracts/5.x/changelog#v501---2023-12-07) [v5.0.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.1) - 2023-12-07[](https://docs.openzeppelin.com/contracts/5.x/changelog#v494---2023-12-07) [v4.9.4](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.4) - 2023-12-07[](https://docs.openzeppelin.com/contracts/5.x/changelog#v500---2023-10-05) [v5.0.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v5.0.0) - 2023-10-05[Additions Summary](https://docs.openzeppelin.com/contracts/5.x/changelog#additions-summary) [Removals Summary](https://docs.openzeppelin.com/contracts/5.x/changelog#removals-summary) [Changes by category](https://docs.openzeppelin.com/contracts/5.x/changelog#changes-by-category-4) [General](https://docs.openzeppelin.com/contracts/5.x/changelog#general-2) [Access](https://docs.openzeppelin.com/contracts/5.x/changelog#access-1) [Finance](https://docs.openzeppelin.com/contracts/5.x/changelog#finance-1) [Governance](https://docs.openzeppelin.com/contracts/5.x/changelog#governance-4) [Metatx](https://docs.openzeppelin.com/contracts/5.x/changelog#metatx) [Proxy](https://docs.openzeppelin.com/contracts/5.x/changelog#proxy-2) [Token](https://docs.openzeppelin.com/contracts/5.x/changelog#token) [Utils](https://docs.openzeppelin.com/contracts/5.x/changelog#utils-3) [How to migrate from 4.x](https://docs.openzeppelin.com/contracts/5.x/changelog#how-to-migrate-from-4x) [ERC20, ERC721, and ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#erc20-erc721-and-erc1155) [More about ERC721](https://docs.openzeppelin.com/contracts/5.x/changelog#more-about-erc721) [More about ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#more-about-erc1155) [ERC165Storage](https://docs.openzeppelin.com/contracts/5.x/changelog#erc165storage) [SafeMath](https://docs.openzeppelin.com/contracts/5.x/changelog#safemath) [Adapting Governor modules](https://docs.openzeppelin.com/contracts/5.x/changelog#adapting-governor-modules) [ECDSA and MessageHashUtils](https://docs.openzeppelin.com/contracts/5.x/changelog#ecdsa-and-messagehashutils) [Interfaces and libraries in upgradeable contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#interfaces-and-libraries-in-upgradeable-contracts) [Offchain Considerations](https://docs.openzeppelin.com/contracts/5.x/changelog#offchain-considerations) [Relying on revert strings for processing errors](https://docs.openzeppelin.com/contracts/5.x/changelog#relying-on-revert-strings-for-processing-errors) [Relying on storage locations for retrieving data](https://docs.openzeppelin.com/contracts/5.x/changelog#relying-on-storage-locations-for-retrieving-data) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v493---2023-07-28) [v4.9.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.3) - 2023-07-28[](https://docs.openzeppelin.com/contracts/5.x/changelog#v492---2023-06-16) [v4.9.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.2) - 2023-06-16[](https://docs.openzeppelin.com/contracts/5.x/changelog#v491---2023-06-07) [v4.9.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.1) - 2023-06-07[](https://docs.openzeppelin.com/contracts/5.x/changelog#v490---2023-05-23) [v4.9.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.9.0) - 2023-05-23[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-4) [Deprecations](https://docs.openzeppelin.com/contracts/5.x/changelog#deprecations) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v483---2023-04-13) [v4.8.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.3) - 2023-04-13[](https://docs.openzeppelin.com/contracts/5.x/changelog#v482---2023-03-02) [v4.8.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.2) - 2023-03-02[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-5) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v481---2023-01-13) [v4.8.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.1) - 2023-01-13[](https://docs.openzeppelin.com/contracts/5.x/changelog#v480---2022-11-08) [v4.8.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.0) - 2022-11-08[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-6) [Deprecations](https://docs.openzeppelin.com/contracts/5.x/changelog#deprecations-1) [ERC-721 Compatibility Note](https://docs.openzeppelin.com/contracts/5.x/changelog#erc-721-compatibility-note) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v473---2022-08-10) [v4.7.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.3) - 2022-08-10[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-7) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v472---2022-07-28) [v4.7.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.2) - 2022-07-28[](https://docs.openzeppelin.com/contracts/5.x/changelog#v471---2022-07-20) [v4.7.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.1) - 2022-07-20[](https://docs.openzeppelin.com/contracts/5.x/changelog#v470---2022-06-30) [v4.7.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.7.0) - 2022-06-30[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-8) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v460---2022-04-29) [v4.6.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.6.0) - 2022-04-29[Upgradeability notice](https://docs.openzeppelin.com/contracts/5.x/changelog#upgradeability-notice) [Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-9) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v450---2022-02-09) [v4.5.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.5.0) - 2022-02-09[Breaking changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-10) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v442---2022-01-11) [v4.4.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.2) - 2022-01-11[](https://docs.openzeppelin.com/contracts/5.x/changelog#v441---2021-12-14) [v4.4.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.1) - 2021-12-14[Breaking change](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-change) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v440---2021-11-25) [v4.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.0) - 2021-11-25[](https://docs.openzeppelin.com/contracts/5.x/changelog#v433---2021-11-15) [v4.3.3](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.3) - 2021-11-15[](https://docs.openzeppelin.com/contracts/5.x/changelog#v432---2021-09-14) [v4.3.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.2) - 2021-09-14[](https://docs.openzeppelin.com/contracts/5.x/changelog#v431---2021-08-26) [v4.3.1](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.1) - 2021-08-26[](https://docs.openzeppelin.com/contracts/5.x/changelog#v342-solc-07---2021-08-26) [v3.4.2-solc-0.7](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.2-solc-0.7) - 2021-08-26[](https://docs.openzeppelin.com/contracts/5.x/changelog#v342---2021-08-26) [v3.4.2](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.2) - 2021-08-26[](https://docs.openzeppelin.com/contracts/5.x/changelog#v430---2021-08-17) [v4.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.3.0) - 2021-08-17[](https://docs.openzeppelin.com/contracts/5.x/changelog#v420---2021-06-30) [v4.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.2.0) - 2021-06-30[Breaking Changes](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-11) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v410---2021-04-30) [v4.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.1.0) - 2021-04-30[](https://docs.openzeppelin.com/contracts/5.x/changelog#v400---2021-03-24) [v4.0.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.0.0) - 2021-03-24[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog) [How to upgrade from 3.x](https://docs.openzeppelin.com/contracts/5.x/changelog#how-to-upgrade-from-3x) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v340---2021-02-03) [v3.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.4.0) - 2021-02-03[Security Fixes](https://docs.openzeppelin.com/contracts/5.x/changelog#security-fixes) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v330---2020-11-27) [v3.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.3.0) - 2020-11-27[](https://docs.openzeppelin.com/contracts/5.x/changelog#v321-for-solidity-07-v321-solc-07---2020-09-15) [v3.2.1 for Solidity 0.7 (v3.2.1-solc-0.7)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.2.1-solc-0.7) - 2020-09-15[](https://docs.openzeppelin.com/contracts/5.x/changelog#v320---2020-09-11) [v3.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.2.0) - 2020-09-11[](https://docs.openzeppelin.com/contracts/5.x/changelog#v310---2020-06-29) [v3.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.1.0) - 2020-06-29[ERC1155](https://docs.openzeppelin.com/contracts/5.x/changelog#erc1155) [More Replacements for `call`](https://docs.openzeppelin.com/contracts/5.x/changelog#more-replacements-for-call) [Using `SafeMath` on Small Signed Integers](https://docs.openzeppelin.com/contracts/5.x/changelog#using-safemath-on-small-signed-integers) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-301-v301---2020-04-27) [OpenZeppelin Contracts 3.0.1 (v3.0.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.0.1) - 2020-04-27[](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-251-v251---2020-04-27) [OpenZeppelin Contracts 2.5.1 (v2.5.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.5.1) - 2020-04-27[](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-30-v300---2020-04-20) [OpenZeppelin Contracts 3.0 (v3.0.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.0.0) - 2020-04-20[What's New](https://docs.openzeppelin.com/contracts/5.x/changelog#whats-new) [Compiling v0.6 Contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#compiling-v06-contracts) [Revamped Access Control](https://docs.openzeppelin.com/contracts/5.x/changelog#revamped-access-control) [Preset Contracts](https://docs.openzeppelin.com/contracts/5.x/changelog#preset-contracts) [Migrating From OpenZeppelin Contracts v2.5](https://docs.openzeppelin.com/contracts/5.x/changelog#migrating-from-openzeppelin-contracts-v25) [Using Hooks](https://docs.openzeppelin.com/contracts/5.x/changelog#using-hooks) [What's Next](https://docs.openzeppelin.com/contracts/5.x/changelog#whats-next) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-contracts-25-v250---2020-02-05) [OpenZeppelin Contracts 2.5 (v2.5.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.5.0) - 2020-02-05[New Documentation :books:](https://docs.openzeppelin.com/contracts/5.x/changelog#new-documentation-books) [Saying Goodbye to Solidity v0.5 :wave:](https://docs.openzeppelin.com/contracts/5.x/changelog#saying-goodbye-to-solidity-v05-wave) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-24-v240---2019-11-01) [OpenZeppelin 2.4 (v2.4.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.4.0) - 2019-11-01[](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-23-v230---2019-06-03) [OpenZeppelin 2.3 (v2.3.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.3.0) - 2019-06-03[ERC777](https://docs.openzeppelin.com/contracts/5.x/changelog#erc777) [Revert reasons](https://docs.openzeppelin.com/contracts/5.x/changelog#revert-reasons) [Documentation site](https://docs.openzeppelin.com/contracts/5.x/changelog#documentation-site) [More](https://docs.openzeppelin.com/contracts/5.x/changelog#more) [More](https://docs.openzeppelin.com/contracts/5.x/changelog#more-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-22-v220---2019-03-14) [OpenZeppelin 2.2 (v2.2.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.2.0) - 2019-03-14[Highlights](https://docs.openzeppelin.com/contracts/5.x/changelog#highlights) [New features](https://docs.openzeppelin.com/contracts/5.x/changelog#new-features) [Improvements](https://docs.openzeppelin.com/contracts/5.x/changelog#improvements) [Bugfixes:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfixes) [Breaking changes in drafts:](https://docs.openzeppelin.com/contracts/5.x/changelog#breaking-changes-in-drafts) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-213-v213---2019-02-26) [OpenZeppelin 2.1.3 (v2.1.3)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.3) - 2019-02-26[Bugfix release :bug: :wrench:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfix-release-bug-wrench) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-201-v201---2019-02-26) [OpenZeppelin 2.0.1 (v2.0.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.1) - 2019-02-26[Bugfix release :bug: :wrench:](https://docs.openzeppelin.com/contracts/5.x/changelog#bugfix-release-bug-wrench-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-212-v212---2019-03-01) [OpenZeppelin 2.1.2 (v2.1.2)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.2) - 2019-03-01[](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-21-v211---2019-01-04) [OpenZeppelin 2.1 (v2.1.1)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.1.1) - 2019-01-04[2.1 is finally out! :tada:](https://docs.openzeppelin.com/contracts/5.x/changelog#21-is-finally-out-tada) [Highlights](https://docs.openzeppelin.com/contracts/5.x/changelog#highlights-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#openzeppelin-20-v200---2018-10-21) [OpenZeppelin 2.0 (v2.0.0)](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.0) - 2018-10-21[Featuring...](https://docs.openzeppelin.com/contracts/5.x/changelog#featuring) [Stable API](https://docs.openzeppelin.com/contracts/5.x/changelog#stable-api) [Granular permissions](https://docs.openzeppelin.com/contracts/5.x/changelog#granular-permissions) [Improved test suite](https://docs.openzeppelin.com/contracts/5.x/changelog#improved-test-suite) [A new audit](https://docs.openzeppelin.com/contracts/5.x/changelog#a-new-audit) [Tons of community love](https://docs.openzeppelin.com/contracts/5.x/changelog#tons-of-community-love) [Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1120---2018-08-11) [v1.12.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.12.0) - 2018-08-11[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-2) [Additions](https://docs.openzeppelin.com/contracts/5.x/changelog#additions) [Improvements](https://docs.openzeppelin.com/contracts/5.x/changelog#improvements-1) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1110---2018-07-13) [v1.11.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.11.0) - 2018-07-13[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-3) [Added](https://docs.openzeppelin.com/contracts/5.x/changelog#added) [Changed](https://docs.openzeppelin.com/contracts/5.x/changelog#changed) [Removed](https://docs.openzeppelin.com/contracts/5.x/changelog#removed) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v1100---2018-06-05) [v1.10.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.10.0) - 2018-06-05[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-4) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v190---2018-04-27) [v1.9.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.9.0) - 2018-04-27[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-5) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v180---2018-03-23) [v1.8.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.8.0) - 2018-03-23[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-6) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v170---2018-02-20) [v1.7.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.7.0) - 2018-02-20[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-7) [Project updates:](https://docs.openzeppelin.com/contracts/5.x/changelog#project-updates) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v160---2018-01-23) [v1.6.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.6.0) - 2018-01-23[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-8) [Project changes](https://docs.openzeppelin.com/contracts/5.x/changelog#project-changes) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v150---2017-12-22) [v1.5.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.5.0) - 2017-12-22[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-9) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v140---2017-11-23) [v1.4.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.4.0) - 2017-11-23[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-10) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v130---2017-09-21) [v1.3.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.3.0) - 2017-09-21[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-11) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v120---2017-07-18) [v1.2.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.2.0) - 2017-07-18[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-12) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v110---2017-07-02) [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.1.0) - 2017-07-02[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-13) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v106---2017-05-29) [v1.0.6](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.6) - 2017-05-29[Changelog](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-14) [Security](https://docs.openzeppelin.com/contracts/5.x/changelog#security) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v105---2017-05-09) [v1.0.5](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.5) - 2017-05-09[Changelog:](https://docs.openzeppelin.com/contracts/5.x/changelog#changelog-15) [](https://docs.openzeppelin.com/contracts/5.x/changelog#v104---2017-03-09) [v1.0.4](https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v1.0.4) - 2017-03-09 --- # Uniswap Hooks | OpenZeppelin Docs Uniswap Hooks ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) A [Solidity library](https://github.com/OpenZeppelin/uniswap-hooks) for secure and modular hooks for [Uniswap v4](https://docs.uniswap.org/contracts/v4/overview) . This library includes: * Base implementations for custom accounting, asynchronous swaps, and custom curves * Fee-related implementations for management and enforcement * Ready-to-use hooks for general use cases, like sandwich protection * Utilities and libraries for hook development [Overview](https://docs.openzeppelin.com/uniswap-hooks#overview) ----------------------------------------------------------------- ### [Installation](https://docs.openzeppelin.com/uniswap-hooks#installation) The library can only be installed with Foundry using gitmodules for now. Support for Hardhat is coming soon. #### [Foundry (git)](https://docs.openzeppelin.com/uniswap-hooks#foundry-git) $ forge install OpenZeppelin/uniswap-hooks Make sure to add `@openzeppelin/uniswap-hooks/=lib/uniswap-hooks/src/` in `remappings.txt`. ### [Usage](https://docs.openzeppelin.com/uniswap-hooks#usage) Once installed, you can use the contracts in the library by importing them: // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; import {BaseDynamicFee, IPoolManager, PoolKey} from "src/fee/BaseDynamicFee.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; /** * @dev A hook that allows the owner to dynamically update the LP fee. */ contract DynamicLPFeeHook is BaseDynamicFee, Ownable { uint24 public fee; constructor(IPoolManager _poolManager) BaseDynamicFee(_poolManager) Ownable(msg.sender) { } /** * @inheritdoc BaseDynamicFee */ function _getFee(PoolKey calldata) internal view override returns (uint24) { return fee; } /** * @notice Sets the LP fee, denominated in hundredths of a bip. */ function setFee(uint24 _fee) external onlyOwner { fee = _fee; } } 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. ### [Videos](https://docs.openzeppelin.com/uniswap-hooks#videos) In order to facilitate understanding of Uniswap Hooks and help start building with them, we’ve released this playlist of guidelines on our YouTube channel. [Security](https://docs.openzeppelin.com/uniswap-hooks#security) ----------------------------------------------------------------- Contracts in the hooks library are provided as is, with no particular guarantees, including backward compatibility. We kindly ask to report any issue directly to our security [contact](https://docs.openzeppelin.com/cdn-cgi/l/email-protection#6d1e080e181f0419142d021d080317081d1d0801040343021f0a) . The team will do its best to assist and mitigate any potential misuses of the library. [Base\ \ Next Page](https://docs.openzeppelin.com/uniswap-hooks/base) ### On this page [Overview](https://docs.openzeppelin.com/uniswap-hooks#overview) [Installation](https://docs.openzeppelin.com/uniswap-hooks#installation) [Foundry (git)](https://docs.openzeppelin.com/uniswap-hooks#foundry-git) [Usage](https://docs.openzeppelin.com/uniswap-hooks#usage) [Videos](https://docs.openzeppelin.com/uniswap-hooks#videos) [Security](https://docs.openzeppelin.com/uniswap-hooks#security) --- # EVM Integration | OpenZeppelin Docs Relayer EVM Integration =============== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/relayer/evm#overview) --------------------------------------------------------------- OpenZeppelin Relayer provides comprehensive support for EVM (Ethereum Virtual Machine) networks, enabling secure transaction relaying, advanced gas management, EIP-1559 support, and robust fee estimation. This page covers everything you need to get started and make the most of EVM-specific features. [Features](https://docs.openzeppelin.com/relayer/evm#features) --------------------------------------------------------------- * Advanced gas price management with EIP-1559 support * Dynamic gas limit estimation with fallback mechanisms * Transaction replacement and acceleration * Multi-network support (Ethereum, Arbitrum, Optimism, BSC, Polygon, etc.) * Custom RPC endpoints with load balancing and failover * Secure transaction signing with multiple signer backends * Transaction status monitoring and confirmation tracking * Whitelist-based security policies * Metrics and observability [Supported Networks](https://docs.openzeppelin.com/relayer/evm#supported-networks) ----------------------------------------------------------------------------------- EVM networks are defined via JSON configuration files, providing flexibility to: * Configure any EVM-compatible network (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) * Set up custom EVM-compatible networks with specific RPC endpoints * Create network variants using inheritance from base configurations * Support both Layer 1 and Layer 2 networks For detailed network configuration options, see the [Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration) guide. [Supported Signers](https://docs.openzeppelin.com/relayer/evm#supported-signers) --------------------------------------------------------------------------------- * `local` (local keystore files) * `vault` (HashiCorp Vault secret storage) * `vault_cloud` (hosted HashiCorp Vault) * `turnkey` (hosted Turnkey signer) * `google_cloud_kms` (Google Cloud KMS) * `aws_kms` (Amazon AWS KMS) For detailed signer configuration options, see the [Signers](https://docs.openzeppelin.com/relayer/configuration/signers) guide. In production systems, hosted signers (AWS KMS, Google Cloud KMS, Turnkey) are recommended for the best security model. [Quickstart](https://docs.openzeppelin.com/relayer/evm#quickstart) ------------------------------------------------------------------- For a step-by-step setup, see [Quick Start Guide](https://docs.openzeppelin.com/relayer/quickstart) . Key prerequisites: * Rust 2021, version `1.86` or later * Redis * Docker (optional) Example configuration for an EVM relayer: { "id": "sepolia-example", "name": "Sepolia Example", "network": "sepolia", "paused": false, "notification_id": "notification-example", "signer_id": "local-signer", "network_type": "evm", "custom_rpc_urls": [\ {\ "url": "https://primary-rpc.example.com",\ "weight": 100\ },\ {\ "url": "https://backup-rpc.example.com",\ "weight": 100\ }\ ], "policies": { "gas_price_cap": 100000000000, "eip1559_pricing": true, "gas_limit_estimation": true, "whitelist_receivers": [\ "0x1234567890123456789012345678901234567890",\ "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"\ ], "min_balance": 1000000000000000000 } } For more configuration examples, visit the [OpenZeppelin Relayer examples repository](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) . [Configuration](https://docs.openzeppelin.com/relayer/evm#configuration) ------------------------------------------------------------------------- ### [Relayer Policies](https://docs.openzeppelin.com/relayer/evm#relayer-policies) In addition to standard relayer configuration and policies, EVM relayers support additional options: * `gas_price_cap`: Maximum gas price limit (in wei) for transactions * `gas_limit_estimation`: Enable/disable automatic gas limit estimation * `whitelist_receivers`: List of authorized contract addresses for transactions * `min_balance`: Minimum balance required for the relayer to operate (in wei) * `eip1559_pricing`: Enable/disable EIP-1559 pricing methodology for transaction fees You can check all options in [User Documentation - Relayers](https://docs.openzeppelin.com/relayer#3-relayers) . ### [Gas Management Configuration](https://docs.openzeppelin.com/relayer/evm#gas-management-configuration) #### [Gas Price Cap](https://docs.openzeppelin.com/relayer/evm#gas-price-cap) Set a maximum gas price to protect against extreme network congestion: { "policies": { "gas_price_cap": 100000000000 } } #### [Gas Limit Estimation](https://docs.openzeppelin.com/relayer/evm#gas-limit-estimation) Enable or disable automatic gas limit estimation: { "policies": { "gas_limit_estimation": true } } When disabled, gas limits must be provided explicitly in transaction requests. The relayer uses a two-tier approach for gas limit estimation: 1. _**Primary Method**_: Uses the RPC `estimate_gas` method to calculate gas requirements * The estimated value is increased by 10% as a safety buffer * Provides accurate estimates for most transaction types 2. _**Fallback Method**_: When RPC estimation fails, default gas limits are applied based on transaction type: * _**Simple ETH transfer**_ (no data): 21,000 gas * _**ERC20 transfer**_ (`0xa9059cbb`): 65,000 gas * _**ERC721/ERC20 transferFrom**_ (`0x23b872dd`): 80,000 gas * _**Complex contracts**_ (all other function calls): 200,000 gas For advanced users working with complex transactions or custom contracts, it is recommended to include an explicit `gas_limit` parameter in the transaction request to ensure optimal gas usage and avoid estimation errors. #### [Whitelist Receivers](https://docs.openzeppelin.com/relayer/evm#whitelist-receivers) Restrict transactions to specific contract addresses: { "policies": { "whitelist_receivers": [\ "0x1234567890123456789012345678901234567890",\ "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"\ ] } } [API Reference](https://docs.openzeppelin.com/relayer/evm#api-reference) ------------------------------------------------------------------------- The EVM API provides comprehensive transaction management capabilities. Common endpoints: * `POST /api/v1/relayers//transactions` send transaction * `GET /api/v1/relayers//transactions` list transactions * `GET /api/v1/relayers//transactions/` get transaction by id ### [Send Transaction - Speed params](https://docs.openzeppelin.com/relayer/evm#send-transaction---speed-params) curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "value": 1, "data": "0x", "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", "speed": "average" }' ### [Send Transaction - Speed params with gas limit included](https://docs.openzeppelin.com/relayer/evm#send-transaction---speed-params-with-gas-limit-included) curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "value": 1, "data": "0x", "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", "speed": "average", "gas_limit": 21000 }' ### [Transaction with EIP-1559 Pricing](https://docs.openzeppelin.com/relayer/evm#transaction-with-eip-1559-pricing) curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "value": 1, "data": "0x", "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", "max_fee_per_gas": 30000000000, "max_priority_fee_per_gas": 20000000000 }' ### [Transaction with Legacy Pricing - gas estimation included](https://docs.openzeppelin.com/relayer/evm#transaction-with-legacy-pricing---gas-estimation-included) curl --location --request POST 'http://localhost:8080/api/v1/relayers/solana-example/transactions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "value": 1, "data": "0x", "to": "0xd9b55a2ba539031e3c18c9528b0dc3a7f603a93b", "gas_price": "12312313123" }' ### [Get Transaction Status](https://docs.openzeppelin.com/relayer/evm#get-transaction-status) curl --location --request GET 'http://localhost:8080/api/v1/relayers/solana-example/transactions/' \ --header 'Authorization: Bearer ' See [API Reference](https://release-v1-0-0--openzeppelin-relayer.netlify.app/api_docs.html) for full details and examples. [Transaction Lifecycle](https://docs.openzeppelin.com/relayer/evm#transaction-lifecycle) ----------------------------------------------------------------------------------------- ### [1\. Transaction Submission](https://docs.openzeppelin.com/relayer/evm#1-transaction-submission) * Validate transaction parameters * Check whitelist policies (if enabled) * Estimate gas limit (if not provided) * Calculate gas price based on network conditions ### [2\. Transaction Signing](https://docs.openzeppelin.com/relayer/evm#2-transaction-signing) * Sign transaction using configured signer * Generate appropriate signature format ### [3\. Transaction Broadcasting](https://docs.openzeppelin.com/relayer/evm#3-transaction-broadcasting) * Submit to network via RPC endpoints * Handle RPC failures with automatic retries * Switch to backup RPC endpoints if needed ### [4\. Transaction Monitoring](https://docs.openzeppelin.com/relayer/evm#4-transaction-monitoring) * Track transaction status and confirmations * Handle transaction replacements if needed * Send notifications on status changes ### [5\. Transaction Confirmation](https://docs.openzeppelin.com/relayer/evm#5-transaction-confirmation) * Wait for required number of confirmations * Mark transaction as confirmed or failed * Clean up resources [Security Best Practices](https://docs.openzeppelin.com/relayer/evm#security-best-practices) --------------------------------------------------------------------------------------------- ### [Network Security](https://docs.openzeppelin.com/relayer/evm#network-security) * Use private RPC endpoints in production * Configure appropriate `gas_price_cap` to prevent excessive fees * Enable `whitelist_receivers` for controlled environments * Monitor relayer balance and set appropriate `min_balance` ### [Signer Security](https://docs.openzeppelin.com/relayer/evm#signer-security) * Use hosted signers (AWS KMS, Google Cloud KMS, Turnkey) in production * Rotate signer keys regularly * Implement proper access controls and audit logging * Never store private keys in plain text ### [Operational Security](https://docs.openzeppelin.com/relayer/evm#operational-security) * Deploy behind a secure reverse proxy * Use HTTPS for all communications * Implement proper rate limiting * Monitor for unusual transaction patterns ### [Monitoring and Observability](https://docs.openzeppelin.com/relayer/evm#monitoring-and-observability) Enable metrics and monitor: * Transaction success rates * Gas price trends * RPC endpoint performance * Relayer balance levels * Failed transaction patterns [Support](https://docs.openzeppelin.com/relayer/evm#support) ------------------------------------------------------------- For help with EVM integration: * Join our [Telegram](https://t.me/openzeppelin_tg/2) community * Open an issue on our [GitHub repository](https://github.com/OpenZeppelin/openzeppelin-relayer) * Check our [comprehensive documentation](https://docs.openzeppelin.com/relayer) [License](https://docs.openzeppelin.com/relayer/evm#license) ------------------------------------------------------------- This project is licensed under the GNU Affero General Public License v3.0. [Storage Configuration\ \ Previous Page](https://docs.openzeppelin.com/relayer/configuration/storage) [Solana Integration\ \ Next Page](https://docs.openzeppelin.com/relayer/solana) ### On this page [Overview](https://docs.openzeppelin.com/relayer/evm#overview) [Features](https://docs.openzeppelin.com/relayer/evm#features) [Supported Networks](https://docs.openzeppelin.com/relayer/evm#supported-networks) [Supported Signers](https://docs.openzeppelin.com/relayer/evm#supported-signers) [Quickstart](https://docs.openzeppelin.com/relayer/evm#quickstart) [Configuration](https://docs.openzeppelin.com/relayer/evm#configuration) [Relayer Policies](https://docs.openzeppelin.com/relayer/evm#relayer-policies) [Gas Management Configuration](https://docs.openzeppelin.com/relayer/evm#gas-management-configuration) [Gas Price Cap](https://docs.openzeppelin.com/relayer/evm#gas-price-cap) [Gas Limit Estimation](https://docs.openzeppelin.com/relayer/evm#gas-limit-estimation) [Whitelist Receivers](https://docs.openzeppelin.com/relayer/evm#whitelist-receivers) [API Reference](https://docs.openzeppelin.com/relayer/evm#api-reference) [Send Transaction - Speed params](https://docs.openzeppelin.com/relayer/evm#send-transaction---speed-params) [Send Transaction - Speed params with gas limit included](https://docs.openzeppelin.com/relayer/evm#send-transaction---speed-params-with-gas-limit-included) [Transaction with EIP-1559 Pricing](https://docs.openzeppelin.com/relayer/evm#transaction-with-eip-1559-pricing) [Transaction with Legacy Pricing - gas estimation included](https://docs.openzeppelin.com/relayer/evm#transaction-with-legacy-pricing---gas-estimation-included) [Get Transaction Status](https://docs.openzeppelin.com/relayer/evm#get-transaction-status) [Transaction Lifecycle](https://docs.openzeppelin.com/relayer/evm#transaction-lifecycle) [1\. Transaction Submission](https://docs.openzeppelin.com/relayer/evm#1-transaction-submission) [2\. Transaction Signing](https://docs.openzeppelin.com/relayer/evm#2-transaction-signing) [3\. Transaction Broadcasting](https://docs.openzeppelin.com/relayer/evm#3-transaction-broadcasting) [4\. Transaction Monitoring](https://docs.openzeppelin.com/relayer/evm#4-transaction-monitoring) [5\. Transaction Confirmation](https://docs.openzeppelin.com/relayer/evm#5-transaction-confirmation) [Security Best Practices](https://docs.openzeppelin.com/relayer/evm#security-best-practices) [Network Security](https://docs.openzeppelin.com/relayer/evm#network-security) [Signer Security](https://docs.openzeppelin.com/relayer/evm#signer-security) [Operational Security](https://docs.openzeppelin.com/relayer/evm#operational-security) [Monitoring and Observability](https://docs.openzeppelin.com/relayer/evm#monitoring-and-observability) [Support](https://docs.openzeppelin.com/relayer/evm#support) [License](https://docs.openzeppelin.com/relayer/evm#license) --- # OpenZeppelin Contracts for Stylus | OpenZeppelin Docs OpenZeppelin Contracts for Stylus ================================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) **A secure, modular smart contract library for [Stylus](https://docs.arbitrum.io/stylus/gentle-introduction) , written in Rust.** OpenZeppelin Contracts for Stylus brings time-tested smart contract patterns to Arbitrum's WASM-based execution environment. This library provides `no_std`\-compatible modules for building secure, reusable contracts in [Stylus](https://docs.arbitrum.io/stylus/gentle-introduction) . [Features](https://docs.openzeppelin.com/contracts-stylus#features) -------------------------------------------------------------------- * ✨ Security-first contracts ported from [`openzeppelin-contracts`](https://github.com/OpenZeppelin/openzeppelin-contracts) . * 📦 Written in Rust with full `no_std` support. * 🧪 Tested with both unit and integration tests. * 🚧 Actively developed. [Quick Start](https://docs.openzeppelin.com/contracts-stylus#quick-start) -------------------------------------------------------------------------- Add the dependency to your `Cargo.toml`: [dependencies] openzeppelin-stylus = "=0.2.0" Enable the ABI export feature: [features] export-abi = ["openzeppelin-stylus/export-abi"] [Usage Example](https://docs.openzeppelin.com/contracts-stylus#usage-example) ------------------------------------------------------------------------------ A minimal ERC-20 implementation using the library: use openzeppelin_stylus::token::erc20::self, Erc20, IErc20; use stylus_sdk:: alloy_primitives::{Address, U256, prelude::*, }; #[entrypoint] #[storage] struct Erc20Example erc20: Erc20, #[public] #[implements(IErc20)] impl Erc20Example {} #[public] impl IErc20 for Erc20Example // ERC-20 logic implementation... Explore more examples in the [`examples` directory](https://github.com/OpenZeppelin/rust-contracts-stylus/tree/main/examples) . [Compatibility](https://docs.openzeppelin.com/contracts-stylus#compatibility) ------------------------------------------------------------------------------ This library is designed to work with `no_std`. To keep your contracts compatible, disable default features for any dependencies that pull in the standard library: [dependencies] alloy-primitives = version = "=0.8.20", default-features = false stylus-sdk = "=0.9.0" [Roadmap & Contributing](https://docs.openzeppelin.com/contracts-stylus#roadmap--contributing) ----------------------------------------------------------------------------------------------- See what’s planned or in development in our [roadmap](https://github.com/orgs/OpenZeppelin/projects/35) . Interested in contributing? Read the [contribution guide](https://github.com/OpenZeppelin/rust-contracts-stylus/blob/main/CONTRIBUTING.md) . [Security](https://docs.openzeppelin.com/contracts-stylus#security) -------------------------------------------------------------------- While this library is under active development, security remains a top priority. For past audits and security reports, see the [`audits` directory](https://github.com/OpenZeppelin/rust-contracts-stylus/tree/main/audits) . [License](https://docs.openzeppelin.com/contracts-stylus#license) ------------------------------------------------------------------ Released under the [MIT License](https://github.com/OpenZeppelin/rust-contracts-stylus/blob/main/LICENSE) . [Access Control\ \ Next Page](https://docs.openzeppelin.com/contracts-stylus/access-control) ### On this page [Features](https://docs.openzeppelin.com/contracts-stylus#features) [Quick Start](https://docs.openzeppelin.com/contracts-stylus#quick-start) [Usage Example](https://docs.openzeppelin.com/contracts-stylus#usage-example) [Compatibility](https://docs.openzeppelin.com/contracts-stylus#compatibility) [Roadmap & Contributing](https://docs.openzeppelin.com/contracts-stylus#roadmap--contributing) [Security](https://docs.openzeppelin.com/contracts-stylus#security) [License](https://docs.openzeppelin.com/contracts-stylus#license) --- # API Reference | OpenZeppelin Docs [Community Contracts](https://docs.openzeppelin.com/community-contracts) API Reference ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Core APIs](https://docs.openzeppelin.com/community-contracts/api#core-apis) ----------------------------------------------------------------------------- * **[Access](https://docs.openzeppelin.com/community-contracts/api/access) ** - Access control and permission management * **[Account](https://docs.openzeppelin.com/community-contracts/api/account) ** - Account abstraction and smart account functionality * **[Crosschain](https://docs.openzeppelin.com/community-contracts/api/crosschain) ** - Cross-chain communication and bridging utilities * **[Interfaces](https://docs.openzeppelin.com/community-contracts/api/interfaces) ** - Standard interfaces and contract definitions * **[Proxy](https://docs.openzeppelin.com/community-contracts/api/proxy) ** - Proxy patterns and upgradeable contract utilities * **[Token](https://docs.openzeppelin.com/community-contracts/api/token) ** - Token standards and implementations [Utilities](https://docs.openzeppelin.com/community-contracts/api#utilities) ----------------------------------------------------------------------------- * **[Utils](https://docs.openzeppelin.com/community-contracts/api/utils) ** - General utility functions and helpers * **[Cryptography](https://docs.openzeppelin.com/community-contracts/api/utils/cryptography) ** - Cryptographic functions and primitives [Utilities\ \ Previous Page](https://docs.openzeppelin.com/community-contracts/utilities) [Access\ \ Next Page](https://docs.openzeppelin.com/community-contracts/api/access) ### On this page [Core APIs](https://docs.openzeppelin.com/community-contracts/api#core-apis) [Utilities](https://docs.openzeppelin.com/community-contracts/api#utilities) --- # Frequently Asked Questions | OpenZeppelin Docs OpenZeppelin Contracts Frequently Asked Questions ========================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Can I restrict a function to EOAs only?](https://docs.openzeppelin.com/contracts/5.x/faq#can-i-restrict-a-function-to-eoas-only) ---------------------------------------------------------------------------------------------------------------------------------- When calling external addresses from your contract it is unsafe to assume that an address is an externally-owned account (EOA) and not a contract. Attempting to prevent calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract constructor. Although checking that the address has code, `address.code.length > 0`, may seem to differentiate contracts from EOAs, it can only say that an address is currently a contract, and its negation (that an address is not currently a contract) does not imply that the address is an EOA. Some counterexamples are: * address of a contract in construction * address where a contract will be created * address where a contract lived, but was destroyed Furthermore, an address will be considered a contract within the same transaction where it is scheduled for destruction by `SELFDESTRUCT`, which only has an effect at the end of the entire transaction. [Subgraph Examples\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/subgraphs/examples/subgraph) [Changelog\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/changelog) ### On this page [Can I restrict a function to EOAs only?](https://docs.openzeppelin.com/contracts/5.x/faq#can-i-restrict-a-function-to-eoas-only) --- # Subgraphs | OpenZeppelin Docs OpenZeppelin Contracts Subgraphs ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Modules for easily indexing OpenZeppelin Contracts activity. Install from npm as [`@openzeppelin/subgraphs`](https://www.npmjs.com/package/@openzeppelin/subgraphs) . Browse on GitHub at [`OpenZeppelin/openzeppelin-subgraphs`](https://github.com/OpenZeppelin/openzeppelin-subgraphs) . [Usage](https://docs.openzeppelin.com/contracts/5.x/subgraphs#usage) --------------------------------------------------------------------- Subgraph are described using three components: * **The graphql schema**, usually named `schema.graphql`, which describes the database entities and links. * **The subgraph manifest**, usually named `subgraph.yaml`, which describes the activity that should be listened to (addresses of contracts, events handlers, function handlers). * **The indexing logic**, written in assembly script, which will process the blockchain activity and update the database accordingly. OpenZeppelin Subgraphs provide schemas description, with the corresponding indexing logic and templates for building your subgraph manifest. Similarly to how OpenZeppelin Contracts provide solidity code containing sets of features that one can assemble to ease building an application, OpenZeppelin subgraphs provides modules dedicated to indexing the activity corresponding to these features. These modules can be composed to index complex onchain activity without the need to actually write the indexing logic for most of the features. ### [Building your manifest](https://docs.openzeppelin.com/contracts/5.x/subgraphs#building-your-manifest) You can build a manifest for your application using the templates provided for each module. These templates are available in `src/datasource/.yaml`. For each datasource, you will have to fill in the name, network, address, and startBlock of your contract. If a contract implements multiple modules, you will want to have multiple datasources listenning to the same address (one per module). **Note:** For the indexing logic to work you will have, for each module used, to name one of your datasources with the name of the module. The `@amxx/graphprotocol-utils` provides tooling to [automate the generation of manifests.](https://docs.openzeppelin.com/contracts/5.x/subgraphs/generate) ### [Assembling your schema](https://docs.openzeppelin.com/contracts/5.x/subgraphs#assembling-your-schema) Depending on the modules you are using, your schema will have to include the corresponding entities. Assembling a schema can be difficult since graphql schema do not natively support import and merging operations. We do provide precompiled schemas for each module in `generated/.schema.graphql`. We also provide a schema that includes all the entities for all the modules in `generated/all.schema.graphql`. Similar to the manifest, `@amxx/graphprotocol-utils` provides tooling to [automate the generation of schemas.](https://docs.openzeppelin.com/contracts/5.x/subgraphs/generate) [Modules](https://docs.openzeppelin.com/contracts/5.x/subgraphs#modules) ------------------------------------------------------------------------- | Module name | Availability | | --- | --- | | **erc20** | ✔ | | **erc20votes** | Planned | | **erc721** | ✔ | | **erc777** | Planned | | **erc1155** | ✔ | | **erc1967upgrade** | ✔ | | **ownable** | ✔ | | **accesscontrol** | ✔ | | **pausable** | ✔ | | **timelock** | ✔ | | **governor** | ✔ | [Usage example](https://docs.openzeppelin.com/contracts/5.x/subgraphs#usage-example) ------------------------------------------------------------------------------------- By combining multiple modules and datasources in your subgraph, you can build query such as the following one, which check the details of an ERC20 token with AccessControl on top of it, and returns the balance of the administrators. { erc20Contract(id: "") { name symbol decimals totalSupply { value } asAccount { asAccessControl { admins: roles(where: { role: "0x0000000000000000000000000000000000000000000000000000000000000000" }) { members { account { address: id balance: ERC20balances(where: { contract: "" }) { value } } } } } } } } [Utilities\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/utilities) [Automatic Generation\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/subgraphs/generate) ### On this page [Usage](https://docs.openzeppelin.com/contracts/5.x/subgraphs#usage) [Building your manifest](https://docs.openzeppelin.com/contracts/5.x/subgraphs#building-your-manifest) [Assembling your schema](https://docs.openzeppelin.com/contracts/5.x/subgraphs#assembling-your-schema) [Modules](https://docs.openzeppelin.com/contracts/5.x/subgraphs#modules) [Usage example](https://docs.openzeppelin.com/contracts/5.x/subgraphs#usage-example) --- # Stellar Smart Contracts Suite | OpenZeppelin Docs Stellar Smart Contracts Suite ============================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Explore our comprehensive suite of secure and scalable smart contract utilities for Stellar Soroban. Our libraries provide robust implementations for fungible and non-fungible tokens, along with powerful tools for access control and contract management. [Tokens](https://docs.openzeppelin.com/stellar-contracts#tokens) ----------------------------------------------------------------- * **[Fungible Tokens](https://docs.openzeppelin.com/stellar-contracts/tokens/fungible/fungible) **: Digital assets representing a fixed or dynamic supply of identical units. * **[Non-Fungible Tokens (NFTs)](https://docs.openzeppelin.com/stellar-contracts/tokens/non-fungible/non-fungible) **: Unique digital assets with verifiable ownership. * **Multi-Tokens**: Hybrid tokens enabling both fungible and non-fungible token functionalities (work in progress). [Access Control](https://docs.openzeppelin.com/stellar-contracts#access-control) --------------------------------------------------------------------------------- * **[Ownable](https://docs.openzeppelin.com/stellar-contracts/access/ownable) **: A simple mechanism with a single account authorized for all privileged actions. * **[Role-Based Access Control](https://docs.openzeppelin.com/stellar-contracts/access/access-control) **: A flexible mechanism with distinct roles for each privileged action. [Utilities](https://docs.openzeppelin.com/stellar-contracts#utilities) ----------------------------------------------------------------------- * **[Pausable](https://docs.openzeppelin.com/stellar-contracts/utils/pausable) **: Pause and unpause contract functions, useful for emergency response. * **[Upgradeable](https://docs.openzeppelin.com/stellar-contracts/utils/upgradeable) **: Manage contract upgrades and data migrations seamlessly. * **[Cryptography](https://docs.openzeppelin.com/stellar-contracts/utils/crypto) **: A set of cryptographic primitives and utilities for Soroban contracts. [Security and Audits](https://docs.openzeppelin.com/stellar-contracts#security-and-audits) ------------------------------------------------------------------------------------------- Our contracts are built with security as a top priority. You can find our audit reports [here](https://github.com/OpenZeppelin/stellar-contracts/tree/main/audits) . [Error Codes](https://docs.openzeppelin.com/stellar-contracts#error-codes) --------------------------------------------------------------------------- In Stellar Soroban, each error variant is assigned an integer. To prevent duplication of error codes, we use the following convention: * Fungible: `1XX` * Non-Fungible: `2XX` * Multi-Token: `3XX` Any future tokens will continue from `4XX`, `5XX`, and so on. * Utilities: `1XXX` * Pausable: `10XX` * Upgradeable: `11XX` * Access: `12XX` * Role Transfer (internal common module for 2-step role transfer): `120X` * Access Control: `121X` * Ownable: `122X` * Merkle Distributor: `13XX` Any future utilities will continue from `14XX`, `15XX`, and so on. [Important Notes](https://docs.openzeppelin.com/stellar-contracts#important-notes) ----------------------------------------------------------------------------------- As a deliberate design choice, this library manages the TTL for temporary and persistent storage items. To provide flexibility to the owner of the contract, this library deliberately does not manage the TTL for instance storage items. It is the responsibility of the developer to manage the TTL for instance storage items. [Audits](https://docs.openzeppelin.com/stellar-contracts#audits) ----------------------------------------------------------------- You can find our audit reports [here](https://github.com/OpenZeppelin/stellar-contracts/tree/main/audits) . [Get Started](https://docs.openzeppelin.com/stellar-contracts#get-started) --------------------------------------------------------------------------- Get started [here](https://docs.openzeppelin.com/stellar-contracts/get-started) . ### On this page [Tokens](https://docs.openzeppelin.com/stellar-contracts#tokens) [Access Control](https://docs.openzeppelin.com/stellar-contracts#access-control) [Utilities](https://docs.openzeppelin.com/stellar-contracts#utilities) [Security and Audits](https://docs.openzeppelin.com/stellar-contracts#security-and-audits) [Error Codes](https://docs.openzeppelin.com/stellar-contracts#error-codes) [Important Notes](https://docs.openzeppelin.com/stellar-contracts#important-notes) [Audits](https://docs.openzeppelin.com/stellar-contracts#audits) [Get Started](https://docs.openzeppelin.com/stellar-contracts#get-started) --- # Contracts for Cairo | OpenZeppelin Docs Contracts for Cairo =================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) **OpenZeppelin Contracts for Cairo** provides modular, reusable, and audited smart-contract building blocks for Starknet. The library ships with ready-to-use components, presets, utilities, and tooling that help you ship production-grade Cairo applications faster. [Getting Started](https://docs.openzeppelin.com/contracts-cairo#getting-started) --------------------------------------------------------------------------------- [### Latest Stable (2.x)\ \ Explore the stable and audited documentation set, including installation, components, and production-ready guides.](https://docs.openzeppelin.com/contracts-cairo/2.x) [### Latest Alpha (3.0.0-alpha.3)\ \ Try the upcoming features, updated APIs, and experimental packages before they are audited, available in the alpha release track.](https://docs.openzeppelin.com/contracts-cairo/alpha) [### Contracts Wizard\ \ Bootstrap Cairo contracts with the interactive Wizard and learn how features compose across packages.](https://docs.openzeppelin.com/contracts-cairo/2.x/wizard) [Core Features](https://docs.openzeppelin.com/contracts-cairo#core-features) ----------------------------------------------------------------------------- [### Components\ \ Reusable building blocks for composing Cairo contracts with mixins and modular architecture.](https://docs.openzeppelin.com/contracts-cairo/2.x/components) [### Presets\ \ Ready-to-deploy contract presets for common Starknet scenarios.](https://docs.openzeppelin.com/contracts-cairo/2.x/presets) [### Access Control\ \ Manage permissions and roles for Cairo contracts with flexible access-control patterns.](https://docs.openzeppelin.com/contracts-cairo/2.x/access) [### Security\ \ Harden your contracts with patterns and modules designed to reduce common vulnerabilities.](https://docs.openzeppelin.com/contracts-cairo/2.x/security) [Token Standards](https://docs.openzeppelin.com/contracts-cairo#token-standards) --------------------------------------------------------------------------------- [### ERC-20\ \ Implement fungible tokens with hooks, minting, and allowance helpers adapted for Starknet.](https://docs.openzeppelin.com/contracts-cairo/2.x/erc20) [### ERC-721\ \ Build non-fungible tokens with metadata, enumeration, and minting extensions.](https://docs.openzeppelin.com/contracts-cairo/2.x/erc721) [### ERC-1155\ \ Support multi-token collections that mix fungible and non-fungible assets.](https://docs.openzeppelin.com/contracts-cairo/2.x/erc1155) [### ERC-4626\ \ Create tokenized vaults that integrate with Starknet DeFi protocols.](https://docs.openzeppelin.com/contracts-cairo/2.x/erc4626) [Advanced Features](https://docs.openzeppelin.com/contracts-cairo#advanced-features) ------------------------------------------------------------------------------------- [### Accounts\ \ Work with smart accounts, multicalls, and account-upgrade flows tailored for Starknet.](https://docs.openzeppelin.com/contracts-cairo/2.x/accounts) [### Upgradeability\ \ Design upgradeable patterns and learn how to manage storage-safe contract evolution.](https://docs.openzeppelin.com/contracts-cairo/2.x/upgrades) [### Universal Deployer\ \ Deploy contracts deterministically using the Universal Deployer Contract.](https://docs.openzeppelin.com/contracts-cairo/2.x/udc) [### Governance\ \ Build Starknet-native governance flows with governor, timelock, multisig, and voting modules.](https://docs.openzeppelin.com/contracts-cairo/2.x/governance/governor) [API Reference](https://docs.openzeppelin.com/contracts-cairo#api-reference) ----------------------------------------------------------------------------- [### Access Control API\ \ Inspect the full access-control interface, events, and helper methods.](https://docs.openzeppelin.com/contracts-cairo/2.x/api/access) [### ERC-20 API\ \ Explore the ERC-20 token standard interface, events, and helper methods for fungible tokens.](https://docs.openzeppelin.com/contracts-cairo/2.x/api/erc20) [### Upgrades API\ \ Learn the low-level traits and components that power upgradeable contracts in Cairo.](https://docs.openzeppelin.com/contracts-cairo/2.x/api/upgrades) [### Utilities API\ \ Browse helper libraries, testing utilities, and dispatchers available to every package.](https://docs.openzeppelin.com/contracts-cairo/2.x/api/utilities) ### On this page [Getting Started](https://docs.openzeppelin.com/contracts-cairo#getting-started) [Core Features](https://docs.openzeppelin.com/contracts-cairo#core-features) [Token Standards](https://docs.openzeppelin.com/contracts-cairo#token-standards) [Advanced Features](https://docs.openzeppelin.com/contracts-cairo#advanced-features) [API Reference](https://docs.openzeppelin.com/contracts-cairo#api-reference) --- # Configuration | OpenZeppelin Docs Relayer Configuration ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/relayer/configuration#overview) ------------------------------------------------------------------------- Most configuration files should live under `./config`, including the signer configurations, under `./config/keys`. Please ensure appropriate access permissions on all configuration files (for `./config/keys/*`, we recommend `0500`. The OpenZeppelin Relayer supports two configuration approaches: _**File-based Configuration:**_ 1. _**`config.json`**_: Contains relayer definitions, signer configurations, and network policies 2. _**`.env`**_ file: Contains environment variables like API keys and connection strings _**API-based Configuration:**_ * Full CRUD operations for relayers, signers, and notifications via REST API * Changes take effect immediately (no container restart required) * See the _**API Reference**_ page for detailed endpoints documentation See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage) for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. For quick setup examples with pre-configured files, see the [examples directory](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples) in our GitHub repository. [Environment configuration (.env)](https://docs.openzeppelin.com/relayer/configuration#environment-configuration-env) ---------------------------------------------------------------------------------------------------------------------- This defines some base configurations for the Relayer application: Copy the example environment file and update values according to your needs cp .env.example .env This table lists the environment variables and their default values. | Environment Variable | Default Value | Accepted Values | Description | | --- | --- | --- | --- | | `RUST_LOG` | `info` | `info, debug, warn, error, trace` | Log level. | | `REPOSITORY_STORAGE_TYPE` | `in-memory` | `in-memory, redis` | Type of storage used for storing repository config and resources. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for detailed information. | | `RESET_STORAGE_ON_START` | `false` | `bool` | Clears all resources from storage on startup and reloads entries from the config file. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for usage details. | | `TRANSACTION_EXPIRATION_HOURS` | `4` | `number` | Number of hours after which transactions in a final state are removed from storage. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for more information. | | `CONFIG_DIR` | `./config` | `` | Relative path of directory where config files reside | | `CONFIG_FILE_NAME` | `config.json` | `` | File Name of the configuration file. | | `RATE_LIMIT_RPS` | `100` | `` | Rate limit for the API in requests per second. | | `RATE_LIMIT_BURST_SIZE` | `300` | `` | Rate limit burst size. | | `API_KEY` | \`\` | `string`, | API key to use for authentication to the relayer server. Minimum length 32 characters. | | `WEBHOOK_SIGNING_KEY` | \`\` | `string` | Signing key to use for webhook notifications. Minimum length 32 characters. | | `LOG_MODE` | `stdout` | `stdout, file` | Write logs either to console or to file. | | `LOG_DATA_DIR` | `./logs` | `` | Directory to persist log files on host. | | `LOG_MAX_SIZE (in bytes)` | `1073741824` | `` | Size after which logs needs to be rolled. | | `METRICS_ENABLED` | `false` | `bool` | Enable metrics server for external tools to scrape metrics. | | `METRICS_PORT` | `8081` | `` | Port to use for metrics server. | | `REDIS_URL` | `redis://localhost:6379` | `` | Redis connection URL for the relayer. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for Redis setup details. | | `REDIS_CONNECTION_TIMEOUT_MS` | `10000` | `` | Connection timeout for Redis in milliseconds. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for Redis configuration. | | `REDIS_KEY_PREFIX` | `oz-relayer` | `string` | Redis key prefix for namespacing. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for more information. | | `STORAGE_ENCRYPTION_KEY` | \`\` | `string` | Encryption key used to encrypt data at rest in Redis storage. See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage)
for security details. | | `RPC_TIMEOUT_MS` | `10000` | `` | Sets the maximum time to wait for RPC connections before timing out. | | `PROVIDER_MAX_RETRIES` | `3` | `` | Maximum number of retry attempts for provider operations. | | `PROVIDER_RETRY_BASE_DELAY_MS` | `100` | `` | Base delay between retry attempts in milliseconds. | | `PROVIDER_RETRY_MAX_DELAY_MS` | `2000` | `` | Maximum delay between retry attempts in milliseconds. | | `PROVIDER_MAX_FAILOVERS` | `3` | `` | Maximum number of failovers (switching to different providers). | | `ENABLE_SWAGGER` | `false` | `true, false` | Enable or disable Swagger UI for API documentation. | | `KEYSTORE_PASSPHRASE` | \`\` | `` | Passphrase for the keystore file used for signing transactions. | ### [Environment configuration example](https://docs.openzeppelin.com/relayer/configuration#environment-configuration-example) `.env` file config example: RUST_LOG=DEBUG CONFIG_DIR=./config CONFIG_FILE_NAME=config.json WEBHOOK_SIGNING_KEY=e1d42480-6f74-4d0b-85f4-b7f0bb690fae API_KEY=5eefd216-0e44-4ca7-b421-2925f90d30d5 RATE_LIMIT_RPS=100 RATE_LIMIT_BURST_SIZE=300 METRICS_ENABLED=true METRICS_PORT=8081 REDIS_URL=redis://localhost:6379 REDIS_CONNECTION_TIMEOUT_MS=10000 REDIS_KEY_PREFIX=oz-relayer RPC_TIMEOUT_MS=10000 PROVIDER_MAX_RETRIES=3 PROVIDER_RETRY_BASE_DELAY_MS=100 PROVIDER_RETRY_MAX_DELAY_MS=2000 PROVIDER_MAX_FAILOVERS=3 ENABLE_SWAGGER=false KEYSTORE_PASSPHRASE=your_keystore_passphrase STORAGE_ENCRYPTION_KEY=X67aXacJB+krEldv9i2w7NCSFwwOzVV/1ELM2KJJjQw= REPOSITORY_STORAGE_TYPE=redis RESET_STORAGE_ON_START=false TRANSACTION_EXPIRATION_HOURS=8 [Main configuration file (config.json)](https://docs.openzeppelin.com/relayer/configuration#main-configuration-file-configjson) -------------------------------------------------------------------------------------------------------------------------------- This file can exist in any directory, but the default location is `./config/config.json`. All components defined in `config.json` can also be managed via REST API endpoints. This provides runtime flexibility for adding, updating, or removing relayers, signers, and notifications without restarting the service. See the _**API Reference**_ page for detailed endpoints documentation. Key sections in this file include: * Signers: Defines transaction signing methods. * Notifications: Sets up status alerts * Relayers: Configures networks, notifications channels, policies & singers. * Networks: Defines blockchain network configurations. * Plugins: Configures plugins. ### [1\. Signers](https://docs.openzeppelin.com/relayer/configuration#1-signers) Transaction signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks. For comprehensive details on configuring all supported signer types including: * Local keystore file signers * HashiCorp Vault (secret and transit) * Cloud KMS providers (Google Cloud, AWS) * Turnkey signers * Security best practices and troubleshooting See the dedicated [Signers Configuration](https://docs.openzeppelin.com/relayer/configuration/signers) guide. Signers can also be managed via API endpoints. See the _**API Reference**_ page for detailed endpoints documentation. ### [2\. Notifications](https://docs.openzeppelin.com/relayer/configuration#2-notifications) * `notifications` array containing notification entries: "notifications": [\ {\ "id": "notification-test",\ "type": "webhook",\ "url": "https://webhook.site/f95cf78d-742d-4b21-88b7-d683e6fd147b",\ "signing_key": {\ "type": "env",\ "value": "WEBHOOK_SIGNING_KEY"\ }\ }\ ] Available configuration fields | Field | Type | Description | | --- | --- | --- | | id | String | Unique id for the notification | | type | String | Type of notification (only `webhook` available, for now) | | url | String | Notification URL | | signing\_key.type | String | Type of key used in signing the notification (`env` or `plain`) | | signing\_key.value | String | Signing key value, env variable name, ... | Notifications can also be managed via API endpoints. See the _**API Reference**_ page for detailed endpoints documentation. ### [3\. Relayers](https://docs.openzeppelin.com/relayer/configuration#3-relayers) * `relayers` array, containing relayer entries: "relayers": [\ \ "id": "solana-testnet",\ "name": "Solana Testnet",\ "paused": false,\ "notification_id": "notification-test",\ "signer_id": "local-signer",\ "network_type": "solana",\ "network": "testnet",\ "custom_rpc_urls": [\ {\ "url": "https://primary-rpc.example.com",\ "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive).\ ,\ \ "url": "https://backup-rpc.example.com",\ "weight": 1\ \ ],\ "policies":\ "allowed_programs": [\ "11111111111111111111111111111111",\ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",\ "BPFLoaderUpgradeab1e11111111111111111111111"\ ]\ \ }\ ] Available configuration fields | Field | Type | Description | | --- | --- | --- | | id | String | Unique id for the relayer | | name | String | Human readable name for the relayer | | paused | Boolean | Whether or not the relayer is paused (`true`, `false`) | | notification\_id | String | ID of a configured notification object | | signer\_id | String | ID of a configured signer | | network\_type | String | Type of network the relayer will connect to (`evm`, `solana`) | | network | String | Network the relayer will connect to. Must match a network identifier defined in your network configuration files. See [Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration)
for details on defining networks. | | custom\_rpc\_urls | list | Optional custom RPC URLs for the network. If provided, this will be used instead of the public RPC URLs. This is useful for using your own RPC node or a paid service provider. The first url of the list is going to be used as the default | | policies | list | Overrides default policies. Please refer to the [`Policies`](https://docs.openzeppelin.com/relayer/configuration#network-policies)
table | Policies | Network type | Policy | Type | Description | | --- | --- | --- | --- | | solana, evm | min\_balance | unsigned 128 | Minimum balance (in lamports or wei) required for the relayer to operate. Optional. | | solana | fee\_payment\_strategy | enum(user,relayer) | Specifies who pays the fee. "user" (default) means the sender pays; "relayer" means the relayer pays. For "user", RPC methods add an instruction to transfer SPL tokens (calculated from the current SOL price plus a configurable margin) from the user to the relayer, ensuring fees are sustainably covered in tokens rather than SOL. | | solana | swap\_config | SwapConfig | Optional object configuring automated token‐swaps on Solana. | | solana | fee\_margin\_percentage | f32 | Additional margin percentage added to estimated transaction fees to account for price fluctuations. For example, a value of 10 will add 10% to estimated fees. Optional. | | solana | max\_allowed\_fee\_lamports | unsigned 64 | Maximum allowed fee (in lamports) for a transaction. Optional. | | solana | allowed\_tokens | `Vector` | List of allowed tokens. Only these tokens are supported if provided. Optional. | | solana | allowed\_programs | `Vector` | List of allowed programs by their identifiers. Only these programs are supported if provided. Optional. | | solana | allowed\_accounts | `Vector` | List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided. | | solana | disallowed\_accounts | `Vector` | List of disallowed accounts by their public keys. These accounts will be explicitly blocked. | | solana | max\_tx\_data\_size | unsigned 16 | Maximum transaction size. Optional. | | solana | max\_signatures | unsigned 8 | Maximum supported signatures. Optional. | | evm | gas\_price\_cap | unsigned 128 | Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) | | evm | gas\_limit\_estimation | bool | Automatic gas\_limit calculation. Enabled by default. (Optional) | | evm | whitelist\_receivers | `Vector` | A list of authorized contracts for each transaction sent using the Relayer. Transactions will be rejected if the destination address is not on the list. (Optional) | #### [RPC URL Configuration](https://docs.openzeppelin.com/relayer/configuration#rpc-url-configuration) The relayer supports two ways to configure RPC URLs: 1. _**Public RPC URLs**_: These are the default RPC endpoints provided by the network. They are automatically selected based on the network configuration. 2. _**Custom RPC URLs**_: You can specify custom RPC URLs using the `custom_rpc_urls` field in the relayer configuration. Each URL can be configured with an optional weight for high availability: "custom_rpc_urls": [\ \ "url": "https://primary-rpc.example.com",\ "weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive).\ ,\ \ "url": "https://secondary-rpc.example.com",\ "weight": 100, // Max allowed weight\ ,\ \ "url": "https://backup-rpc.example.com" // No weight specified, defaults to 100\ ,\ \ "url": "https://backup2-rpc.example.com",\ "weight": 0, // A value of 0 disables the endpoint.\ \ ] This is useful when you want to: * Use your own RPC nodes with load balancing * Use a paid service provider for better reliability and performance * Override the default public RPC URLs * Access custom network endpoints * Configure primary and backup endpoints with different weights When both are available, the relayer will: 1. First attempt to use the `custom_rpc_urls` if configured. 2. Fall back to the public RPC URLs if no custom URL is configured. For backward compatibility, string arrays are still supported: "custom_rpc_urls": ["https://your-rpc.example.com"] When using custom RPC URLs: * Ensure the URLs are secure (HTTPS) when accessing over public networks * Keep your API keys and authentication tokens secure * Test the RPC endpoints' reliability and performance before using it in production * Configure weights to prioritize endpoints, assigning higher values to more reliable or performant ones. * The weight must be an integer between 0 and 100 (inclusive). * A weight of 0 disables the endpoint. * If a weight is not specified for an endpoint, it defaults to 100. Relayers could also be managed via API endpoints. See the _**API Reference**_ page for detailed endpoints documentation. ### [4\. Plugins](https://docs.openzeppelin.com/relayer/configuration#4-plugins) For more information on how to write a plugin, please refer to the [Plugins](https://docs.openzeppelin.com/relayer/plugins) page. * `plugins` array, containing plugin configurations: "plugins": [\ {\ "id": "my-plugin",\ "path": "my-plugin.ts"\ }\ ] Available configuration fields | Field | Type | Description | | --- | --- | --- | | id | String | Unique id for the plugin | | path | String | Path to the plugin file | ### [5\. Networks](https://docs.openzeppelin.com/relayer/configuration#5-networks) You can configure networks either: * In separate JSON files (recommended for better organization) * Directly in your main `config.json` For comprehensive network configuration details, including: * Network field reference * Configuration examples for all network types * Network inheritance * Special tags and their behavior * Best practices and troubleshooting See the dedicated [Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration) guide. [Configuration File Example](https://docs.openzeppelin.com/relayer/configuration#configuration-file-example) ------------------------------------------------------------------------------------------------------------- Full `config/config.json` example with evm and solana relayers definitions using keystore signer: { "relayers": [\ {\ "id": "sepolia-example",\ "name": "Sepolia Example",\ "network": "sepolia",\ "paused": false,\ "notification_id": "notification-example",\ "signer_id": "local-signer",\ "network_type": "evm",\ "custom_rpc_urls": [\ {\ "url": "https://primary-rpc.example.com",\ "weight": 2\ },\ {\ "url": "https://backup-rpc.example.com",\ "weight": 1\ }\ ],\ "policies": {\ "gas_price_cap": 30000000000000,\ "eip1559_pricing": true\ }\ },\ {\ "id": "solana-example",\ "name": "Solana Example",\ "network": "devnet",\ "paused": false,\ "notification_id": "notification-example",\ "signer_id": "local-signer",\ "network_type": "solana",\ "custom_rpc_urls": [\ {\ "url": "https://primary-solana-rpc.example.com",\ "weight": 2\ },\ {\ "url": "https://backup-solana-rpc.example.com",\ "weight": 1\ }\ ],\ "policies": {\ "fee_payment_strategy": "user",\ "min_balance": 0,\ "allowed_tokens": [\ {\ "mint": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr",\ "max_allowed_fee": 100000000\ },\ {\ "mint": "So11111111111111111111111111111111111111112"\ }\ ]\ }\ },\ {\ "id": "solana-mainnet-example",\ "name": "Solana Mainnet Example",\ "network": "mainnet-beta",\ "paused": false,\ "notification_id": "notification-example",\ "signer_id": "local-signer",\ "network_type": "solana",\ "custom_rpc_urls": ["https://your-private-solana-rpc.example.com"],\ "policies": {\ "fee_payment_strategy": "user",\ "min_balance": 0,\ "swap_config": {\ "cron_schedule": "0 0 * * * *",\ "min_balance_threshold": 0,\ "strategy": "jupiter-ultra"\ },\ "allowed_tokens": [\ {\ "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",\ "max_allowed_fee": 100000000,\ "swap_config": {\ "min_amount": 0,\ "max_amount": 0,\ "retain_min_amount": 0\ }\ },\ {\ "mint": "So11111111111111111111111111111111111111112"\ }\ ]\ }\ }\ ], "notifications": [\ {\ "id": "notification-example",\ "type": "webhook",\ "url": "https://webhook.site/1384d4d9-21b1-40a0-bcd1-d3f3b66be955",\ "signing_key": {\ "type": "env",\ "value": "WEBHOOK_SIGNING_KEY"\ }\ }\ ], "signers": [\ {\ "id": "local-signer",\ "type": "local",\ "config": {\ "path": "config/keys/local-signer.json",\ "passphrase": {\ "type": "env",\ "value": "KEYSTORE_PASSPHRASE"\ }\ }\ }\ ], "networks": [\ {\ "average_blocktime_ms": 12000,\ "chain_id": 11155111,\ "explorer_urls": [\ "https://api-sepolia.etherscan.io/api",\ "https://sepolia.etherscan.io"\ ],\ "features": [\ "eip1559"\ ],\ "is_testnet": true,\ "network": "sepolia",\ "required_confirmations": 6,\ "rpc_urls": [\ "https://sepolia.drpc.org",\ "https://1rpc.io/sepolia",\ "https://ethereum-sepolia-rpc.publicnode.com",\ "https://ethereum-sepolia-public.nodies.app"\ ],\ "symbol": "ETH",\ "tags": [\ "deprecated"\ ],\ "type": "evm"\ },\ {\ "type": "solana",\ "network": "devnet",\ "rpc_urls": ["https://api.devnet.solana.com"],\ "explorer_urls": ["https://explorer.solana.com?cluster=devnet"],\ "average_blocktime_ms": 400,\ "is_testnet": true\ },\ {\ "type": "solana",\ "network": "mainnet-beta",\ "rpc_urls": ["https://api.mainnet-beta.solana.com"],\ "explorer_urls": ["https://explorer.solana.com"],\ "average_blocktime_ms": 400,\ "is_testnet": false\ }\ ] } [Configuration Management Approaches](https://docs.openzeppelin.com/relayer/configuration#configuration-management-approaches) ------------------------------------------------------------------------------------------------------------------------------- The OpenZeppelin Relayer supports two complementary approaches for configuration management: ### [File-based Configuration](https://docs.openzeppelin.com/relayer/configuration#file-based-configuration) * Ideal for initial setup and deployment * Configuration persists across restarts * Requires container restart for changes to take effect * Suitable for infrastructure-as-code workflows ### [API-based Configuration](https://docs.openzeppelin.com/relayer/configuration#api-based-configuration) * Enables runtime configuration changes * No service restarts required * Perfect for dynamic environments * Supports automated configuration management See [Storage Configuration](https://docs.openzeppelin.com/relayer/configuration/storage) for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. [Quickstart\ \ Previous Page](https://docs.openzeppelin.com/relayer/quickstart) [Signers\ \ Next Page](https://docs.openzeppelin.com/relayer/configuration/signers) ### On this page [Overview](https://docs.openzeppelin.com/relayer/configuration#overview) [Environment configuration (.env)](https://docs.openzeppelin.com/relayer/configuration#environment-configuration-env) [Environment configuration example](https://docs.openzeppelin.com/relayer/configuration#environment-configuration-example) [Main configuration file (config.json)](https://docs.openzeppelin.com/relayer/configuration#main-configuration-file-configjson) [1\. Signers](https://docs.openzeppelin.com/relayer/configuration#1-signers) [2\. Notifications](https://docs.openzeppelin.com/relayer/configuration#2-notifications) [3\. Relayers](https://docs.openzeppelin.com/relayer/configuration#3-relayers) [RPC URL Configuration](https://docs.openzeppelin.com/relayer/configuration#rpc-url-configuration) [4\. Plugins](https://docs.openzeppelin.com/relayer/configuration#4-plugins) [5\. Networks](https://docs.openzeppelin.com/relayer/configuration#5-networks) [Configuration File Example](https://docs.openzeppelin.com/relayer/configuration#configuration-file-example) [Configuration Management Approaches](https://docs.openzeppelin.com/relayer/configuration#configuration-management-approaches) [File-based Configuration](https://docs.openzeppelin.com/relayer/configuration#file-based-configuration) [API-based Configuration](https://docs.openzeppelin.com/relayer/configuration#api-based-configuration) --- # Proxy Upgrade Pattern | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) Proxy Upgrade Pattern ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This article describes the "unstructured storage" proxy pattern, the fundamental building block of OpenZeppelin Upgrades. For a more in depth read, please see [our proxy-patterns blog post](https://blog.openzeppelin.com/proxy-patterns/) , which discusses the need for proxies, goes into more technical detail on the subject, elaborates on other possible proxy patterns that were considered for OpenZeppelin Upgrades, and more. [Why Upgrade a Contract?](https://docs.openzeppelin.com/upgrades-plugins/proxies#why-upgrade-a-contract) --------------------------------------------------------------------------------------------------------- By design, smart contracts are immutable. On the other hand, software quality heavily depends on the ability to upgrade and patch source code in order to produce iterative releases. Even though blockchain based software profits significantly from the technology’s immutability, still a certain degree of mutability is needed for bug fixing and potential product improvements. OpenZeppelin Upgrades solves this apparent contradiction by providing an easy to use, simple, robust, and opt-in upgrade mechanism for smart contracts that can be controlled by any type of governance, be it a multi-sig wallet, a simple address or a complex DAO. [Upgrading via the Proxy Pattern](https://docs.openzeppelin.com/upgrades-plugins/proxies#upgrading-via-the-proxy-pattern) -------------------------------------------------------------------------------------------------------------------------- The basic idea is using a proxy for upgrades. The first contract is a simple wrapper or "proxy" which users interact with directly and is in charge of forwarding transactions to and from the second contract, which contains the logic. The key concept to understand is that the logic contract can be replaced while the proxy, or the access point is never changed. Both contracts are still immutable in the sense that their code cannot be changed, but the logic contract can simply be swapped by another contract. The wrapper can thus point to a different logic implementation and in doing so, the software is "upgraded". User ---- tx ---> Proxy ----------> Implementation_v0 | ------------> Implementation_v1 | ------------> Implementation_v2 [Proxy Forwarding](https://docs.openzeppelin.com/upgrades-plugins/proxies#proxy-forwarding) -------------------------------------------------------------------------------------------- The most immediate problem that proxies need to solve is how the proxy exposes the entire interface of the logic contract without requiring a one to one mapping of the entire logic contract’s interface. That would be difficult to maintain, prone to errors, and would make the interface itself not upgradeable. Hence, a dynamic forwarding mechanism is required. The basics of such a mechanism are presented in the code below: // This code is for "illustration" purposes. To implement this functionality in production it // is recommended to use the `Proxy` contract from the `@openzeppelin/contracts` library. // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.2/contracts/proxy/Proxy.sol assembly { // (1) copy incoming call data calldatacopy(0, 0, calldatasize()) // (2) forward call to logic contract let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // (3) retrieve return data returndatacopy(0, 0, returndatasize()) // (4) forward return data back to caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } This code can be put in the [fallback function](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function) of a proxy, and will forward any call to any function with any set of parameters to the logic contract without it needing to know anything in particular of the logic contract’s interface. In essence, (1) the `calldata` is copied to memory, (2) the call is forwarded to the logic contract, (3) the return data from the call to the logic contract is retrieved, and (4) the returned data is forwarded back to the caller. A very important thing to note is that the code makes use of the EVM’s `delegatecall` opcode which executes the callee’s code in the context of the caller’s state. That is, the logic contract controls the proxy’s state and the logic contract’s state is meaningless. Thus, the proxy doesn’t only forward transactions to and from the logic contract, but also represents the pair’s state. The state is in the proxy and the logic is in the particular implementation that the proxy points to. [Unstructured Storage Proxies](https://docs.openzeppelin.com/upgrades-plugins/proxies#unstructured-storage-proxies) -------------------------------------------------------------------------------------------------------------------- A problem that quickly comes up when using proxies has to do with the way in which variables are stored in the proxy contract. Suppose that the proxy stores the logic contract’s address in its only variable `address public _implementation;`. Now, suppose that the logic contract is a basic token whose first variable is `address public _owner`. Both variables are 32 byte in size, and as far as the EVM knows, occupy the first slot of the resulting execution flow of a proxied call. When the logic contract writes to `_owner`, it does so in the scope of the proxy’s state, and in reality writes to `_implementation`. This problem can be referred to as a "storage collision". |Proxy |Implementation | |--------------------------|-------------------------| |address _implementation |address _owner | <=== Storage collision! |... |mapping _balances | | |uint256 _supply | | |... | There are many ways to overcome this problem, and the "unstructured storage" approach which OpenZeppelin Upgrades implements works as follows. Instead of storing the `_implementation` address at the proxy’s first storage slot, it chooses a pseudo random slot instead. This slot is sufficiently random, that the probability of a logic contract declaring a variable at the same slot is negligible. The same principle of randomizing slot positions in the proxy’s storage is used in any other variables the proxy may have, such as an admin address (that is allowed to update the value of `_implementation`), etc. |Proxy |Implementation | |--------------------------|-------------------------| |... |address _owner | |... |mapping _balances | |... |uint256 _supply | |... |... | |... | | |... | | |... | | |... | | |address _implementation | | <=== Randomized slot. |... | | |... | | An example of how the randomized storage is achieved, following [EIP 1967](http://eips.ethereum.org/EIPS/eip-1967) : bytes32 private constant implementationPosition = bytes32(uint256( keccak256('eip1967.proxy.implementation')) - 1 )); As a result, a logic contract doesn’t need to care about overwriting any of the proxy’s variables. Other proxy implementations that face this problem usually imply having the proxy know about the logic contract’s storage structure and adapt to it, or instead having the logic contract know about the proxy’s storage structure and adapt to it. This is why this approach is called "unstructured storage"; neither of the contracts needs to care about the structure of the other. [Storage Collisions Between Implementation Versions](https://docs.openzeppelin.com/upgrades-plugins/proxies#storage-collisions-between-implementation-versions) ---------------------------------------------------------------------------------------------------------------------------------------------------------------- As discussed, the unstructured approach avoids storage collisions between the logic contract and the proxy. However, storage collisions between different versions of the logic contract can occur. In this case, imagine that the first implementation of the logic contract stores `address public _owner` at the first storage slot and an upgraded logic contract stores `address public _lastContributor` at the same first slot. When the updated logic contract attempts to write to the `_lastContributor` variable, it will be using the same storage position where the previous value for `_owner` was being stored, and overwrite it! Incorrect storage preservation: |Implementation_v0 |Implementation_v1 | |--------------------|-------------------------| |address _owner |address _lastContributor | <=== Storage collision! |mapping _balances |address _owner | |uint256 _supply |mapping _balances | |... |uint256 _supply | | |... | Correct storage preservation: |Implementation_v0 |Implementation_v1 | |--------------------|-------------------------| |address _owner |address _owner | |mapping _balances |mapping _balances | |uint256 _supply |uint256 _supply | |... |address _lastContributor | <=== Storage extension. | |... | The unstructured storage proxy mechanism doesn’t safeguard against this situation. It is up to the user to have new versions of a logic contract extend previous versions, or otherwise guarantee that the storage hierarchy is always appended to but not modified. However, OpenZeppelin Upgrades detects such collisions and warns the developer appropriately. [The Constructor Caveat](https://docs.openzeppelin.com/upgrades-plugins/proxies#the-constructor-caveat) -------------------------------------------------------------------------------------------------------- In Solidity, code that is inside a constructor or part of a global variable declaration is not part of a deployed contract’s runtime bytecode. This code is executed only once, when the contract instance is deployed. As a consequence of this, the code within a logic contract’s constructor will never be executed in the context of the proxy’s state. To rephrase, proxies are completely oblivious to the storage trie changes that are performed by the constructor. It’s simply as if they weren’t there for the proxy. (Note that `immutable` variables can be reflected in a proxy contract but [should be used with caution](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-immutable-variables) .) The problem is easily solved though. Logic contracts should move the code within the constructor to a regular 'initializer' function, and have this function be called whenever the proxy links to this logic contract. Special care needs to be taken with this initializer function so that it can only be called once, which is one of the properties of constructors in general programming. This is why when we create a proxy using OpenZeppelin Upgrades, you can provide the name of the initializer function and pass parameters. To ensure that the `initialize` function can only be called once, a simple modifier is used. OpenZeppelin Upgrades provides this functionality via a contract that can be extended: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract MyContract is Initializable { function initialize( address arg1, uint256 arg2, bytes memory arg3 ) public payable initializer { // "constructor" code... } } Notice how the contract extends `Initializable` and implements the `initializer` provided by it. [Transparent Proxies and Function Clashes](https://docs.openzeppelin.com/upgrades-plugins/proxies#transparent-proxies-and-function-clashes) -------------------------------------------------------------------------------------------------------------------------------------------- As described in the previous sections, upgradeable contract instances (or proxies) work by delegating all calls to a logic contract. However, the proxies need some functions of their own, such as `upgradeTo(address)` to upgrade to a new implementation. This begs the question of how to proceed if the logic contract also has a function named `upgradeTo(address)`: upon a call to that function, did the caller intend to call the proxy or the logic contract? Clashing can also happen among functions with different names. Every function that is part of a contract’s public ABI is identified, at the bytecode level, by a 4-byte identifier. This identifier depends on the name and arity of the function, but since it’s only 4 bytes, there is a possibility that two different functions with different names may end up having the same identifier. The Solidity compiler tracks when this happens within the same contract, but not when the collision happens across different ones, such as between a proxy and its logic contract. Read [this article](https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357) for more info on this. The way OpenZeppelin Upgrades deals with this problem is via the _transparent proxy_ pattern. A transparent proxy will decide which calls are delegated to the underlying logic contract based on the caller address (i.e., the `msg.sender`): * If the caller is the admin of the proxy (the address with rights to upgrade the proxy), then the proxy will **not** delegate any calls, and only answer any messages it understands. * If the caller is any other address, the proxy will **always** delegate a call, no matter if it matches one of the proxy’s functions. Assuming a proxy with an `owner()` and an `upgradeTo()` function, that delegates calls to an ERC20 contract with an `owner()` and a `transfer()` function, the following table covers all scenarios: | msg.sender | owner() | upgradeTo() | transfer() | | --- | --- | --- | --- | | Owner | returns proxy.owner() | returns proxy.upgradeTo() | fails | | Other | returns erc20.owner() | fails | returns erc20.transfer() | Fortunately, OpenZeppelin Upgrades accounts for this situation, and uses an intermediary ProxyAdmin contract for each transparent proxy. Even if you call the `deploy` command from your node’s default account, the ProxyAdmin contracts will be the actual admins of your transparent proxies. This means that you will be able to interact with the proxies from any of your node’s accounts, without having to worry about the nuances of the transparent proxy pattern. Only advanced users that create proxies from Solidity need to be aware of the transparent proxies pattern. [Summary](https://docs.openzeppelin.com/upgrades-plugins/proxies#summary) -------------------------------------------------------------------------- Any developer using upgradeable contracts should be familiar with proxies in the ways that are described in this article. In the end, the concept is very simple, and OpenZeppelin Upgrades is designed to encapsulate all the proxy mechanics in a way that the amount of things you need to keep in mind when developing projects are reduced to an absolute minimum. It all comes down to the following list: * Have a basic understanding of what a proxy is * Always extend storage instead of modifying it * Make sure your contracts use initializer functions instead of constructors Furthermore, the OpenZeppelin Upgrades will let you know when something goes wrong with one of the items in this list. ### On this page [Why Upgrade a Contract?](https://docs.openzeppelin.com/upgrades-plugins/proxies#why-upgrade-a-contract) [Upgrading via the Proxy Pattern](https://docs.openzeppelin.com/upgrades-plugins/proxies#upgrading-via-the-proxy-pattern) [Proxy Forwarding](https://docs.openzeppelin.com/upgrades-plugins/proxies#proxy-forwarding) [Unstructured Storage Proxies](https://docs.openzeppelin.com/upgrades-plugins/proxies#unstructured-storage-proxies) [Storage Collisions Between Implementation Versions](https://docs.openzeppelin.com/upgrades-plugins/proxies#storage-collisions-between-implementation-versions) [The Constructor Caveat](https://docs.openzeppelin.com/upgrades-plugins/proxies#the-constructor-caveat) [Transparent Proxies and Function Clashes](https://docs.openzeppelin.com/upgrades-plugins/proxies#transparent-proxies-and-function-clashes) [Summary](https://docs.openzeppelin.com/upgrades-plugins/proxies#summary) --- # Network Configuration | OpenZeppelin Docs Relayer[Configuration](https://docs.openzeppelin.com/relayer/configuration) Network Configuration ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) The OpenZeppelin Relayer supports multiple blockchain networks through a flexible JSON-based configuration system. This guide covers everything you need to know about configuring networks for your relayer instances. [Overview](https://docs.openzeppelin.com/relayer/network_configuration#overview) --------------------------------------------------------------------------------- Networks are defined in JSON configuration files, allowing you to: * Configure _**any EVM-compatible network**_ (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) * Set up _**Solana networks**_ (mainnet-beta, devnet, testnet, custom RPC endpoints) * Configure _**Stellar networks**_ (Pubnet, Testnet, custom networks) * Create _**custom network configurations**_ with specific RPC endpoints, chain IDs, and network parameters * Use _**inheritance**_ to create network variants without duplicating configuration [Network Types](https://docs.openzeppelin.com/relayer/network_configuration#network-types) ------------------------------------------------------------------------------------------- | Network Type | Description | | --- | --- | | `evm` | Ethereum Virtual Machine compatible networks. Supports any EVM chain by configuring chain ID, RPC URLs, and network-specific parameters. | | `solana` | Solana blockchain networks. Supports all Solana clusters and custom RPC endpoints. | | `stellar` | Stellar blockchain networks. Supports Stellar Public Network and Testnet. | [Configuration Methods](https://docs.openzeppelin.com/relayer/network_configuration#configuration-methods) ----------------------------------------------------------------------------------------------------------- ### [Default Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#default-network-configuration) If no `networks` field is specified in your `config.json`, the relayer will automatically load network configurations from the `./config/networks` directory. This is the default behavior. "relayers": [...], "notifications": [...], "signers": [...] // No "networks" field - defaults to "./config/networks" Once you specify a `networks` field in your configuration, the default `./config/networks` directory will _**not**_ be loaded automatically. If you want to use files from that directory, you must explicitly specify the path `"./config/networks"`. You can configure networks in two ways: ### [Method 1: Separate JSON Files](https://docs.openzeppelin.com/relayer/network_configuration#method-1-separate-json-files) Specify the path to network configuration files in your main `config.json`: "relayers": [...], "notifications": [...], "signers": [...], "networks": "./config/networks" // Path to directory or file This is the same as the default behavior, but explicitly specified. You can also point to a different directory or file path. Each JSON file _**must**_ contain a top-level `networks` array: "networks": [\ // ... network definitions ...\ ] When using a directory structure: networks/ ├── evm.json # "networks": [...] ├── solana.json # "networks": [...] └── stellar.json # "networks": [...] ### [Method 2: Direct Configuration](https://docs.openzeppelin.com/relayer/network_configuration#method-2-direct-configuration) Define networks directly in your main `config.json` instead of using separate files: "relayers": [...], "notifications": [...], "signers": [...], "networks": [\ {\ "type": "evm",\ "network": "ethereum-mainnet",\ "chain_id": 1,\ // ... other fields\ \ ] } When using this method, the default `./config/networks` directory is ignored, and only the networks defined in this array will be available. [Network Field Reference](https://docs.openzeppelin.com/relayer/network_configuration#network-field-reference) --------------------------------------------------------------------------------------------------------------- ### [Common Fields](https://docs.openzeppelin.com/relayer/network_configuration#common-fields) All network types support these configuration fields: | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Network type: `"evm"`, `"solana"`, or `"stellar"` | | `network` | string | Yes | Unique network identifier (e.g., "ethereum-mainnet", "polygon-mumbai") | | `from` | string | No | Name of parent network to inherit from (same type only) | | `rpc_urls` | array\[string\] | Yes\* | List of RPC endpoint URLs (\*Required for base networks, optional for inherited) | | `explorer_urls` | array\[string\] | No | List of blockchain explorer URLs | | `average_blocktime_ms` | number | No | Estimated average time between blocks in milliseconds | | `is_testnet` | boolean | No | Whether this is a testnet (affects behavior and validation) | | `tags` | array\[string\] | No | Arbitrary tags for categorization and filtering | ### [Special Network Tags](https://docs.openzeppelin.com/relayer/network_configuration#special-network-tags) Some tags have special meaning and affect relayer behavior: | Tag | Description and Behavior | | --- | --- | | `rollup` | Identifies Layer 2 rollup networks (e.g., Arbitrum, Optimism, Base) | | `optimism` | Identifies Optimism-based networks using the OP Stack (e.g., Optimism, Base, World Chain) | | `arbitrum-based` | Identifies Arbitrum-based networks using the Arbitrum Stack | | `no-mempool` | Indicates networks that lack a traditional mempool (e.g., Arbitrum) | | `deprecated` | Marks networks that are deprecated and may be removed in future versions | #### [Example: Using Special Tags](https://docs.openzeppelin.com/relayer/network_configuration#example-using-special-tags) Here’s an example showing how special tags are used in practice: "type": "evm", "network": "arbitrum-one", "chain_id": 42161, "required_confirmations": 1, "symbol": "ETH", "rpc_urls": ["https://arb1.arbitrum.io/rpc"], "tags": ["rollup", "no-mempool"], // Arbitrum is a rollup without mempool "is_testnet": false These tags help the relayer: * Apply specific transaction handling for rollups * Use optimized fee calculation for OP Stack chains * Skip mempool-related operations for networks without mempools * Warn users about deprecated networks ### [EVM-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#evm-specific-fields) The OpenZeppelin Relayer supports any EVM-based L1 blockchain, as long as it doesn’t deviate significantly from standard EVM behavior. Some L2 networks may also work, depending on how closely they follow EVM conventions. Users are encouraged to add the networks they need via the JSON configuration and test them thoroughly on testnets before deploying to production. | Field | Type | Required | Description | | --- | --- | --- | --- | | `chain_id` | number | Yes\* | Unique chain identifier (e.g., 1 for Ethereum mainnet, 137 for Polygon) (\*Required for base networks, optional for inherited) | | `required_confirmations` | number | Yes\* | Number of block confirmations before considering a transaction final (\*Required for base networks, optional for inherited) | | `symbol` | string | Yes\* | Native currency symbol (e.g., "ETH", "MATIC", "BNB") (\*Required for base networks, optional for inherited) | | `features` | array\[string\] | No | Supported features (e.g., \["eip1559", "london"\]) | #### [Example: EVM Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#example-evm-network-configuration) Here’s an example showing an EVM network configuration: "type": "evm", "network": "ethereum-mainnet", "chain_id": 1, // Ethereum mainnet chain ID "required_confirmations": 12, // High security: 12 confirmations "symbol": "ETH", // Native currency symbol "features": ["eip1559"], // Supports EIP-1559 fee market "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], "is_testnet": false ### [Solana-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#solana-specific-fields) Currently, Solana networks use only the common fields. Additional Solana-specific configuration options may be added in future versions. ### [Stellar-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#stellar-specific-fields) | Field | Type | Required | Description | | --- | --- | --- | --- | | `passphrase` | string | No | Network passphrase for transaction signing and network identification (optional for all networks, including base networks) | #### [Example: Stellar Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#example-stellar-network-configuration) Here’s an example showing a Stellar network configuration with passphrase: "type": "stellar", "network": "pubnet", "rpc_urls": ["https://mainnet.sorobanrpc.com"], "explorer_urls": ["https://stellar.expert/explorer/public"], "passphrase": "Public Global Stellar Network ; September 2015", // Official mainnet passphrase "average_blocktime_ms": 5000, "is_testnet": false [Configuration Examples](https://docs.openzeppelin.com/relayer/network_configuration#configuration-examples) ------------------------------------------------------------------------------------------------------------- ### [Basic EVM Network](https://docs.openzeppelin.com/relayer/network_configuration#basic-evm-network) "type": "evm", "network": "ethereum-mainnet", "chain_id": 1, "required_confirmations": 12, "symbol": "ETH", "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"], "explorer_urls": ["https://etherscan.io"], "average_blocktime_ms": 12000, "is_testnet": false, "tags": ["mainnet", "ethereum"] ### [Layer 2 EVM Network with Tags](https://docs.openzeppelin.com/relayer/network_configuration#layer-2-evm-network-with-tags) "type": "evm", "network": "optimism", "chain_id": 10, "required_confirmations": 1, "symbol": "ETH", "rpc_urls": [\ "https://mainnet.optimism.io",\ "https://optimism.drpc.org"\ ], "features": ["eip1559"], "tags": ["rollup", "optimism"], "average_blocktime_ms": 2000, "is_testnet": false ### [Solana Network](https://docs.openzeppelin.com/relayer/network_configuration#solana-network) "type": "solana", "network": "mainnet-beta", "rpc_urls": ["https://api.mainnet-beta.solana.com"], "explorer_urls": ["https://explorer.solana.com"], "average_blocktime_ms": 400, "is_testnet": false, "tags": ["mainnet", "solana"] ### [Stellar Network](https://docs.openzeppelin.com/relayer/network_configuration#stellar-network) "type": "stellar", "network": "pubnet", "rpc_urls": ["https://mainnet.sorobanrpc.com"], "passphrase": "Public Global Stellar Network ; September 2015", "explorer_urls": ["https://stellar.expert/explorer/public"], "average_blocktime_ms": 5000, "is_testnet": false, "tags": ["mainnet", "stellar"] [Network Inheritance](https://docs.openzeppelin.com/relayer/network_configuration#network-inheritance) ------------------------------------------------------------------------------------------------------- Networks can inherit from other networks of the same type, allowing you to create variants without duplicating configuration: "networks": [\ {\ "type": "evm",\ "network": "ethereum-base",\ "chain_id": 1,\ "required_confirmations": 12,\ "symbol": "ETH",\ "rpc_urls": ["https://mainnet.infura.io/v3/YOUR_KEY"]\ ,\ \ "from": "ethereum-base",\ "type": "evm",\ "network": "ethereum-sepolia",\ "chain_id": 11155111,\ "required_confirmations": 3,\ "rpc_urls": ["https://sepolia.infura.io/v3/YOUR_KEY"],\ "is_testnet": true\ \ ] } When using inheritance: * The child network inherits all fields from the parent * Fields specified in the child override parent values * The `from` field must reference a network of the same type [Using Networks in Relayer Configuration](https://docs.openzeppelin.com/relayer/network_configuration#using-networks-in-relayer-configuration) ----------------------------------------------------------------------------------------------------------------------------------------------- Once networks are defined, reference them in your relayer configurations: "relayers": [\ {\ "id": "my-evm-relayer",\ "name": "My EVM Relayer",\ "network": "ethereum-mainnet", // References network ID\ "network_type": "evm",\ "signer_id": "my-signer"\ \ ] } } [Best Practices](https://docs.openzeppelin.com/relayer/network_configuration#best-practices) --------------------------------------------------------------------------------------------- ### [1\. Network Organization](https://docs.openzeppelin.com/relayer/network_configuration#1-network-organization) * Group related networks in separate files (e.g., `ethereum.json`, `polygon.json`) * Use consistent naming conventions for network identifiers * Include both mainnet and testnet configurations ### [2\. RPC URLs](https://docs.openzeppelin.com/relayer/network_configuration#2-rpc-urls) * Always configure multiple RPC URLs for redundancy * Use private/dedicated RPC endpoints for production * Ensure URLs are secure (HTTPS) when accessing over public networks ### [3\. Confirmation Requirements](https://docs.openzeppelin.com/relayer/network_configuration#3-confirmation-requirements) * Set appropriate `required_confirmations` based on network security * Higher values for mainnet, lower for testnets * Consider network-specific finality characteristics ### [4\. Tags and Features](https://docs.openzeppelin.com/relayer/network_configuration#4-tags-and-features) * Use tags to categorize networks (e.g., "mainnet", "testnet", "rollup") * Enable appropriate features (e.g., "eip1559" for supported networks) * Document custom tags used in your organization ### [5\. Inheritance](https://docs.openzeppelin.com/relayer/network_configuration#5-inheritance) * Create base configurations for common settings * Use inheritance to reduce duplication * Override only necessary fields in child networks [Troubleshooting](https://docs.openzeppelin.com/relayer/network_configuration#troubleshooting) ----------------------------------------------------------------------------------------------- ### [Common Issues](https://docs.openzeppelin.com/relayer/network_configuration#common-issues) _**Network not found:**_ * Ensure the network identifier in relayer config matches exactly * Check that network configuration files are in the correct location * Verify JSON syntax is valid _**RPC connection failures:**_ * Test RPC URLs independently before configuring * Ensure firewall/network allows outbound HTTPS connections * Check API keys are included in RPC URLs where required _**Invalid configuration:**_ * Validate required fields are present for network type * Ensure numeric fields (chain\_id, confirmations) are numbers, not strings * Check that inherited networks reference existing parent networks [See Also](https://docs.openzeppelin.com/relayer/network_configuration#see-also) --------------------------------------------------------------------------------- * [Relayer Configuration](https://docs.openzeppelin.com/relayer/configuration) * [Quickstart Guide](https://docs.openzeppelin.com/relayer/quickstart) * [Solana Integration](https://docs.openzeppelin.com/relayer/solana) * [API Reference](https://docs.openzeppelin.com/relayer/api) [Signers\ \ Previous Page](https://docs.openzeppelin.com/relayer/configuration/signers) [Storage Configuration\ \ Next Page](https://docs.openzeppelin.com/relayer/configuration/storage) ### On this page [Overview](https://docs.openzeppelin.com/relayer/network_configuration#overview) [Network Types](https://docs.openzeppelin.com/relayer/network_configuration#network-types) [Configuration Methods](https://docs.openzeppelin.com/relayer/network_configuration#configuration-methods) [Default Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#default-network-configuration) [Method 1: Separate JSON Files](https://docs.openzeppelin.com/relayer/network_configuration#method-1-separate-json-files) [Method 2: Direct Configuration](https://docs.openzeppelin.com/relayer/network_configuration#method-2-direct-configuration) [Network Field Reference](https://docs.openzeppelin.com/relayer/network_configuration#network-field-reference) [Common Fields](https://docs.openzeppelin.com/relayer/network_configuration#common-fields) [Special Network Tags](https://docs.openzeppelin.com/relayer/network_configuration#special-network-tags) [Example: Using Special Tags](https://docs.openzeppelin.com/relayer/network_configuration#example-using-special-tags) [EVM-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#evm-specific-fields) [Example: EVM Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#example-evm-network-configuration) [Solana-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#solana-specific-fields) [Stellar-Specific Fields](https://docs.openzeppelin.com/relayer/network_configuration#stellar-specific-fields) [Example: Stellar Network Configuration](https://docs.openzeppelin.com/relayer/network_configuration#example-stellar-network-configuration) [Configuration Examples](https://docs.openzeppelin.com/relayer/network_configuration#configuration-examples) [Basic EVM Network](https://docs.openzeppelin.com/relayer/network_configuration#basic-evm-network) [Layer 2 EVM Network with Tags](https://docs.openzeppelin.com/relayer/network_configuration#layer-2-evm-network-with-tags) [Solana Network](https://docs.openzeppelin.com/relayer/network_configuration#solana-network) [Stellar Network](https://docs.openzeppelin.com/relayer/network_configuration#stellar-network) [Network Inheritance](https://docs.openzeppelin.com/relayer/network_configuration#network-inheritance) [Using Networks in Relayer Configuration](https://docs.openzeppelin.com/relayer/network_configuration#using-networks-in-relayer-configuration) [Best Practices](https://docs.openzeppelin.com/relayer/network_configuration#best-practices) [1\. Network Organization](https://docs.openzeppelin.com/relayer/network_configuration#1-network-organization) [2\. RPC URLs](https://docs.openzeppelin.com/relayer/network_configuration#2-rpc-urls) [3\. Confirmation Requirements](https://docs.openzeppelin.com/relayer/network_configuration#3-confirmation-requirements) [4\. Tags and Features](https://docs.openzeppelin.com/relayer/network_configuration#4-tags-and-features) [5\. Inheritance](https://docs.openzeppelin.com/relayer/network_configuration#5-inheritance) [Troubleshooting](https://docs.openzeppelin.com/relayer/network_configuration#troubleshooting) [Common Issues](https://docs.openzeppelin.com/relayer/network_configuration#common-issues) [See Also](https://docs.openzeppelin.com/relayer/network_configuration#see-also) --- # Frequently Asked Questions | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) Frequently Asked Questions ========================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Can I change Solidity compiler versions when upgrading?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-change-solidity-compiler-versions-when-upgrading) --------------------------------------------------------------------------------------------------------------------------------------------------------------------- Yes. The Solidity team guarantees that the compiler will [preserve the storage layout across versions](https://twitter.com/ethchris/status/1073692785176444928) . [Why am I getting the error "Cannot call fallback function from the proxy admin"?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-am-i-getting-the-error-cannot-call-fallback-function-from-the-proxy-admin) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This is due to the [Transparent Proxy Pattern](https://docs.openzeppelin.com/upgrades-plugins/proxies#transparent-proxies-and-function-clashes) . You shouldn’t get this error when using the OpenZeppelin Upgrades Plugins, since it uses the `ProxyAdmin` contract for managing your proxies. However, if you are using OpenZeppelin Contracts proxies programmatically you could potentially run into such error. The solution is to always interact with your proxies from an account that is not the admin of the proxy, unless you want to specifically call the functions of the proxy itself. [What does it mean for a contract to be upgrade safe?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-a-contract-to-be-upgrade-safe) --------------------------------------------------------------------------------------------------------------------------------------------------------------- When deploying a proxy for a contract, there are some limitations to the contract code. In particular, the contract cannot have a constructor, and should not use the `selfdestruct` or `delegatecall` operations for security reasons. As a replacement for the constructor, it is common to set up an `initialize` function to take care of the contract’s initialization. You can use the [`Initializable`](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializers) base contract to have access to an `initializer` modifier that ensures the function is only called once. import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract MyContract is Initializable { uint256 value; function initialize(uint256 initialValue) public initializer { value = initialValue; } } Both plugins will validate that the contract you are trying to deploy complies with these rules. You can read more about how to write upgrade safe contracts [here](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable) . [How can I disable some of the checks?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-disable-some-of-the-checks) --------------------------------------------------------------------------------------------------------------------------------- Deployment and upgrade related functions come with an optional `opts` object, which includes an `unsafeAllow` option. This can be set to disable any check performed by the plugin. The list of checks that can individually be disabled is: * `state-variable-assignment` * `state-variable-immutable` * `external-library-linking` * `struct-definition` * `enum-definition` * `constructor` * `delegatecall` * `selfdestruct` * `missing-public-upgradeto` * `internal-function-storage` This function is a generalized version of the original `unsafeAllowCustomTypes` and `unsafeAllowLinkedLibraries` allowing any check to be manually disabled. For example, in order to upgrade to an implementation that contains a delegate call, you would call: await upgradeProxy(proxyAddress, implementationFactory, unsafeAllow: ['delegatecall'] ); Additionally, it is possible to precisely disable checks directly from the Solidity source code using NatSpec comments. This requires Solidity >=0.8.2. contract SomeContract { function some_dangerous_function() public { ... /// @custom:oz-upgrades-unsafe-allow delegatecall (bool success, bytes memory returndata) = msg.sender.delegatecall(""); ... } } This syntax can be used with the following errors: * `/// @custom:oz-upgrades-unsafe-allow state-variable-immutable` * `/// @custom:oz-upgrades-unsafe-allow state-variable-assignment` * `/// @custom:oz-upgrades-unsafe-allow external-library-linking` * `/// @custom:oz-upgrades-unsafe-allow constructor` * `/// @custom:oz-upgrades-unsafe-allow delegatecall` * `/// @custom:oz-upgrades-unsafe-allow selfdestruct` In some cases you may want to allow multiple errors in a single line. /// @custom:oz-upgrades-unsafe-allow constructor state-variable-immutable contract SomeOtherContract { uint256 immutable x; constructor() { x = block.number; } } You can also use the following to allow specific errors in reachable code, which includes any referenced contracts, functions, and libraries: * `/// @custom:oz-upgrades-unsafe-allow-reachable delegatecall` * `/// @custom:oz-upgrades-unsafe-allow-reachable selfdestruct` [Can I safely use `delegatecall` and `selfdestruct`?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-safely-use-delegatecall-and-selfdestruct) --------------------------------------------------------------------------------------------------------------------------------------------------------- This is an advanced technique and can put funds at risk of permanent loss. It may be possible to safely use `delegatecall` and `selfdestruct` if they are guarded so that they can only be triggered through proxies and not on the implementation contract itself. A way to achieve this in Solidity is as follows. abstract contract OnlyDelegateCall { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable self = address(this); function checkDelegateCall() private view { require(address(this) != self); } modifier onlyDelegateCall() { checkDelegateCall(); _; } } contract UsesUnsafeOperations is OnlyDelegateCall { /// @custom:oz-upgrades-unsafe-allow selfdestruct function destroyProxy() onlyDelegateCall { selfdestruct(msg.sender); } } [What does it mean for an implementation to be compatible?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-an-implementation-to-be-compatible) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- When upgrading a proxy from one implementation to another, the _storage layout_ of both implementations must be compatible. This means that, even though you can completely change the code of the implementation, you cannot modify the existing contract state variables. The only operation allowed is to append new state variables after the ones already declared. Both plugins will validate that the new implementation contract is compatible with the previous one. You can read more about how to make storage-compatible changes to an implementation contract [here](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts) . [What is a proxy admin?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy-admin) --------------------------------------------------------------------------------------------------- A `ProxyAdmin` is an intermediary contract that acts as the upgrader of a transparent proxy. Each `ProxyAdmin` is owned by the deployer address, or by the `initialOwner` address when deploying a transparent proxy from OpenZeppelin Contracts 5.0 or above. You can transfer the ownership of a proxy admin by calling [`transferOwnership`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) . [What is an implementation contract?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-an-implementation-contract) ----------------------------------------------------------------------------------------------------------------------------- Upgradeable deployments require at least two contracts: a proxy and an implementation. The proxy contract is the instance you and your users will interact with, and the implementation is the contract that holds the code. If you call `deployProxy` several times for the same implementation contract, several proxies will be deployed, but only one implementation contract will be used. When you upgrade a proxy to a new version, a new implementation contract is deployed if needed, and the proxy is set to use the new implementation contract. You can read more about the proxy upgrade pattern [here](https://docs.openzeppelin.com/upgrades-plugins/proxies) . [What is a proxy?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy) --------------------------------------------------------------------------------------- A proxy is a contract that delegates all of its calls to a second contract, named an implementation contract. All state and funds are held in the proxy, but the code actually executed is that of the implementation. A proxy can be _upgraded_ by its admin to use a different implementation contract. You can read more about the proxy upgrade pattern [here](https://docs.openzeppelin.com/upgrades-plugins/proxies) . [Why can't I use `immutable` variables?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-immutable-variables) -------------------------------------------------------------------------------------------------------------------------------- Solidity 0.6.5 [introduced the `immutable` keyword](https://github.com/ethereum/solidity/releases/tag/v0.6.5) to declare a variable that can be assigned only once during construction and can be read only after construction. It does so by calculating its value during contract creation and storing its value directly into the bytecode. Notice that this behavior is incompatible with the way upgradeable contracts work for two reasons: 1. Upgradeable contracts have no constructors but initializers, therefore they can’t handle immutable variables. 2. Since the immutable variable value is stored in the bytecode its value would be shared among all proxies pointing to a given contract instead of each proxy’s storage. In some cases immutable variables are upgrade safe. The plugins cannot currently detect these cases automatically so they will point it out as an error anyway. You can manually disable the check using the option `unsafeAllow: ['state-variable-immutable']`, or in Solidity >=0.8.2 placing the comment `/// @custom:oz-upgrades-unsafe-allow state-variable-immutable` before the variable declaration. [Why can't I use external libraries?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-external-libraries) ---------------------------------------------------------------------------------------------------------------------------- At the moment, the plugins only have partial support for upgradeable contracts linked to external libraries. This is because it’s not known at compile time what implementation is going to be linked, thus making it very difficult to guarantee the safety of the upgrade operation. There are plans to add this functionality in the near future with certain constraints that make the issue easier to address like assuming that the external library’s source code is either present in the codebase or that it’s been deployed and mined so it can be fetched from the blockchain for analysis. In the meantime, you can deploy upgradeable contracts linked to external libraries by setting the `unsafeAllowLinkedLibraries` flag to true in the `deployProxy` or `upgradeProxy` calls, or including ’external-library-linking'`in the`unsafeAllow\` array. Keep in mind the plugins will not verify that the linked libraries are upgrade safe. This has to be done manually for now until the full support for external libraries is implemented. You can follow or contribute to [this issue in GitHub](https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/52) . [Why do I need a public `upgradeTo` or `upgradeToAndCall` function?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-do-i-need-a-public-upgradeto-or-upgradetoandcall-function) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- When using UUPS proxies (through the `kind: 'uups'` option), the implementation contract must include one or both of the public functions `upgradeTo(address newImplementation)` or `upgradeToAndCall(address newImplementation, bytes memory data)`. This is because in the UUPS pattern the proxy does not contain an upgrading function itself, and the entire upgradeability mechanism lives on the implementation side. Thus, on every deploy and upgrade we have to make sure to include it, otherwise we may permanently disable the upgradeability of the contract. The recommended way to include one or both of these functions is by inheriting the `UUPSUpgradeable` contract provided in OpenZeppelin Contracts, as shown below. This contract adds the required function(s), but also contains a built-in mechanism that will check on-chain, at the time of an upgrade, that the new implementation proposed also inherits `UUPSUpgradeable` or implements the same interface. In this way, when using the Upgrades Plugins there are two layers of mitigations to prevent accidentally disabling upgradeability: an off-chain check by the plugins, and an on-chain fallback in the contract itself. import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; contract MyContract is Initializable, ..., UUPSUpgradeable { ... } Read more about the differences with the Transparent Proxy Pattern in [Transparent vs UUPS](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups) . [Can I use custom types like structs and enums?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-use-custom-types-like-structs-and-enums) --------------------------------------------------------------------------------------------------------------------------------------------------- Past versions of the plugins did not support upgradeable contracts that used custom types like structs or enums in their code or linked libraries. This is no longer the case for current versions of the plugins, and structs and enums will be automatically checked for compatibility when upgrading a contract. Some users who have already deployed proxies with structs and/or enums and who need to upgrade those proxies may need to use the override flag `unsafeAllowCustomTypes` for their next upgrade, after which it will no longer be necessary. If the project contains the source code for the implementation currently in use by the proxy, the plugin will attempt to recover the metadata that it needs before the upgrade, falling back to the override flag if this is not possible. [How can I rename a variable, or change its type?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-rename-a-variable-or-change-its-type) ------------------------------------------------------------------------------------------------------------------------------------------------------ Renaming a variable is disallowed by default because there is a chance that a renaming is actually an accidental reordering. For example, if variables `uint a; uint b;` are upgraded to `uint b; uint a;`, if renaming was simply allowed this would not be seen as a mistake, but it could have been an accident, especially when multiple inheritance is involved. It is possible to disable this check by passing the option `unsafeAllowRenames: true`. A more granular approach is to use a docstring comment `/// @custom:oz-renamed-from ` right above the variable that is being renamed, for example: contract V1 { uint x; } contract V2 { /// @custom:oz-renamed-from x uint y; } Changing the type of a variable is not allowed either, even in cases where the types have the same size and alignment, for the similar reason explained above. As long as we can guarantee that the rest of the layout is not affected by this type change, it is also possible to override this check by placing a docstring comment `/// @custom:oz-retyped-from `. contract V1 { bool x; } contract V2 { /// @custom:oz-retyped-from bool uint8 x; } Docstring comments don’t yet work for struct members, due to a current Solidity limitation. [How can I use internal functions in storage variables?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-use-internal-functions-in-storage-variables) ------------------------------------------------------------------------------------------------------------------------------------------------------------------- Internal functions in storage variables are code pointers which will no longer be valid after an upgrade, because the code will move around and the pointer would change. To avoid this issue, you can declare those functions as external, or avoid code pointers in storage altogether and define an `enum` that you will use with a dispatcher function to select from the list of available functions. If you must use internal functions, those internal functions need to be reassigned during each upgrade. For example, the `messageFunction` variable in the following contract is not upgrade safe. Attempting to call `showMessage()` after an upgrade would likely result in a revert. import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract V1 is Initializable { function() internal pure returns (string memory) messageFunction; function initialize() initializer public { messageFunction = hello; } function hello() internal pure returns (string memory) { return "Hello, World!"; } function showMessage() public view returns (string memory) return messageFunction(); } ... } To allow the above contract to be deployed by the Upgrades Plugins, you can disable the `internal-function-storage` check according to [How can I disable some of the checks?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-disable-some-of-the-checks?) , but ensure you follow the steps below to reassign the internal function during upgrades. In new versions of this contract, assign the internal function in the storage variable again, for example by using a [reinitializer](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-reinitializer-uint64-) : import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "./V1.sol"; contract V2 is V1 { function initializeV2() reinitializer(2) public { messageFunction = hello; } ... } Then when upgrading, call the reinitializer function as part of the upgrade process, for example in Hardhat: await upgrades.upgradeProxy(PROXY_ADDRESS, ContractFactoryV2, call: 'initializeV2', unsafeAllow: ['internal-function-storage'] ); or in Foundry: Upgrades.upgradeProxy( PROXY_ADDRESS, "V2.sol", abi.encodeCall(V2.initializeV2, ()) ); ### On this page [Can I change Solidity compiler versions when upgrading?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-change-solidity-compiler-versions-when-upgrading) [Why am I getting the error "Cannot call fallback function from the proxy admin"?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-am-i-getting-the-error-cannot-call-fallback-function-from-the-proxy-admin) [What does it mean for a contract to be upgrade safe?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-a-contract-to-be-upgrade-safe) [How can I disable some of the checks?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-disable-some-of-the-checks) [Can I safely use `delegatecall` and `selfdestruct`?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-safely-use-delegatecall-and-selfdestruct) [What does it mean for an implementation to be compatible?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-does-it-mean-for-an-implementation-to-be-compatible) [What is a proxy admin?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy-admin) [What is an implementation contract?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-an-implementation-contract) [What is a proxy?](https://docs.openzeppelin.com/upgrades-plugins/faq#what-is-a-proxy) [Why can't I use `immutable` variables?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-immutable-variables) [Why can't I use external libraries?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-external-libraries) [Why do I need a public `upgradeTo` or `upgradeToAndCall` function?](https://docs.openzeppelin.com/upgrades-plugins/faq#why-do-i-need-a-public-upgradeto-or-upgradetoandcall-function) [Can I use custom types like structs and enums?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-use-custom-types-like-structs-and-enums) [How can I rename a variable, or change its type?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-rename-a-variable-or-change-its-type) [How can I use internal functions in storage variables?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-use-internal-functions-in-storage-variables) --- # Developing smart contracts | OpenZeppelin Docs Learn Developing smart contracts ========================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Welcome to the exciting world of smart contract development! This guide will let you get started writing Solidity contracts by going over the following: * [Setting up a Solidity Project](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#setting-up-a-project) * [Compiling Solidity Source Code](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#compiling-solidity) * [Adding More Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#adding-more-contracts) * [Using OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#using-openzeppelin-contracts) [About Solidity](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#about-solidity) -------------------------------------------------------------------------------------------------------------- We won’t cover language concepts such as syntax or keywords in this guide. For that, you’ll want to check out the following curated content, which feature great learning resources for both newcomers and experienced developers: * For a general overview of how Ethereum and smart contracts work, the official website hosts a [Learn about Ethereum](https://ethereum.org/learn/) section with lots of beginner-friendly content. * If you’re new to the language, the [official Solidity documentation](https://solidity.readthedocs.io/en/latest/introduction-to-smart-contracts.html) is a good resource to have handy. Take a look at their [security recommendations](https://solidity.readthedocs.io/en/latest/security-considerations.html) , which nicely go over the differences between blockchains and traditional software platforms. * Consensys' [best practices](https://consensys.github.io/smart-contract-best-practices/) are quite extensive, and include both [proven patterns](https://consensys.github.io/smart-contract-best-practices/development-recommendations/) to learn from and [known pitfalls](https://consensys.github.io/smart-contract-best-practices/attacks/) to avoid. * The [Ethernaut](https://ethernaut.openzeppelin.com/) web-based game will have you look for subtle vulnerabilities in smart contracts as you advance through levels of increasing difficulty. With that out of the way, let’s get started! [Setting up a Project](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#setting-up-a-project) -------------------------------------------------------------------------------------------------------------------------- The first step after [creating a project](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project#creating-a-project) is to install a development tool. The most popular development frameworks for Ethereum are [Hardhat](https://hardhat.org/) and [Foundry](https://github.com/foundry-rs/foundry) . Each has their strengths and it is useful to be comfortable using all of them. In these guides we will show how to develop, test and deploy smart contracts using Hardhat, and we cover its most common use with [ethers.js](https://docs.ethers.io/) . To get started with Hardhat we will install it in our [project directory](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project#creating-a-project) . npm install --save-dev hardhat Once installed, we can run `npx hardhat`. This will create a Hardhat config file (`hardhat.config.js`) in our project directory. npx hardhat # 888 888 888 888 888 # 888 888 888 888 888 # 888 888 888 888 888 # 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 # 888 888 "88b 888P" d88" 888 888 "88b "88b 888 # 888 888 .d888888 888 888 888 888 888 .d888888 888 # 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. # 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 # # 👷 Welcome to Hardhat v2.22.12 👷‍ # # ✔ What do you want to do? · Create an empty hardhat.config.js # Config file created [First contract](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#first-contract) -------------------------------------------------------------------------------------------------------------- We store our Solidity source files (`.sol`) in a `contracts` directory. This is equivalent to the `src` directory you may be familiar with from other languages. We can now write our first simple smart contract, called `Box`: it will let people store a value that can be later retrieved. We will save this file as `contracts/Box.sol`. Each `.sol` file should have the code for a single contract, and be named after it. pragma solidity ^0.8.0; contract Box { uint256 private _value; // Emitted when the stored value changes event ValueChanged(uint256 value); // Stores a new value in the contract function store(uint256 value) public { _value = value; emit ValueChanged(value); } // Reads the last stored value function retrieve() public view returns (uint256) { return _value; } } [Compiling Solidity](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#compiling-solidity) ---------------------------------------------------------------------------------------------------------------------- The Ethereum Virtual Machine (EVM) cannot execute Solidity code directly: we first need to compile it into EVM bytecode. Our `Box.sol` contract uses Solidity 0.8 so we need to first [configure Hardhat to use an appropriate solc version](https://hardhat.org/config/#solidity-configuration) . We specify a Solidity 0.8 solc version in our `hardhat.config.js`. /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = solidity: "0.8.24", ; Compiling can then be achieved by running a single compile command: If you’re unfamiliar with the `npx` command, check out our [Node project setup guide](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project#using-npx) . npx hardhat compile # Compiled 1 Solidity file successfully (evm target: paris). The [`compile`](https://hardhat.org/guides/compile-contracts.html#compiling-your-contracts) built-in task will automatically look for all contracts in the `contracts` directory, and compile them using the Solidity compiler using the configuration in [`hardhat.config.js`](https://hardhat.org/config/#solidity-configuration) . You will notice an `artifacts` directory was created: it holds the compiled artifacts (bytecode and metadata), which are .json files. It’s a good idea to add this directory to your `.gitignore`. [Adding more contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#adding-more-contracts) ---------------------------------------------------------------------------------------------------------------------------- As your project grows, you will begin to create more contracts that interact with each other: each one should be stored in its own `.sol` file. To see how this looks, let’s add a simple access control system to our `Box` contract: we will store an administrator address in a contract called `Auth`, and only let `Box` be used by those accounts that `Auth` allows. Because the compiler will pick up all files in the `contracts` directory and subdirectories, you are free to organize your code as you see fit. Here, we’ll store the `Auth` contract in an `access-control` subdirectory: pragma solidity ^0.8.0; contract Auth { address private _administrator; constructor(address deployer) { // Make the deployer of the contract the administrator _administrator = deployer; } function isAdministrator(address user) public view returns (bool) { return user == _administrator; } } To use this contract from `Box` we use an `import` statement, referring to `Auth` by its relative path: pragma solidity ^0.8.0; import "./access-control/Auth.sol"; contract Box { uint256 private _value; Auth private _auth; event ValueChanged(uint256 value); constructor() { _auth = new Auth(msg.sender); } function store(uint256 value) public { // Require that the caller is registered as an administrator in Auth require(_auth.isAdministrator(msg.sender), "Unauthorized"); _value = value; emit ValueChanged(value); } function retrieve() public view returns (uint256) { return _value; } } Separating concerns across multiple contracts is a great way to keep each one simple, and is generally a good practice. However, this is not the only way to split your code into modules. You can also use _inheritance_ for encapsulation and code reuse in Solidity, as we’ll see next. [Using OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#using-openzeppelin-contracts) ------------------------------------------------------------------------------------------------------------------------------------------ Reusable modules and libraries are the cornerstone of great software. [**OpenZeppelin Contracts**](https://docs.openzeppelin.com/contracts) contains lots of useful building blocks for smart contracts to build on. And you can rest easy when building on them: they’ve been the subject of multiple audits, with their security and correctness battle-tested. ### [About inheritance](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#about-inheritance) Many of the contracts in the library are not standalone, that is, you’re not expected to deploy them as-is. Instead, you will use them as a starting point to build your own contracts by adding features to them. Solidity provides _multiple inheritance_ as a mechanism to achieve this: take a look at the [Solidity documentation](https://solidity.readthedocs.io/en/latest/contracts.html#inheritance) for more details. For example, the [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable) contract marks the deployer account as the contract’s owner, and provides a modifier called `onlyOwner`. When applied to a function, `onlyOwner` will cause all function calls that do not originate from the owner account to revert. Functions to [transfer](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-transferOwnership-address-) and [renounce](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-renounceOwnership--) ownership are also available. When used this way, inheritance becomes a powerful mechanism that allows for modularization, without forcing you to deploy and manage multiple contracts. ### [Importing OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#importing-openzeppelin-contracts) The latest published release of the OpenZeppelin Contracts library can be downloaded by running: npm install @openzeppelin/contracts You should always use the library from these published releases: copy-pasting library source code into your project is a dangerous practice that makes it very easy to introduce security vulnerabilities in your contracts. To use one of the OpenZeppelin Contracts, `import` it by prefixing its path with `@openzeppelin/contracts`. For example, in order to replace our own [`Auth`](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#auth-contract) contract, we will import `@openzeppelin/contracts/access/Ownable.sol` to add access control to `Box`: pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; contract Box is Ownable { uint256 private _value; event ValueChanged(uint256 value); constructor() Ownable(msg.sender) {} // The onlyOwner modifier restricts who can call the store function function store(uint256 value) public onlyOwner { _value = value; emit ValueChanged(value); } function retrieve() public view returns (uint256) { return _value; } } The [OpenZeppelin Contracts documentation](https://docs.openzeppelin.com/contracts) is a great place to learn about developing secure smart contract systems. It features both guides and a detailed API reference: see for example the [Access Control](https://docs.openzeppelin.com/contracts/5.x/access-control) guide to know more about the `Ownable` contract used in the code sample above. [Next steps](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#next-steps) ------------------------------------------------------------------------------------------------------ Writing and compiling Solidity contracts are but the first steps in the journey to having your decentralized application running on the Ethereum network. Once you are comfortable with this setup, you’ll want to move on to more advanced tasks: * [Deploying and Interacting](https://docs.openzeppelin.com/contracts/5.x/learn/deploying-and-interacting) * [Writing Automated Tests](https://docs.openzeppelin.com/contracts/5.x/learn/writing-automated-tests) * [Connecting to Public Test Networks](https://docs.openzeppelin.com/contracts/5.x/learn/connecting-to-public-test-networks) [Setting up a Node project\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/learn/setting-up-a-node-project) [Deploying and interacting\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/learn/deploying-and-interacting) ### On this page [About Solidity](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#about-solidity) [Setting up a Project](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#setting-up-a-project) [First contract](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#first-contract) [Compiling Solidity](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#compiling-solidity) [Adding more contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#adding-more-contracts) [Using OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#using-openzeppelin-contracts) [About inheritance](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#about-inheritance) [Importing OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#importing-openzeppelin-contracts) [Next steps](https://docs.openzeppelin.com/contracts/5.x/learn/developing-smart-contracts#next-steps) --- # Plugins | OpenZeppelin Docs Relayer Plugins ======= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/relayer/plugins#overview) ------------------------------------------------------------------- OpenZeppelin Relayer supports plugins to extend the functionality of the relayer. Plugins are `TypeScript` functions running in the Relayer server that can include any arbitrary logic defined by the Relayer operator. The plugin system features: * _**Handler Pattern**_: Simple export-based plugin development * _**TypeScript Support**_: Full type safety and IntelliSense * _**Plugin API**_: Clean interface for interacting with relayers * _**Docker Integration**_: Seamless development and deployment * _**Comprehensive Error Handling**_: Detailed logging and debugging capabilities [Configuration](https://docs.openzeppelin.com/relayer/plugins#configuration) ----------------------------------------------------------------------------- ### [Writing a Plugin](https://docs.openzeppelin.com/relayer/plugins#writing-a-plugin) Plugins are declared under `plugins` directory, and are expected to be TypeScript files (`.ts` extension). openzeppelin-relayer/ ├── plugins/ │ └── my-plugin.ts # Plugin code └── config/ └── config.json # Plugins in configuration file #### [Handler Pattern (Recommended)](https://docs.openzeppelin.com/relayer/plugins#handler-pattern-recommended) This approach uses a simple `handler` export pattern: /// Required imports. import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; /// Define your plugin parameters interface type MyPluginParams = { destinationAddress: string; amount?: number; message?: string; relayerId?: string; }; /// Define your plugin return type type MyPluginResult = { success: boolean; transactionId: string; message: string; }; /// Export a handler function - that's it! export async function handler(api: PluginAPI, params: MyPluginParams): Promise { console.info("🚀 Plugin started..."); // Validate parameters if (!params.destinationAddress) { throw new Error("destinationAddress is required"); } // Use the relayer API const relayer = api.useRelayer(params.relayerId || "my-relayer"); const result = await relayer.sendTransaction({ to: params.destinationAddress, value: params.amount || 1, data: "0x", gas_limit: 21000, speed: Speed.FAST, }); console.info(`Transaction submitted: ${result.id}`); // Wait for confirmation await result.wait({ interval: 5000, // Check every 5 seconds timeout: 120000 // Timeout after 2 minutes }); return { success: true, transactionId: result.id, message: `Successfully sent ${params.amount || 1} wei to ${params.destinationAddress}` }; } #### [Legacy Pattern (Deprecated, but supported)](https://docs.openzeppelin.com/relayer/plugins#legacy-pattern-deprecated-but-supported) The `runPlugin()` pattern is deprecated and will be removed in a future version. Please migrate to the handler export pattern above. Legacy plugins will continue to work but will show deprecation warnings. import { runPlugin, PluginAPI } from "./lib/plugin"; async function myPlugin(api: PluginAPI, params: any) { // Plugin logic here return "result"; } runPlugin(myPlugin); // ⚠️ Deprecated - shows warning but still works _**Example legacy plugin**_ (`plugins/examples/example-deprecated.ts`): import { PluginAPI, runPlugin } from "../lib/plugin"; import { Speed } from "@openzeppelin/relayer-sdk"; type Params = { destinationAddress: string; }; async function example(api: PluginAPI, params: Params): Promise { console.info("Plugin started..."); const relayer = api.useRelayer("sepolia-example"); const result = await relayer.sendTransaction({ to: params.destinationAddress, value: 1, data: "0x", gas_limit: 21000, speed: Speed.FAST, }); await result.wait(); return "done!"; } runPlugin(example); ### [Declaring in config file](https://docs.openzeppelin.com/relayer/plugins#declaring-in-config-file) Plugins are configured in the `./config/config.json` file, under the `plugins` key. The file contains a list of plugins, each with an id, path and timeout in seconds (optional). The plugin path is relative to the `/plugins` directory Example: { "plugins": [\ {\ "id": "my-plugin",\ "path": "my-plugin.ts",\ "timeout": 30\ }\ ] } ### [Timeout](https://docs.openzeppelin.com/relayer/plugins#timeout) The timeout is the maximum time **in seconds** that the plugin can run. If the plugin exceeds the timeout, it will be terminated with an error. The timeout is optional, and if not provided, the default is 300 seconds (5 minutes). [Plugin Development Guidelines](https://docs.openzeppelin.com/relayer/plugins#plugin-development-guidelines) ------------------------------------------------------------------------------------------------------------- ### [TypeScript Best Practices](https://docs.openzeppelin.com/relayer/plugins#typescript-best-practices) * _**Define Parameter Types**_: Always create interfaces or types for your plugin parameters * _**Define Return Types**_: Specify what your plugin returns for better developer experience * _**Handle Errors Gracefully**_: Use try-catch blocks and return structured error responses * _**Validate Input**_: Check required parameters and provide meaningful error messages * _**Use Async/Await**_: Modern async patterns for better readability ### [Testing Your Plugin](https://docs.openzeppelin.com/relayer/plugins#testing-your-plugin) You can test your handler function directly: import { handler } from './my-plugin'; // Mock API for testing (in real scenarios, use proper mocking) const mockApi = { useRelayer: (id: string) => ({ sendTransaction: async (tx: any) => ({ id: "test-tx-123", wait: async () => {} }) }) } as any; const result = await handler(mockApi, { destinationAddress: "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", amount: 1000 }); console.log(result); [Invocation](https://docs.openzeppelin.com/relayer/plugins#invocation) ----------------------------------------------------------------------- Plugins are invoked by hitting the `api/v1/plugins/plugin-id/call` endpoint. The endpoint accepts a `POST` request. Example post request body: { "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", "amount": 1000000000000000, "message": "Hello from OpenZeppelin Relayer!" } The parameters are passed directly to your plugin's `handler` function. [Debugging](https://docs.openzeppelin.com/relayer/plugins#debugging) --------------------------------------------------------------------- When invoking a plugin, the response will include: * `logs`: The logs from the plugin execution. * `return_value`: The returned value of the plugin execution. * `error`: An error message if the plugin execution failed. * `traces`: A list of messages sent between the plugin and the Relayer instance. This includes all the payloads passed through the `PluginAPI` object. ### [Complete Example](https://docs.openzeppelin.com/relayer/plugins#complete-example) 1. _**Plugin Code**_ (`plugins/example.ts`): import { Speed, PluginAPI } from "@openzeppelin/relayer-sdk"; type ExampleParams = { destinationAddress: string; amount?: number; message?: string; }; type ExampleResult = { success: boolean; transactionId: string; transactionHash: string | null; message: string; timestamp: string; }; export async function handler(api: PluginAPI, params: ExampleParams): Promise { console.info("🚀 Example plugin started"); console.info(`📋 Parameters:`, JSON.stringify(params, null, 2)); try { // Validate parameters if (!params.destinationAddress) { throw new Error("destinationAddress is required"); } const amount = params.amount || 1; const message = params.message || "Hello from OpenZeppelin Relayer!"; console.info(`💰 Sending ${amount} wei to ${params.destinationAddress}`); // Get relayer and send transaction const relayer = api.useRelayer("my-relayer"); const result = await relayer.sendTransaction({ to: params.destinationAddress, value: amount, data: "0x", gas_limit: 21000, speed: Speed.FAST, }); console.info(`✅ Transaction submitted: ${result.id}`); // Wait for confirmation const confirmation = await result.wait({ interval: 5000, timeout: 120000 }); console.info(`🎉 Transaction confirmed: ${confirmation.hash}`); return { success: true, transactionId: result.id, transactionHash: confirmation.hash || null, message: `Successfully sent ${amount} wei to ${params.destinationAddress}. ${message}`, timestamp: new Date().toISOString() }; } catch (error) { console.error("❌ Plugin execution failed:", error); return { success: false, transactionId: "", transactionHash: null, message: `Plugin failed: ${(error as Error).message}`, timestamp: new Date().toISOString() }; } } 1. _**Plugin Configuration**_ (`config/config.json`): { "plugins": [\ {\ "id": "example-plugin",\ "path": "example-plugin.ts",\ "timeout": 30\ }\ ] } 1. _**API Invocation**_: curl -X POST http://localhost:8080/api/v1/plugins/example-plugin/call \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "destinationAddress": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A", "amount": 1000000000000000, "message": "Test transaction from plugin" }' 1. _**API Response**_: { "success": true, "message": "Plugin called successfully", "logs": [\ {\ "level": "info",\ "message": "🚀 Example plugin started"\ },\ {\ "level": "info",\ "message": "💰 Sending 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A"\ },\ {\ "level": "info",\ "message": "✅ Transaction submitted: tx-123456"\ },\ {\ "level": "info",\ "message": "🎉 Transaction confirmed: 0xabc123..."\ }\ ], "return_value": { "success": true, "transactionId": "tx-123456", "transactionHash": "0xabc123def456...", "message": "Successfully sent 1000000000000000 wei to 0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A. Test transaction from plugin", "timestamp": "2024-01-15T10:30:00.000Z" }, "error": "", "traces": [\ {\ "relayer_id": "my-relayer",\ "method": "sendTransaction",\ "payload": {\ "to": "0x742d35Cc6640C21a1c7656d2c9C8F6bF5e7c3F8A",\ "value": "1000000000000000",\ "data": "0x",\ "gas_limit": 21000,\ "speed": "fast"\ }\ }\ ] } [Response Fields](https://docs.openzeppelin.com/relayer/plugins#response-fields) --------------------------------------------------------------------------------- * _**`logs`**_: Terminal output from the plugin (console.log, console.error, etc.) * _**`return_value`**_: The value returned by your plugin's handler function * _**`error`**_: Error message if the plugin execution failed * _**`traces`**_: Messages exchanged between the plugin and the Relayer instance via PluginAPI [Migration from Legacy Pattern](https://docs.openzeppelin.com/relayer/plugins#migration-from-legacy-pattern) ------------------------------------------------------------------------------------------------------------- ### [Current Status](https://docs.openzeppelin.com/relayer/plugins#current-status) * ✅ _**Legacy plugins still work**_ - No immediate action required * ⚠️ _**Deprecation warnings**_ - Legacy plugins will show console warnings * 📅 _**Future removal**_ - The `runPlugin` pattern will be removed in a future major version * 🎯 _**Recommended action**_ - Migrate to handler pattern for new plugins ### [Migration Steps](https://docs.openzeppelin.com/relayer/plugins#migration-steps) If you have existing plugins using `runPlugin()`, migration is simple: _**Before (Legacy - still works)**_: import { runPlugin, PluginAPI } from "./lib/plugin"; async function myPlugin(api: PluginAPI, params: any): Promise { // Your plugin logic return result; } runPlugin(myPlugin); // ⚠️ Shows deprecation warning _**After (Modern - recommended)**_: import { PluginAPI } from "@openzeppelin/relayer-sdk"; export async function handler(api: PluginAPI, params: any): Promise { // Same plugin logic - just export as handler! return result; } ### [Step-by-Step Migration](https://docs.openzeppelin.com/relayer/plugins#step-by-step-migration) 1. _**Remove the `runPlugin()` call**_ at the bottom of your file 2. _**Rename your function to `handler`**_ (or create a new handler export) 3. _**Export the `handler` function**_ using `export async function handler` 4. _**Add proper TypeScript types**_ for better development experience 5. _**Test your plugin**_ to ensure it works with the new pattern 6. _**Update your documentation**_ to reflect the new pattern ### [Backwards Compatibility](https://docs.openzeppelin.com/relayer/plugins#backwards-compatibility) The relayer will automatically detect which pattern your plugin uses: * If it finds a `handler` export → uses modern pattern * If no `handler` but `runPlugin()` was called → uses legacy pattern with warning * If neither → shows clear error message This ensures a smooth transition period where both patterns work simultaneously. [Project Roadmap\ \ Previous Page](https://docs.openzeppelin.com/relayer/roadmap) [Changelog\ \ Next Page](https://docs.openzeppelin.com/relayer/changelog) ### On this page [Overview](https://docs.openzeppelin.com/relayer/plugins#overview) [Configuration](https://docs.openzeppelin.com/relayer/plugins#configuration) [Writing a Plugin](https://docs.openzeppelin.com/relayer/plugins#writing-a-plugin) [Handler Pattern (Recommended)](https://docs.openzeppelin.com/relayer/plugins#handler-pattern-recommended) [Legacy Pattern (Deprecated, but supported)](https://docs.openzeppelin.com/relayer/plugins#legacy-pattern-deprecated-but-supported) [Declaring in config file](https://docs.openzeppelin.com/relayer/plugins#declaring-in-config-file) [Timeout](https://docs.openzeppelin.com/relayer/plugins#timeout) [Plugin Development Guidelines](https://docs.openzeppelin.com/relayer/plugins#plugin-development-guidelines) [TypeScript Best Practices](https://docs.openzeppelin.com/relayer/plugins#typescript-best-practices) [Testing Your Plugin](https://docs.openzeppelin.com/relayer/plugins#testing-your-plugin) [Invocation](https://docs.openzeppelin.com/relayer/plugins#invocation) [Debugging](https://docs.openzeppelin.com/relayer/plugins#debugging) [Complete Example](https://docs.openzeppelin.com/relayer/plugins#complete-example) [Response Fields](https://docs.openzeppelin.com/relayer/plugins#response-fields) [Migration from Legacy Pattern](https://docs.openzeppelin.com/relayer/plugins#migration-from-legacy-pattern) [Current Status](https://docs.openzeppelin.com/relayer/plugins#current-status) [Migration Steps](https://docs.openzeppelin.com/relayer/plugins#migration-steps) [Step-by-Step Migration](https://docs.openzeppelin.com/relayer/plugins#step-by-step-migration) [Backwards Compatibility](https://docs.openzeppelin.com/relayer/plugins#backwards-compatibility) --- # Relayer API Reference | OpenZeppelin Docs Relayer Relayer API Reference ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Relayers](https://docs.openzeppelin.com/relayer/api#relayers) --------------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#list-relayers) [List Relayers](https://docs.openzeppelin.com/relayer/api/listRelayers) Lists all relayers with pagination support ### [](https://docs.openzeppelin.com/relayer/api#create-relayer) [Create Relayer](https://docs.openzeppelin.com/relayer/api/createRelayer) Creates a new relayer ### [](https://docs.openzeppelin.com/relayer/api#get-relayer) [Get Relayer](https://docs.openzeppelin.com/relayer/api/getRelayer) Retrieves details of a specific relayer by ID ### [](https://docs.openzeppelin.com/relayer/api#delete-relayer) [Delete Relayer](https://docs.openzeppelin.com/relayer/api/deleteRelayer) Deletes a relayer by ID ### [](https://docs.openzeppelin.com/relayer/api#update-relayer) [Update Relayer](https://docs.openzeppelin.com/relayer/api/updateRelayer) Updates a relayer's information ### [](https://docs.openzeppelin.com/relayer/api#get-relayer-balance) [Get Relayer Balance](https://docs.openzeppelin.com/relayer/api/getRelayerBalance) Retrieves the balance of a specific relayer ### [](https://docs.openzeppelin.com/relayer/api#rpc) [RPC](https://docs.openzeppelin.com/relayer/api/rpc) Performs a JSON-RPC call using the specified relayer ### [](https://docs.openzeppelin.com/relayer/api#sign) [Sign](https://docs.openzeppelin.com/relayer/api/sign) Signs data using the specified relayer ### [](https://docs.openzeppelin.com/relayer/api#sign-transaction) [Sign Transaction](https://docs.openzeppelin.com/relayer/api/signTransaction) Signs a transaction using the specified relayer (Stellar only) ### [](https://docs.openzeppelin.com/relayer/api#sign-typed-data) [Sign Typed Data](https://docs.openzeppelin.com/relayer/api/signTypedData) Signs typed data using the specified relayer ### [](https://docs.openzeppelin.com/relayer/api#get-relayer-status) [Get Relayer Status](https://docs.openzeppelin.com/relayer/api/getRelayerStatus) Fetches the current status of a specific relayer ### [](https://docs.openzeppelin.com/relayer/api#send-transaction) [Send Transaction](https://docs.openzeppelin.com/relayer/api/sendTransaction) Sends a transaction through the specified relayer ### [](https://docs.openzeppelin.com/relayer/api#list-transactions) [List Transactions](https://docs.openzeppelin.com/relayer/api/listTransactions) Lists all transactions for a specific relayer with pagination ### [](https://docs.openzeppelin.com/relayer/api#get-transaction-by-nonce) [Get Transaction by Nonce](https://docs.openzeppelin.com/relayer/api/getTransactionByNonce) Retrieves a transaction by its nonce value ### [](https://docs.openzeppelin.com/relayer/api#delete-pending-transactions) [Delete Pending Transactions](https://docs.openzeppelin.com/relayer/api/deletePendingTransactions) Deletes all pending transactions for a specific relayer ### [](https://docs.openzeppelin.com/relayer/api#get-transaction-by-id) [Get Transaction by ID](https://docs.openzeppelin.com/relayer/api/getTransactionById) Retrieves a specific transaction by its ID ### [](https://docs.openzeppelin.com/relayer/api#replace-transaction) [Replace Transaction](https://docs.openzeppelin.com/relayer/api/replaceTransaction) Replaces a specific transaction with a new one ### [](https://docs.openzeppelin.com/relayer/api#cancel-transaction) [Cancel Transaction](https://docs.openzeppelin.com/relayer/api/cancelTransaction) Cancels a specific transaction by its ID [Plugins](https://docs.openzeppelin.com/relayer/api#plugins) ------------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#call-plugin) [Call Plugin](https://docs.openzeppelin.com/relayer/api/callPlugin) Calls a plugin method [Notifications](https://docs.openzeppelin.com/relayer/api#notifications) ------------------------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#list-notifications) [List Notifications](https://docs.openzeppelin.com/relayer/api/listNotifications) Lists all notifications with pagination support ### [](https://docs.openzeppelin.com/relayer/api#create-notification) [Create Notification](https://docs.openzeppelin.com/relayer/api/createNotification) Creates a new notification ### [](https://docs.openzeppelin.com/relayer/api#get-notification) [Get Notification](https://docs.openzeppelin.com/relayer/api/getNotification) Retrieves details of a specific notification by ID ### [](https://docs.openzeppelin.com/relayer/api#delete-notification) [Delete Notification](https://docs.openzeppelin.com/relayer/api/deleteNotification) Deletes a notification by ID ### [](https://docs.openzeppelin.com/relayer/api#update-notification) [Update Notification](https://docs.openzeppelin.com/relayer/api/updateNotification) Updates an existing notification [Signers](https://docs.openzeppelin.com/relayer/api#signers) ------------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#list-signers) [List Signers](https://docs.openzeppelin.com/relayer/api/listSigners) Lists all signers with pagination support ### [](https://docs.openzeppelin.com/relayer/api#create-signer) [Create Signer](https://docs.openzeppelin.com/relayer/api/createSigner) Creates a new signer ### [](https://docs.openzeppelin.com/relayer/api#get-signer) [Get Signer](https://docs.openzeppelin.com/relayer/api/getSigner) Retrieves details of a specific signer by ID ### [](https://docs.openzeppelin.com/relayer/api#delete-signer) [Delete Signer](https://docs.openzeppelin.com/relayer/api/deleteSigner) Deletes a signer by ID ### [](https://docs.openzeppelin.com/relayer/api#update-signer) [Update Signer](https://docs.openzeppelin.com/relayer/api/updateSigner) Updates an existing signer [Metrics](https://docs.openzeppelin.com/relayer/api#metrics) ------------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#scrape-metrics) [Scrape Metrics](https://docs.openzeppelin.com/relayer/api/scrape_metrics) Triggers an update of system metrics and returns the result in plain text format ### [](https://docs.openzeppelin.com/relayer/api#list-metrics) [List Metrics](https://docs.openzeppelin.com/relayer/api/list_metrics) Returns a list of all available metric names in JSON format ### [](https://docs.openzeppelin.com/relayer/api#metric-detail) [Metric Detail](https://docs.openzeppelin.com/relayer/api/metric_detail) Returns the details of a specific metric in plain text format [Health](https://docs.openzeppelin.com/relayer/api#health) ----------------------------------------------------------- ### [](https://docs.openzeppelin.com/relayer/api#health-1) [Health](https://docs.openzeppelin.com/relayer/api/health) Health routes implementation [Solana Integration\ \ Previous Page](https://docs.openzeppelin.com/relayer/solana) [List Relayers\ \ Next Page](https://docs.openzeppelin.com/relayer/api/listRelayers) ### On this page [Relayers](https://docs.openzeppelin.com/relayer/api#relayers) [](https://docs.openzeppelin.com/relayer/api#list-relayers) [List Relayers](https://docs.openzeppelin.com/relayer/api/listRelayers) [](https://docs.openzeppelin.com/relayer/api#create-relayer) [Create Relayer](https://docs.openzeppelin.com/relayer/api/createRelayer) [](https://docs.openzeppelin.com/relayer/api#get-relayer) [Get Relayer](https://docs.openzeppelin.com/relayer/api/getRelayer) [](https://docs.openzeppelin.com/relayer/api#delete-relayer) [Delete Relayer](https://docs.openzeppelin.com/relayer/api/deleteRelayer) [](https://docs.openzeppelin.com/relayer/api#update-relayer) [Update Relayer](https://docs.openzeppelin.com/relayer/api/updateRelayer) [](https://docs.openzeppelin.com/relayer/api#get-relayer-balance) [Get Relayer Balance](https://docs.openzeppelin.com/relayer/api/getRelayerBalance) [](https://docs.openzeppelin.com/relayer/api#rpc) [RPC](https://docs.openzeppelin.com/relayer/api/rpc) [](https://docs.openzeppelin.com/relayer/api#sign) [Sign](https://docs.openzeppelin.com/relayer/api/sign) [](https://docs.openzeppelin.com/relayer/api#sign-transaction) [Sign Transaction](https://docs.openzeppelin.com/relayer/api/signTransaction) [](https://docs.openzeppelin.com/relayer/api#sign-typed-data) [Sign Typed Data](https://docs.openzeppelin.com/relayer/api/signTypedData) [](https://docs.openzeppelin.com/relayer/api#get-relayer-status) [Get Relayer Status](https://docs.openzeppelin.com/relayer/api/getRelayerStatus) [](https://docs.openzeppelin.com/relayer/api#send-transaction) [Send Transaction](https://docs.openzeppelin.com/relayer/api/sendTransaction) [](https://docs.openzeppelin.com/relayer/api#list-transactions) [List Transactions](https://docs.openzeppelin.com/relayer/api/listTransactions) [](https://docs.openzeppelin.com/relayer/api#get-transaction-by-nonce) [Get Transaction by Nonce](https://docs.openzeppelin.com/relayer/api/getTransactionByNonce) [](https://docs.openzeppelin.com/relayer/api#delete-pending-transactions) [Delete Pending Transactions](https://docs.openzeppelin.com/relayer/api/deletePendingTransactions) [](https://docs.openzeppelin.com/relayer/api#get-transaction-by-id) [Get Transaction by ID](https://docs.openzeppelin.com/relayer/api/getTransactionById) [](https://docs.openzeppelin.com/relayer/api#replace-transaction) [Replace Transaction](https://docs.openzeppelin.com/relayer/api/replaceTransaction) [](https://docs.openzeppelin.com/relayer/api#cancel-transaction) [Cancel Transaction](https://docs.openzeppelin.com/relayer/api/cancelTransaction) [Plugins](https://docs.openzeppelin.com/relayer/api#plugins) [](https://docs.openzeppelin.com/relayer/api#call-plugin) [Call Plugin](https://docs.openzeppelin.com/relayer/api/callPlugin) [Notifications](https://docs.openzeppelin.com/relayer/api#notifications) [](https://docs.openzeppelin.com/relayer/api#list-notifications) [List Notifications](https://docs.openzeppelin.com/relayer/api/listNotifications) [](https://docs.openzeppelin.com/relayer/api#create-notification) [Create Notification](https://docs.openzeppelin.com/relayer/api/createNotification) [](https://docs.openzeppelin.com/relayer/api#get-notification) [Get Notification](https://docs.openzeppelin.com/relayer/api/getNotification) [](https://docs.openzeppelin.com/relayer/api#delete-notification) [Delete Notification](https://docs.openzeppelin.com/relayer/api/deleteNotification) [](https://docs.openzeppelin.com/relayer/api#update-notification) [Update Notification](https://docs.openzeppelin.com/relayer/api/updateNotification) [Signers](https://docs.openzeppelin.com/relayer/api#signers) [](https://docs.openzeppelin.com/relayer/api#list-signers) [List Signers](https://docs.openzeppelin.com/relayer/api/listSigners) [](https://docs.openzeppelin.com/relayer/api#create-signer) [Create Signer](https://docs.openzeppelin.com/relayer/api/createSigner) [](https://docs.openzeppelin.com/relayer/api#get-signer) [Get Signer](https://docs.openzeppelin.com/relayer/api/getSigner) [](https://docs.openzeppelin.com/relayer/api#delete-signer) [Delete Signer](https://docs.openzeppelin.com/relayer/api/deleteSigner) [](https://docs.openzeppelin.com/relayer/api#update-signer) [Update Signer](https://docs.openzeppelin.com/relayer/api/updateSigner) [Metrics](https://docs.openzeppelin.com/relayer/api#metrics) [](https://docs.openzeppelin.com/relayer/api#scrape-metrics) [Scrape Metrics](https://docs.openzeppelin.com/relayer/api/scrape_metrics) [](https://docs.openzeppelin.com/relayer/api#list-metrics) [List Metrics](https://docs.openzeppelin.com/relayer/api/list_metrics) [](https://docs.openzeppelin.com/relayer/api#metric-detail) [Metric Detail](https://docs.openzeppelin.com/relayer/api/metric_detail) [Health](https://docs.openzeppelin.com/relayer/api#health) [](https://docs.openzeppelin.com/relayer/api#health-1) [Health](https://docs.openzeppelin.com/relayer/api/health) --- # Writing Upgradeable Contracts | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) Writing Upgradeable Contracts ============================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) When working with upgradeable contracts using OpenZeppelin Upgrades, there are a few minor caveats to keep in mind when writing your Solidity code. It’s worth mentioning that these restrictions have their roots in how the Ethereum VM works, and apply to all projects that work with upgradeable contracts, not just OpenZeppelin Upgrades. [Initializers](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializers) ------------------------------------------------------------------------------------------------ You can use your Solidity contracts with OpenZeppelin Upgrades without any modifications, except for their _constructors_. Due to a requirement of the proxy-based upgradeability system, no constructors can be used in upgradeable contracts. To learn about the reasons behind this restriction, head to [Proxies](https://docs.openzeppelin.com/upgrades-plugins/proxies#the-constructor-caveat) . This means that, when using a contract with the OpenZeppelin Upgrades, you need to change its constructor into a regular function, typically named `initialize`, where you run all the setup logic: // NOTE: Do not use this code snippet, it's incomplete and has a critical vulnerability! pragma solidity ^0.6.0; contract MyContract { uint256 public x; function initialize(uint256 _x) public { x = _x; } } However, while Solidity ensures that a `constructor` is called only once in the lifetime of a contract, a regular function can be called many times. To prevent a contract from being _initialized_ multiple times, you need to add a check to ensure the `initialize` function is called only once: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract MyContract { uint256 public x; bool private initialized; function initialize(uint256 _x) public { require(!initialized, "Contract instance has already been initialized"); initialized = true; x = _x; } } Since this pattern is very common when writing upgradeable contracts, OpenZeppelin Contracts provides an `Initializable` base contract that has an `initializer` modifier that takes care of this: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract MyContract is Initializable { uint256 public x; function initialize(uint256 _x) public initializer { x = _x; } } Another difference between a `constructor` and a regular function is that Solidity takes care of automatically invoking the constructors of all ancestors of a contract. When writing an initializer, you need to take special care to manually call the initializers of all parent contracts. Note that the `initializer` modifier can only be called once even when using inheritance, so parent contracts should use the `onlyInitializing` modifier: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract BaseContract is Initializable { uint256 public y; function initialize() public onlyInitializing { y = 42; } } contract MyContract is BaseContract { uint256 public x; function initialize(uint256 _x) public initializer { BaseContract.initialize(); // Do not forget this call! x = _x; } } ### [Using Upgradeable Smart Contract Libraries](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#using-upgradeable-smart-contract-libraries) Keep in mind that this restriction affects not only your contracts, but also the contracts you import from a library. Consider for example [`ERC20`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.3/contracts/token/ERC20/ERC20.sol) from OpenZeppelin Contracts: the contract initializes the token's name and symbol in its constructor. // @openzeppelin/contracts/token/ERC20/ERC20.sol pragma solidity ^0.8.0; ... contract ERC20 is Context, IERC20 { ... string private _name; string private _symbol; constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } ... } This means you should not be using these contracts in your OpenZeppelin Upgrades project. Instead, make sure to use `@openzeppelin/contracts-upgradeable`, which is an official fork of OpenZeppelin Contracts that has been modified to use initializers instead of constructors. Take a look at what [ERC20Upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.7.3/contracts/token/ERC20/ERC20Upgradeable.sol) looks like in `@openzeppelin/contracts-upgradeable`: // @openzeppelin/contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol pragma solidity ^0.8.0; ... contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable { ... string private _name; string private _symbol; function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } ... } Whether using OpenZeppelin Contracts or another smart contract library, always make sure that the package is set up to handle upgradeable contracts. Learn more about OpenZeppelin Contracts Upgradeable in [Contracts: Using with Upgrades](https://docs.openzeppelin.com/contracts/5.x/upgradeable) . ### [Avoiding Initial Values in Field Declarations](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#avoiding-initial-values-in-field-declarations) Solidity allows defining initial values for fields when declaring them in a contract. contract MyContract { uint256 public hasInitialValue = 42; // equivalent to setting in the constructor } This is equivalent to setting these values in the constructor, and as such, will not work for upgradeable contracts. Make sure that all initial values are set in an initializer function as shown below; otherwise, any upgradeable instances will not have these fields set. contract MyContract is Initializable { uint256 public hasInitialValue; function initialize() public initializer { hasInitialValue = 42; // set initial value in initializer } } It is still ok to define _constant_ state variables, because the compiler [does not reserve a storage slot for these variables](https://solidity.readthedocs.io/en/latest/contracts.html#constant-state-variables) , and every occurrence is replaced by the respective constant expression. So the following still works with OpenZeppelin Upgrades: contract MyContract { uint256 public constant hasInitialValue = 42; // define as constant } ### [Initializing the Implementation Contract](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializing-the-implementation-contract) Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being used, you should invoke the `_disableInitializers` function in the constructor to automatically lock it when it is deployed: /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } ### [Validating Initializers](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#validating-initializers) The OpenZeppelin Upgrades plugins will automatically detect specific issues with initializers in implementation contracts. These include checking if your implementation contract is missing an initializer when there are parent initializers that need to be called, if a parent initializer is not called, or if a parent initializer is called more than once. The plugins will also warn if parent initializers are not called in linearized order. Reinitializers are not included in validations by default, because the Upgrades plugins cannot determine whether they are intended to be used for new deployments. If you want to validate a reinitializer function as an initializer that can be used for new deployments, annotate it with `@custom:oz-upgrades-validate-as-initializer`. Note that functions which cannot possibly be initializers are always ignored, such as private functions which cannot be called externally or by child contracts. [Creating New Instances From Your Contract Code](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#creating-new-instances-from-your-contract-code) -------------------------------------------------------------------------------------------------------------------------------------------------------------------- When creating a new instance of a contract from your contract's code, these creations are handled directly by Solidity and not by OpenZeppelin Upgrades, which means that **these contracts will not be upgradeable**. For instance, in the following example, even if `MyContract` is deployed as upgradeable, the `token` contract created is not: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyContract is Initializable { ERC20 public token; function initialize() public initializer { token = new ERC20("Test", "TST"); // This contract will not be upgradeable } } If you would like the `ERC20` instance to be upgradeable, the easiest way to achieve that is to simply accept an instance of that contract as a parameter, and inject it after creating it: // contracts/MyContract.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; contract MyContract is Initializable { IERC20Upgradeable public token; function initialize(IERC20Upgradeable _token) public initializer { token = _token; } } [Potentially Unsafe Operations](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#potentially-unsafe-operations) ---------------------------------------------------------------------------------------------------------------------------------- When working with upgradeable smart contracts, you will always interact with the contract instance, and never with the underlying logic contract. However, nothing prevents a malicious actor from sending transactions to the logic contract directly. This does not pose a threat, since any changes to the state of the logic contracts do not affect your contract instances, as the storage of the logic contracts is never used in your project. There is, however, an exception. If the direct call to the logic contract triggers a `selfdestruct` operation, then the logic contract will be destroyed, and all your contract instances will end up delegating all calls to an address without any code. This would effectively break all contract instances in your project. A similar effect can be achieved if the logic contract contains a `delegatecall` operation. If the contract can be made to `delegatecall` into a malicious contract that contains a `selfdestruct`, then the calling contract will be destroyed. As such, it is not allowed to use either `selfdestruct` or `delegatecall` in your contracts. [Modifying Your Contracts](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts) ------------------------------------------------------------------------------------------------------------------------ When writing new versions of your contracts, either due to new features or bug fixing, there is an additional restriction to observe: you cannot change the order in which the contract state variables are declared, nor their type. You can read more about the reasons behind this restriction by learning about our [Proxies](https://docs.openzeppelin.com/upgrades-plugins/proxies) . Violating any of these storage layout restrictions will cause the upgraded version of the contract to have its storage values mixed up, and can lead to critical errors in your application. This means that if you have an initial contract that looks like this: contract MyContract { uint256 private x; string private y; } Then you cannot change the type of a variable: contract MyContract { string private x; string private y; } Or change the order in which they are declared: contract MyContract { string private y; uint256 private x; } Or introduce a new variable before existing ones: contract MyContract { bytes private a; uint256 private x; string private y; } Or remove an existing variable: contract MyContract { string private y; } If you need to introduce a new variable, make sure you always do so at the end: contract MyContract { uint256 private x; string private y; bytes private z; } Keep in mind that if you rename a variable, then it will keep the same value as before after upgrading. This may be the desired behavior if the new variable is semantically the same as the old one: contract MyContract { uint256 private x; string private z; // starts with the value from `y` } And if you remove a variable from the end of the contract, note that the storage will not be cleared. A subsequent update that adds a new variable will cause that variable to read the leftover value from the deleted one. contract MyContract { uint256 private x; } Then upgraded to: contract MyContract { uint256 private x; string private z; // starts with the value from `y` } Note that you may also be inadvertently changing the storage variables of your contract by changing its parent contracts. For instance, if you have the following contracts: contract A { uint256 a; } contract B { uint256 b; } contract MyContract is A, B {} Then modifying `MyContract` by swapping the order in which the base contracts are declared, or introducing new base contracts, will change how the variables are actually stored: contract MyContract is B, A {} You also cannot add new variables to base contracts, if the child has any variables of its own. Given the following scenario: contract Base { uint256 base1; } contract Child is Base { uint256 child; } If `Base` is modified to add an extra variable: contract Base { uint256 base1; uint256 base2; } Then the variable `base2` would be assigned the slot that `child` had in the previous version. A workaround for this is to declare unused variables or storage gaps in base contracts that you may want to extend in the future, as a means of "reserving" those slots. Note that this trick does not involve increased gas usage. ### [Storage Gaps](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#storage-gaps) Storage gaps are a convention for reserving storage slots in a base contract, allowing future versions of that contract to use up those slots without affecting the storage layout of child contracts. To create a storage gap, declare a fixed-size array in the base contract with an initial number of slots. This can be an array of `uint256` so that each element reserves a 32 byte slot. Use the name `__gap` or a name starting with `__gap_` for the array so that OpenZeppelin Upgrades will recognize the gap: contract Base { uint256 base1; uint256[49] __gap; } contract Child is Base { uint256 child; } If `Base` is later modified to add extra variable(s), reduce the appropriate number of slots from the storage gap, keeping in mind [Solidity's rules on how contiguous items are packed](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#layout-of-state-variables-in-storage) . For example: contract Base { uint256 base1; uint256 base2; // 32 bytes uint256[48] __gap; } Or: contract Base { uint256 base1; address base2; // 20 bytes uint256[48] __gap; // array always starts at a new slot } Or: contract Base { uint256 base1; uint128 base2a; // 16 bytes uint128 base2b; // 16 bytes - continues from the same slot as above uint256[48] __gap; } To help determine the proper storage gap size in the new version of your contract, you can simply attempt an upgrade using `upgradeProxy` or just run the validations with `validateUpgrade` (see docs for [Hardhat Upgrades](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades) or [Foundry Upgrades](https://docs.openzeppelin.com/upgrades-plugins/foundry/api) ). If a storage gap is not being reduced properly, you will see an error message indicating the expected size of the storage gap. ### [Namespaced Storage Layout](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#namespaced-storage-layout) [ERC-7201: Namespaced Storage Layout](https://eips.ethereum.org/EIPS/eip-7201) is another convention that can be used to avoid storage layout errors when modifying base contracts or when changing the inheritance order of contracts. This convention is used in the upgradeable variant of OpenZeppelin Contracts starting with version 5.0. This convention involves placing all storage variables of a contract into one or more structs and annotating those structs with `@custom:storage-location erc7201:`. A namespace id is a string that uniquely identifies each namespace in a contract, so the same id must not be defined more than once in a contract or any of its base contracts. When using namespaced storage layouts, the OpenZeppelin Upgrades plugins will automatically detect the namespace ids and validate that each change within a namespace during an upgrade is safe according to the same rules as described in [Modifying Your Contracts](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts) . Solidity version 0.8.20 or higher is required in order to use the Upgrades plugins with namespaced storage layouts. The plugins will give an error if they detect `@custom:storage-location` annotations with an older version of Solidity, because older versions of the compiler do not produce sufficient information for validation of namespaced storage layouts. ### On this page [Initializers](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializers) [Using Upgradeable Smart Contract Libraries](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#using-upgradeable-smart-contract-libraries) [Avoiding Initial Values in Field Declarations](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#avoiding-initial-values-in-field-declarations) [Initializing the Implementation Contract](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializing-the-implementation-contract) [Validating Initializers](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#validating-initializers) [Creating New Instances From Your Contract Code](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#creating-new-instances-from-your-contract-code) [Potentially Unsafe Operations](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#potentially-unsafe-operations) [Modifying Your Contracts](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts) [Storage Gaps](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#storage-gaps) [Namespaced Storage Layout](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#namespaced-storage-layout) --- # Account Modules | OpenZeppelin Docs [Community Contracts](https://docs.openzeppelin.com/community-contracts) Account Abstraction Account Modules =============== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) 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](https://docs.openzeppelin.com/community-contracts/account-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](https://docs.openzeppelin.com/community-contracts/account-modules#accounts) OpenZeppelin offers an implementation of an [`AccountERC7579`](https://docs.openzeppelin.com/contracts/5.x/api/account#AccountERC7579) contract that allows installing modules compliant with this standard. There’s also an [`AccountERC7579Hooked`](https://docs.openzeppelin.com/contracts/5.x/api/account#AccountERC7579Hooked) variant that supports installation of hooks. Like [most accounts](https://docs.openzeppelin.com/contracts/5.x/accounts#handling-initialization) , an instance should define an initializer function where the first module that controls the account will be set: // contracts/MyAccountERC7579.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol"; import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import {MODULE_TYPE_VALIDATOR} from "@openzeppelin/contracts/interfaces/draft-IERC7579.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; contract MyAccountERC7579 is Initializable, AccountERC7579 { function initializeAccount(address validator, bytes calldata validatorData) public initializer { // Install a validator module to handle signature verification _installModule(MODULE_TYPE_VALIDATOR, validator, validatorData); } } For simplicity, the [`AccountERC7579Hooked`](https://docs.openzeppelin.com/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](https://docs.openzeppelin.com/community-contracts/account-modules#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](https://docs.openzeppelin.com/community-contracts/account-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`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579Executor) or [`ERC7579Validator`](https://docs.openzeppelin.com/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: // contracts/MyERC7579Modules.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {IERC7579Module, IERC7579Hook} from "@openzeppelin/contracts/interfaces/draft-IERC7579.sol"; import {ERC7579Executor} from "@openzeppelin/community-contracts/account/modules/ERC7579Executor.sol"; import {ERC7579Validator} from "@openzeppelin/community-contracts/account/modules/ERC7579Validator.sol"; // Basic validator module abstract contract MyERC7579RecoveryValidator is ERC7579Validator {} // Basic executor module abstract contract MyERC7579RecoveryExecutor is ERC7579Executor {} // Basic fallback handler abstract contract MyERC7579RecoveryFallback is IERC7579Module {} // Basic hook abstract contract MyERC7579RecoveryHook is IERC7579Hook {} Explore these abstract ERC-7579 modules in the [API Reference](https://docs.openzeppelin.com/community-contracts/api/account#modules) . #### [Execution Modes](https://docs.openzeppelin.com/community-contracts/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: // 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](https://docs.openzeppelin.com/community-contracts/account-modules#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](https://docs.openzeppelin.com/community-contracts/account-modules#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](https://docs.openzeppelin.com/community-contracts/account-modules#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](https://docs.openzeppelin.com/community-contracts/account-modules#examples) --------------------------------------------------------------------------------------- ### [Social Recovery](https://docs.openzeppelin.com/community-contracts/account-modules#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](https://docs.openzeppelin.com/contracts/5.x/multisig#beyond-standard-signature-verification) section. For ERC-7579 modules, this is implemented through the [`ERC7579Multisig`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579Multisig) validator. Combined with an [`ERC7579Executor`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579Executor) , it provides a basic foundation that can be extended with more sophisticated features: // contracts/MyERC7579SocialRecovery.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC7579Executor} from "@openzeppelin/community-contracts/account/modules/ERC7579Executor.sol"; import {ERC7579Validator} from "@openzeppelin/community-contracts/account/modules/ERC7579Validator.sol"; import {ERC7579Multisig} from "@openzeppelin/community-contracts/account/modules/ERC7579Multisig.sol"; abstract contract MyERC7579SocialRecovery is EIP712, ERC7579Executor, ERC7579Multisig, Nonces { bytes32 private constant RECOVER_TYPEHASH = keccak256("Recover(address account,bytes32 salt,uint256 nonce,bytes32 mode,bytes executionCalldata)"); function isModuleType(uint256 moduleTypeId) public pure override(ERC7579Executor, ERC7579Validator) returns (bool) { return ERC7579Executor.isModuleType(moduleTypeId) || ERC7579Executor.isModuleType(moduleTypeId); } // Data encoding: [uint16(executionCalldataLength), executionCalldata, signature] function _validateExecution( address account, bytes32 salt, bytes32 mode, bytes calldata data ) internal override returns (bytes calldata) { uint16 executionCalldataLength = uint16(bytes2(data[0:2])); // First 2 bytes are the length bytes calldata executionCalldata = data[2:2 + executionCalldataLength]; // Next bytes are the calldata bytes calldata signature = data[2 + executionCalldataLength:]; // Remaining bytes are the signature require(_rawERC7579Validation(account, _getExecuteTypeHash(account, salt, mode, executionCalldata), signature)); return executionCalldata; } function _getExecuteTypeHash( address account, bytes32 salt, bytes32 mode, bytes calldata executionCalldata ) internal returns (bytes32) { return _hashTypedDataV4( keccak256(abi.encode(RECOVER_TYPEHASH, account, salt, _useNonce(account), mode, executionCalldata)) ); } } For enhanced security, you can extend this foundation with scheduling, delays, and cancellations using [`ERC7579DelayedExecutor`](https://docs.openzeppelin.com/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: // contracts/MyERC7579DelayedSocialRecovery.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC7579Executor} from "@openzeppelin/community-contracts/account/modules/ERC7579Executor.sol"; import {ERC7579Validator} from "@openzeppelin/community-contracts/account/modules/ERC7579Validator.sol"; import {Calldata} from "@openzeppelin/contracts/utils/Calldata.sol"; import {ERC7579DelayedExecutor} from "@openzeppelin/community-contracts/account/modules/ERC7579DelayedExecutor.sol"; import {ERC7579Multisig} from "@openzeppelin/community-contracts/account/modules/ERC7579Multisig.sol"; abstract contract MyERC7579DelayedSocialRecovery is EIP712, ERC7579DelayedExecutor, ERC7579Multisig { bytes32 private constant RECOVER_TYPEHASH = keccak256("Recover(address account,bytes32 salt,bytes32 mode,bytes executionCalldata)"); function isModuleType(uint256 moduleTypeId) public pure override(ERC7579Executor, ERC7579Validator) returns (bool) { return ERC7579Executor.isModuleType(moduleTypeId) || ERC7579Executor.isModuleType(moduleTypeId); } // Data encoding: [uint16(executorArgsLength), executorArgs, uint16(multisigArgsLength), multisigArgs] function onInstall(bytes calldata data) public override(ERC7579DelayedExecutor, ERC7579Multisig) { uint16 executorArgsLength = uint16(bytes2(data[0:2])); // First 2 bytes are the length bytes calldata executorArgs = data[2:2 + executorArgsLength]; // Next bytes are the args uint16 multisigArgsLength = uint16(bytes2(data[2 + executorArgsLength:4 + executorArgsLength])); // Next 2 bytes are the length bytes calldata multisigArgs = data[4 + executorArgsLength:4 + executorArgsLength + multisigArgsLength]; // Next bytes are the args ERC7579DelayedExecutor.onInstall(executorArgs); ERC7579Multisig.onInstall(multisigArgs); } function onUninstall(bytes calldata) public override(ERC7579DelayedExecutor, ERC7579Multisig) { ERC7579DelayedExecutor.onUninstall(Calldata.emptyBytes()); ERC7579Multisig.onUninstall(Calldata.emptyBytes()); } // Data encoding: [uint16(executionCalldataLength), executionCalldata, signature] function _validateSchedule( address account, bytes32 salt, bytes32 mode, bytes calldata data ) internal view override { uint16 executionCalldataLength = uint16(bytes2(data[0:2])); // First 2 bytes are the length bytes calldata executionCalldata = data[2:2 + executionCalldataLength]; // Next bytes are the calldata bytes calldata signature = data[2 + executionCalldataLength:]; // Remaining bytes are the signature require(_rawERC7579Validation(account, _getExecuteTypeHash(account, salt, mode, executionCalldata), signature)); } function _getExecuteTypeHash( address account, bytes32 salt, bytes32 mode, bytes calldata executionCalldata ) internal view returns (bytes32) { return _hashTypedDataV4(keccak256(abi.encode(RECOVER_TYPEHASH, account, salt, mode, executionCalldata))); } } The delayed executor’s signature validation doesn’t require a nonce since operations are uniquely identified by their [operation id](https://docs.openzeppelin.com/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`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579MultisigWeighted) to assign different weights to signers * [`ERC7579MultisigConfirmation`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579MultisigConfirmation) to implement a confirmation system that verifies signatures when adding signers * [`ERC7579MultisigStorage`](https://docs.openzeppelin.com/community-contracts/api/account#ERC7579MultisigStorage) to allow guardians to presign recovery operations for more flexible coordination [Overview\ \ Previous Page](https://docs.openzeppelin.com/community-contracts) [Paymasters\ \ Next Page](https://docs.openzeppelin.com/community-contracts/paymasters) ### On this page [ERC-7579](https://docs.openzeppelin.com/community-contracts/account-modules#erc-7579) [Accounts](https://docs.openzeppelin.com/community-contracts/account-modules#accounts) [Modules](https://docs.openzeppelin.com/community-contracts/account-modules#modules) [Building Custom Modules](https://docs.openzeppelin.com/community-contracts/account-modules#building-custom-modules) [Execution Modes](https://docs.openzeppelin.com/community-contracts/account-modules#execution-modes) [Call Types](https://docs.openzeppelin.com/community-contracts/account-modules#call-types) [Execution Types](https://docs.openzeppelin.com/community-contracts/account-modules#execution-types) [Execution Data Format](https://docs.openzeppelin.com/community-contracts/account-modules#execution-data-format) [Examples](https://docs.openzeppelin.com/community-contracts/account-modules#examples) [Social Recovery](https://docs.openzeppelin.com/community-contracts/account-modules#social-recovery) --- # Utilities | OpenZeppelin Docs OpenZeppelin ContractsPrevious Versionsv3 Utilities ========= [Outdated Version\ \ You're viewing an older version (v3.x) The latest documentation is available for the current version. Click here to visit latest version.](https://docs.openzeppelin.com/contracts/5.x/utilities) Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. Here are some of the more popular ones. [Cryptography](https://docs.openzeppelin.com/contracts/3.x/utilities#cryptography) ----------------------------------------------------------------------------------- ### [Checking Signatures On-Chain](https://docs.openzeppelin.com/contracts/3.x/utilities#checking-signatures-on-chain) [`ECDSA`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#ECDSA) provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via [`web3.eth.sign`](https://web3js.readthedocs.io/en/v1.2.4/web3-eth.html#sign) , and are a 65 byte array (of type `bytes` in Solidity) arranged the following way: `[[v (1)], [r (32)], [s (32)]]`. The data signer can be recovered with [`ECDSA.recover`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#ECDSA-recover-bytes32-bytes-) , and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix '\\x19Ethereum Signed Message:\\n', so when attempting to recover the signer of an Ethereum signed message hash, you’ll want to use [`toEthSignedMessageHash`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#ECDSA-toEthSignedMessageHash-bytes32-) . using ECDSA for bytes32; function _verify(bytes32 data, address account) pure returns (bool) return keccack256(data) .toEthSignedMessageHash() .recover(signature) == account; Getting signature verification right is not trivial: make sure you fully read and understand [`ECDSA`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#ECDSA) 's documentation. ### [Verifying Merkle Proofs](https://docs.openzeppelin.com/contracts/3.x/utilities#verifying-merkle-proofs) [`MerkleProof`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#MerkleProof) provides [`verify`](https://docs.openzeppelin.com/contracts/3.x/api/cryptography#MerkleProof-verify-bytes32---bytes32-bytes32-) , which can prove that some value is part of a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) . [Introspection](https://docs.openzeppelin.com/contracts/3.x/utilities#introspection) ------------------------------------------------------------------------------------- In Solidity, it’s frequently helpful to know whether or not a contract supports an interface you’d like to use. ERC165 is a standard that helps do runtime interface detection. Contracts provides helpers both for implementing ERC165 in your contracts and querying other contracts: * [`IERC165`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#IERC165) — this is the ERC165 interface that defines [`supportsInterface`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#IERC165-supportsInterface-bytes4-) . When implementing ERC165, you’ll conform to this interface. * [`ERC165`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#ERC165) — inherit this contract if you’d like to support interface detection using a lookup table in contract storage. You can register interfaces using [`_registerInterface(bytes4)`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#ERC165-_registerInterface-bytes4-) : check out example usage as part of the ERC721 implementation. * [`ERC165Checker`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#ERC165Checker) — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about. * include with `using ERC165Checker for address;` * [`myAddress._supportsInterface(bytes4)`](https://docs.openzeppelin.com/contracts/3.x/api/introspection#ERC165Checker-_supportsInterface-address-bytes4-) * \[`myAddress._supportsAllInterfaces(bytes4[](/contracts/3.x/api/introspection#ERC165Checker-_supportsAllInterfaces-address-bytes4---))`\] contract MyContract using ERC165Checker for address; bytes4 private InterfaceId_ERC721 = 0x80ac58cd; /** * @dev transfer an ERC721 token from this contract to someone else */ function transferERC721( address token, address to, uint256 tokenId ) public { require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN"); IERC721(token).transferFrom(address(this), to, tokenId); } [Math](https://docs.openzeppelin.com/contracts/3.x/utilities#math) ------------------------------------------------------------------- The most popular math related library OpenZeppelin Contracts provides is [`SafeMath`](https://docs.openzeppelin.com/contracts/3.x/api/math#SafeMath) , which provides mathematical functions that protect your contract from overflows and underflows. Include the contract with `using SafeMath for uint256;` and then call the functions: * `myNumber.add(otherNumber)` * `myNumber.sub(otherNumber)` * `myNumber.div(otherNumber)` * `myNumber.mul(otherNumber)` * `myNumber.mod(otherNumber)` Easy! [Payment](https://docs.openzeppelin.com/contracts/3.x/utilities#payment) ------------------------------------------------------------------------- Want to split some payments between multiple people? Maybe you have an app that sends 30% of art purchases to the original creator and 70% of the profits to the current owner; you can build that with [`PaymentSplitter`](https://docs.openzeppelin.com/contracts/3.x/api/payment#PaymentSplitter) ! In Solidity, there are some security concerns with blindly sending money to accounts, since it allows them to execute arbitrary code. You can read up on these security concerns in the [Ethereum Smart Contract Best Practices](https://consensys.github.io/smart-contract-best-practices/) website. One of the ways to fix reentrancy and stalling problems is, instead of immediately sending Ether to accounts that need it, you can use [`PullPayment`](https://docs.openzeppelin.com/contracts/3.x/api/payment#PullPayment) , which offers an [`_asyncTransfer`](https://docs.openzeppelin.com/contracts/3.x/api/payment#PullPayment-_asyncTransfer-address-uint256-) function for sending money to something and requesting that they [`withdrawPayments()`](https://docs.openzeppelin.com/contracts/3.x/api/payment#PullPayment-withdrawPayments-address-payable-) it later. If you want to Escrow some funds, check out [`Escrow`](https://docs.openzeppelin.com/contracts/3.x/api/payment#Escrow) and [`ConditionalEscrow`](https://docs.openzeppelin.com/contracts/3.x/api/payment#ConditionalEscrow) for governing the release of some escrowed Ether. [Collections](https://docs.openzeppelin.com/contracts/3.x/utilities#collections) --------------------------------------------------------------------------------- If you need support for more powerful collections than Solidity’s native arrays and mappings, take a look at [`EnumerableSet`](https://docs.openzeppelin.com/contracts/3.x/api/utils#EnumerableSet) and [`EnumerableMap`](https://docs.openzeppelin.com/contracts/3.x/api/utils#EnumerableMap) . They are similar to mappings in that they store and remove elements in constant time and don’t allow for repeated entries, but they also support _enumeration_, which means you can easily query all stored entries both on and off-chain. [Misc](https://docs.openzeppelin.com/contracts/3.x/utilities#misc) ------------------------------------------------------------------- Want to check if an address is a contract? Use [`Address`](https://docs.openzeppelin.com/contracts/3.x/api/utils#Address) and [`Address.isContract()`](https://docs.openzeppelin.com/contracts/3.x/api/utils#Address-isContract-address-) . Want to keep track of some numbers that increment by 1 every time you want another one? Check out [`Counters`](https://docs.openzeppelin.com/contracts/3.x/api/utils#Counters) . This is useful for lots of things, like creating incremental identifiers, as shown on the [ERC721 guide](https://docs.openzeppelin.com/contracts/3.x/erc721) . [Strategies\ \ Previous Page](https://docs.openzeppelin.com/contracts/3.x/gsn-strategies) [Overview\ \ Next Page](https://docs.openzeppelin.com/community-contracts) ### On this page [Cryptography](https://docs.openzeppelin.com/contracts/3.x/utilities#cryptography) [Checking Signatures On-Chain](https://docs.openzeppelin.com/contracts/3.x/utilities#checking-signatures-on-chain) [Verifying Merkle Proofs](https://docs.openzeppelin.com/contracts/3.x/utilities#verifying-merkle-proofs) [Introspection](https://docs.openzeppelin.com/contracts/3.x/utilities#introspection) [Math](https://docs.openzeppelin.com/contracts/3.x/utilities#math) [Payment](https://docs.openzeppelin.com/contracts/3.x/utilities#payment) [Collections](https://docs.openzeppelin.com/contracts/3.x/utilities#collections) [Misc](https://docs.openzeppelin.com/contracts/3.x/utilities#misc) --- # Changelog | OpenZeppelin Docs Relayer Changelog ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [](https://docs.openzeppelin.com/relayer/changelog#v110---2025-08-11) [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.1.0) - 2025-08-11 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/relayer/changelog#110-2025-08-11) [1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0) (2025-08-11) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features) * Add Arbitrum support ([#373](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/373) ) ([7b5372b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b5372bf54fe26756ca5db6cb393e0d9d79ae621) ) * add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5) ) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8) ) * Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130) ) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745) ) * add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9) ) * add evm intristic gas\_limit validation ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715) ) * Add get\_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229) ) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4) ) * Add Launctube plugin example ([#414](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/414) ) ([5bda763](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5bda7635f304923fcd4031f855009228eeefee4b) ) * Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28) ) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49) ) * Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102) ) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d) ) * Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236) ) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d) ) * Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134) ) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744) ) * add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146) ) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b) ) * Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290) ) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228) ) * Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279) ) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33) ) * Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6) ) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883) ) * Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148) ) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974) ) * Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65) ) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e) ) * Add status\_reason field to transaction responses ([#369](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/369) ) ([c489e5d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c489e5d39e3cec555caf92ac93266016c547b2bb) ) * Add stellar launchtube plugin ([#401](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/401) ) ([801e2f7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/801e2f7efc8f0cb7eb54f545ce398e6ee24cf6b9) ) * Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309) ) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c) ) * add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13) ) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3) ) * Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284) ) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317) ) * Add support to plugin list endpoint ([#358](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/358) ) ([6517af0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6517af0a753db41638b006fa2b896a3ccec0d4ef) ) * add timeout\_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169) ) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99) ) * Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223) ) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362) ) * Add wait API for plugin transactions ([#345](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/345) ) ([6069af2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6069af256e6cfe8470244731d4bb444b87bd175f) ) * Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137) ) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93) ) * Added resolve\_plugin\_path for script\_path ([#340](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/340) ) ([0b30739](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0b30739e51f5ef6c0b97c1da585d403496b2bbac) ) * Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110) ) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278) ) * Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302) ) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f) ) * enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360) ) * enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6) ) * Enhance Stellar tx handling with fee updates ([#368](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/368) ) ([05617d7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/05617d7cb06ab378c2c2207f9d0a2e11a04cc472) ) * **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287) ) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06) ) * **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289) ) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b) ) * **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286) ) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e) ) * extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238) ) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81) ) * handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233) ) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3) ) * implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168) ) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9) ) * Implement get\_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228) ) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9) ) * implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235) ) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5) ) * improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119) ) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1) ) * Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120) ) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896) ) * Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120) ) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896) ) * initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c) ) * Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74) ) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9) ) * Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178) ) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298) ) * Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312) ) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c) ) * Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11) ) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640) ) * Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50) ) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8) ) * Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122) ) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281) ) * Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12) ) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb) ) * Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109) ) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb) ) * PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101) ) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f) ) * PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101) ) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f) ) * Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19) ) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a) ) * Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26) ) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432) ) * Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29) ) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163) ) * plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36) ) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1) ) * Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38) ) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b) ) * Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61) ) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e) ) * Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63) ) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3) ) * Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57) ) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172) ) * Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45) ) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202) ) * Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99) ) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18) ) * Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43) ) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9) ) * plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231) ) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1) ) * Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37) ) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8) ) * Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42) ) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57) ) * Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42) ) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57) ) * Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44) ) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1) ) * Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44) ) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1) ) * Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49) ) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0) ) * Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49) ) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0) ) * Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69) ) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94) ) * Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72) ) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e) ) * Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76) ) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0) ) * Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78) ) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7) ) * Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78) ) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7) ) * Plat-6303 store solana submitted transactions to db and run status check logic ([#398](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/398) ) ([e8420bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e8420bca02c20a53b02d9bedc8da1b7a784716dc) ) * Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94) ) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861) ) * Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83) ) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e) ) * Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83) ) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e) ) * plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104) ) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421) ) * PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98) ) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe) ) * PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98) ) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe) ) * PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100) ) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8) ) * PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100) ) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8) ) * PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105) ) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a) ) * plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125) ) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6) ) * Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131) ) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf) ) * PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117) ) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9) ) * PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117) ) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9) ) * Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127) ) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938) ) * Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127) ) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938) ) * Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126) ) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423) ) * plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166) ) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451) ) * plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135) ) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe) ) * Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138) ) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b) ) * Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174) ) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3) ) * plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198) ) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3) ) * plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221) ) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b) ) * Plat-6677 implement redis repositories for existing collections ([#350](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/350) ) ([5fee731](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5fee731c5f19013f41a12a5b93af79d65bdf777e) ) * Plat-6679 implement startup logic to populate redis from config file ([#359](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/359) ) ([5e1c0c8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5e1c0c825d3c1185a5c59360a2c857d79b46abba) ) * Plat-6681 expose crud api endpoints ([#365](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/365) ) ([f3c3426](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f3c34266f3f035cd240105833ef4e67711cb0356) ) * Plat-6684 add support for transaction entries expiration ([#394](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/394) ) ([6f6f765](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6f6f765556b2fc16764f8afe02ceedf268c26c13) ) * plat-6817 EVM add support for gas limit calculation ([#355](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/355) ) ([dd1b2d6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dd1b2d6768d09f051791d0db68c912a38d273715) ) * plat-6873 add storage documentation ([#395](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/395) ) ([ffd4ed5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ffd4ed58d322bad63be500a084a0b082ac7b59d9) ) * Plugins improvements ([#410](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/410) ) ([648a0f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/648a0f121a6308e8bde0e09010d2e0c83de5c6ec) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253) ) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe) ) * **replace\_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272) ) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52) ) * Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313) ) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74) ) * Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8) ) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642) ) * **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305) ) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510) ) * Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62) ) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa) ) * Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213) ) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014) ) * Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183) ) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4) ) * Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199) ) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245) ) * support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182) ) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba) ) * support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197) ) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349) ) * Support plugin timeouts ([#348](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/348) ) ([0a1c51e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0a1c51e9fe540ba570af25146538992a26b9a8a0) ) * Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81) ) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1) ) * Types introduced for plugin params and result ([#351](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/351) ) ([dda83a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dda83a296fd5bd5bfca7f7902f4ca035e1bd8796) ) * Update Stellar network config and docs ([#380](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/380) ) ([a4e1a0f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a4e1a0f38590f21c6d5e917a02fee4f6bef4f075) ) * Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85) ) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes) * Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294) ) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300) ) * change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206) ) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8) ) * Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266) ) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8) ) * CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171) ) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0) ) * CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173) ) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0) ) * Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113) ) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5) ) * Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285) ) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e) ) * Correct env var value in semgrep.yml ([#375](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/375) ) ([2e98e21](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e98e2149135b97a62b90c302675379642fdf7b3) ) * Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156) ) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c) ) * Docker readme file ([#339](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/339) ) ([2db9933](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2db9933def061046cc3585a07249107a236ef98c) ) * docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255) ) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5) ) * Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128) ) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a) ) * Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129) ) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49) ) * **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f) ) * Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121) ) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c) ) * Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124) ) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575) ) * Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108) ) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb) ) * Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89) ) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09) ) * Implement stellar sequence sync and tx reset ([#367](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/367) ) ([60b5deb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/60b5deb4915041d60a064cfac1a066406c339517) ) * Inheritance validation ([#374](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/374) ) ([f8b921b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f8b921b4d6d85b8068428f1e34de121183a02179) ) * Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300) ) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e) ) * Minor fixes in Plugin docs ([#325](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/325) ) ([33bb6a1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/33bb6a1841f2e84723e49cc81258a930241dc735) ) * Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155) ) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e) ) * Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70) ) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac) ) * PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118) ) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce) ) * PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139) ) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff) ) * plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132) ) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6) ) * Plat-6815 resubmission bug ([#353](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/353) ) ([72ac174](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/72ac17471e3a0a6ac35e9a9bb9ff8fe5e8b94bf2) ) * plat-6888 aws kms signer issue ([#411](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/411) ) ([3c12c88](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3c12c88703c92526fe975eabba6ba0ffa9ca9c79) ) * Plugin result + adds tests for plugin ts lib ([#336](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/336) ) ([b30246e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b30246e8922d3cb5bd3c5b92a7678f7591db5b97) ) * Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307) ) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753) ) * Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163) ) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b) ) * remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222) ) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8) ) * Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315) ) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6) ) * Replace tx request body ([#326](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/326) ) ([a20c916](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a20c916b592891b7a2afafd2e62b32723fc05dc2) ) * SBOM upload error ([#342](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/342) ) ([1f9318e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1f9318e22cbe59ca03bc617b0986379574e5f770) ) * Semgrep CI integration ([#371](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/371) ) ([6b9a6d2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6b9a6d24e22b78743f16c566026b34f9912669ad) ) * Semgrep send metrics value ([#381](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/381) ) ([315ccbc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/315ccbca9a48816fc6e0c8133301aa3e3186ff93) ) * Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3) ) * Solve issues with new solana\_sdk version ([#324](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/324) ) ([ab97253](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab972533259506bb21e22ec7f899a45d2fc97db5) ) * Switch Redocly build to use standalone html file ([#291](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/291) ) ([97a8698](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/97a86980bec6260920a469018fee0d3541d1a063) ) * syntax error in codeql.yml ([#385](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/385) ) ([987fd33](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/987fd33566b66b2821490d0769a3c863a778c271) ) * Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298) ) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6) ) * Update semgrep.yml ([#347](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/347) ) ([5ffb803](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ffb8036ca6d3fb5a8cdb34fa5484e7732c842a1) ) * Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292) ) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196) ) * Use unicode character for emoji ([#343](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/343) ) ([784e89f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/784e89fae4ad2ddad037ddbbd0bec6df160e9a6a) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0) [](https://docs.openzeppelin.com/relayer/changelog#v100---2025-06-30) [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.0.0) - 2025-06-30 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/relayer/changelog#100-2025-06-30) [1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0) (2025-06-30) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-1) * add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5) ) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8) ) * Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130) ) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745) ) * add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9) ) * Add get\_status method for EVM and Stellar ([#229](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/229) ) ([e84217e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e84217e0fa941fcd580ad6b84ab6bfac939dd5f4) ) * Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28) ) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49) ) * Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102) ) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d) ) * Add node support to environment ([#236](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/236) ) ([3ab46f8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ab46f848e7e4c6dee2545d62dc646b33623d63d) ) * Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134) ) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744) ) * add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146) ) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b) ) * Add plugin invoker service ([#290](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/290) ) ([489ce02](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/489ce0285cd88a18b1616af94bfc970a4a674228) ) * Add plugins call endpoint ([#279](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/279) ) ([c278589](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c278589f4c6bf88be86788fdd9b68c2f166f5f33) ) * Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6) ) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883) ) * Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148) ) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974) ) * Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65) ) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e) ) * Add support for feebumped tx ([#309](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/309) ) ([b4efd2e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b4efd2e894fb6534b61a10c5f8872a73d923410c) ) * add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13) ) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3) ) * Add support for stellar InvokeHostFunction transactions ([#284](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/284) ) ([32ba63e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/32ba63e58e3dfc1359b7a5c9f61f9ff2a8b6c317) ) * add timeout\_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169) ) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99) ) * Add transaction status handling for stellar ([#223](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/223) ) ([9496eb6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9496eb63514afb0bd29c731bebe86ffdcf393362) ) * Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137) ) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93) ) * Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110) ) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278) ) * Create initial js plugins library ([#302](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/302) ) ([98238e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/98238e9a6a30de8dba3bf8d308a82658e29de46f) ) * enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360) ) * enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6) ) * **evm:** Add AWS KMS signer support ([#287](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/287) ) ([723a9a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/723a9a8d7e625dd3f52b2d678d0e1cd842053e06) ) * **evm:** Implement delete pending txs ([#289](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/289) ) ([bc6f829](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc6f829e580d42359adebceeddaf38002390e10b) ) * **evm:** Implement json rpc endpoint ([#286](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/286) ) ([91528aa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/91528aab82e3fa3cba08f63feb4ac9879aa8940e) ) * extract networks to json files ([#238](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/238) ) ([5ac07b3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/5ac07b3c570485d7cdbc419a23f373867d7ebe81) ) * handle non-retriable errors and provider health errors ([#233](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/233) ) ([7add348](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7add348da4d06af5ebebcce78d856485e9894ac3) ) * implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168) ) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9) ) * Implement get\_balance method for StellarRelayer ([#228](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/228) ) ([d92c75f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d92c75fe7da1b02ddb7a38df32f98082474e4cd9) ) * implement network config deserializing ([#235](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/235) ) ([6d537f9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6d537f9298626fefc0d5a45c311a95208e1c8ef5) ) * improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119) ) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1) ) * Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120) ) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896) ) * initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c) ) * Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74) ) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9) ) * Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178) ) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298) ) * Pass arbitrary payloads to script exectution ([#312](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/312) ) ([adecaf5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/adecaf5d73c3df9083c6a3fcf62ed669bc90b25c) ) * Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11) ) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640) ) * Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50) ) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8) ) * Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122) ) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281) ) * Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12) ) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb) ) * Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109) ) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb) ) * PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101) ) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f) ) * Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19) ) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a) ) * Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26) ) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432) ) * Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29) ) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163) ) * plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36) ) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1) ) * Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38) ) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b) ) * Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61) ) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e) ) * Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63) ) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3) ) * Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57) ) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172) ) * Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45) ) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202) ) * Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99) ) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18) ) * Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43) ) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9) ) * plat-6215 add support for rpc failovers and retries ([#231](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/231) ) ([ca6d24f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ca6d24f1bcdbb912795dcb1496519b49b5e81bf1) ) * Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37) ) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8) ) * Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42) ) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57) ) * Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44) ) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1) ) * Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49) ) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0) ) * Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69) ) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94) ) * Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72) ) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e) ) * Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76) ) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0) ) * Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78) ) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7) ) * Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94) ) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861) ) * Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83) ) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e) ) * plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104) ) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421) ) * PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98) ) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe) ) * PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100) ) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8) ) * PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105) ) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a) ) * plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125) ) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6) ) * Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131) ) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf) ) * PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117) ) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9) ) * Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127) ) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938) ) * Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126) ) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423) ) * plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166) ) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451) ) * plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135) ) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe) ) * Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138) ) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b) ) * Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174) ) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3) ) * plat-6522 allow for the use of on chain defi to automatically swap spl ([#198](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/198) ) ([dc9e2e2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/dc9e2e2dd1d46830bc6479c1928a2e7ef7f91fb3) ) * plat-6571 add support for gcp signer ([#221](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/221) ) ([0170fa1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0170fa12c3ecc64d1c48ed3a726358ed74d4596b) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Relayer plugins - add support to plugins in configs ([#253](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/253) ) ([6a14239](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6a14239486900b2ef121b5de9e87410c412b65fe) ) * **replace\_tx:** Implement replace tx for evm ([#272](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/272) ) ([b48e71f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b48e71f55fda03bea83e90255b0d180db704cb52) ) * Set default network folder ([#313](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/313) ) ([b28c99c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b28c99c43bedd921a55660622d845e63890e0d74) ) * Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8) ) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642) ) * **signer:** Add GCP Signer to EVM ([#305](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/305) ) ([a8817b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a8817b6c87c65731232d0a141338f3996aef2510) ) * Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62) ) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa) ) * Stellar RPC config ([#213](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/213) ) ([6fd75ea](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd75ea65bf1a945ba891f99d83b0cdacdf30014) ) * Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183) ) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4) ) * Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199) ) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245) ) * support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182) ) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba) ) * support for retries and failovers in EVM Provider ([#197](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/197) ) ([542f21a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/542f21a9346def9b7fe47e0a29a2bbd5ab2af349) ) * Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81) ) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1) ) * Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85) ) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-1) * Add memo validation for InvokeHostFunction ([#294](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/294) ) ([6bb4ffa](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6bb4ffaf9ceb4a8daef29ec5878595cca7041300) ) * change the ampersand to and, as as the shell interpret it ([#206](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/206) ) ([d164d6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d164d6a4d63fbf0acdfe1330cf25147e86280af8) ) * Changing base image to wolfi, added node and npm ([#266](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/266) ) ([1181996](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1181996dac6da52f96e164b1c937828a3940d5b8) ) * CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171) ) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0) ) * CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173) ) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0) ) * Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113) ) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5) ) * Config example file ([#285](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/285) ) ([a020c6f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a020c6fcd6f9b638d955d5f2c99aa0e199d8bf6e) ) * Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156) ) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c) ) * docker-scan - chainguard issue ([#255](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/255) ) ([c9ab94b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c9ab94bcee7b386a33b063504b3e6d2cf188d8b5) ) * Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128) ) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a) ) * Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129) ) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49) ) * **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f) ) * Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121) ) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c) ) * Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124) ) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575) ) * Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108) ) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb) ) * Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89) ) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09) ) * Make plugins entry in configs optional ([#300](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/300) ) ([f299779](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f299779318429677fd672d4a2433828971a1b62e) ) * Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155) ) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e) ) * Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70) ) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac) ) * PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118) ) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce) ) * PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139) ) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff) ) * plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132) ) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6) ) * Relayer plugins format output ([#307](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/307) ) ([8f25e5f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f25e5f55812e3d346c8bc0ff063cf07e2f0b753) ) * Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163) ) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b) ) * remove the ci job dependant from the test job ([#222](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/222) ) ([4056610](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40566108b66c701323145c2889ce0141b84714b8) ) * Replace automatic minor version bumps ([#315](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/315) ) ([85784b4](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/85784b486a9508429ae94373a7f3db13d78b39d6) ) * Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3) ) * Update configs and dockerfiles in examples ([#298](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/298) ) ([2e505ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2e505ad827ab7544f7c6a3fdf4018b1e9428f1d6) ) * Update Stellar API docs to match implementation ([#292](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/292) ) ([96d95e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/96d95e35784c25f39afe626b56f11477fd213196) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0) [](https://docs.openzeppelin.com/relayer/changelog#v020---2025-05-14) [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.2.0) - 2025-05-14 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/relayer/changelog#020-2025-05-14) [0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0) (2025-05-14) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-2) * add optimism extra cost calculation ([#146](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/146) ) ([b85e070](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b85e070074ecc0aa4fbd7d5dc3af6ca0d600220b) ) * add timeout\_seconds to EVM relayer configuration ([#169](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/169) ) ([6fd59bc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6fd59bc0e5993d63608d47e7ba7825a027e26b99) ) * implement balance validation in EVM ([#168](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/168) ) ([27fe333](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/27fe333806c28c268af981f5377e188160c845b9) ) * Local signing for stellar ([#178](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/178) ) ([f69270a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f69270ade4c9a9239bba874ac74858c8e7375298) ) * plat-6471 add Solana Token 2022 extensions support ([#166](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/166) ) ([d35c506](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d35c506ea298a86897ede5702481403f839f2451) ) * Plat-6521 add turnkey hosted signer support (evm, solana) ([#174](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/174) ) ([b24688e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b24688ead4fe3015ca3b7c74e56f1906085a5aa3) ) * Stellar RPC service ([#183](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/183) ) ([9943ffd](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9943ffd67a709df487264f50eccd03b06cc817d4) ) * Stellar transaction submission ([#199](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/199) ) ([c6b72bf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c6b72bfba82c7fb9288c07e49bef04cf527d1245) ) * support for multiple custom RPCs with weighted configuration ([#182](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/182) ) ([92ea5ad](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/92ea5ad324323b957fcbdce85c37517ec6f963ba) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-2) * CLA assistant ([#171](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/171) ) ([b326a56](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b326a5680722e812263aab949003c214795fd2c0) ) * CLA labels ([#173](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/173) ) ([e31405b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e31405b8cba9ffd2ff991d56444320ff3d069ad0) ) * Docker Compose ([#156](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/156) ) ([6ca012f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6ca012fb9b50d5c2159c498679673cb27530fc3c) ) * Missing libssl and workflow ([#155](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/155) ) ([9de7133](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9de7133c2ba1768f4d989158f19c27444e522f9e) ) * Release merge conflicts ([#163](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/163) ) ([4cac422](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4cac4221817373a1ae7eff92db187dbae2f1665b) ) * Skip releases ([ccafcbe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ccafcbe11bc6ea46dacb9c59be578abd45112ad3) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0) [](https://docs.openzeppelin.com/relayer/changelog#v011---2025-04-08) [v0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.1) - 2025-04-08 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/relayer/changelog#011-2025-04-08) [0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1) (2025-04-08) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-3) * Skip releases ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f) ) * Skip releases with release please ([#158](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/158) ) ([e79b2e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e79b2e963439721dd8e151fa0827654e4019df5f) ) ### [⚙️ Miscellaneous Chores](https://docs.openzeppelin.com/relayer/changelog#%EF%B8%8F-miscellaneous-chores) * Fix workflow and missing libs in docker file ([#157](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/157) ) ([c7a681d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7a681dea154b06b675a286e936606e2f9ce087b) ) * plat-7575 Docs fixes ([#153](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/153) ) ([#154](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/154) ) ([44257e8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44257e8ea3e658adbf40f69ad809e4e3503e9af4) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1) [](https://docs.openzeppelin.com/relayer/changelog#v010---2025-04-07) [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.0) - 2025-04-07 ====================================================================================================================================================================== [0.1.0 (2025-04-07)](https://docs.openzeppelin.com/relayer/changelog#010-2025-04-07) ------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-3) * add base models ([#5](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/5) ) ([55db42b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/55db42b16d88e95ca8f6927e3b4d07c939e677c8) ) * Add CLA assistant bot ([#130](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/130) ) ([4ad5733](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4ad5733daadefe5e52bd617eaa47039677443745) ) * add directory structure and example ([d946c10](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d946c10fd96ee2d1ce2e373ba4ccfced31f985f9) ) * Add logging improvements ([#28](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/28) ) ([bb6751a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bb6751a4f868eb82787e7763a7995d3974ecfd49) ) * Add logic to resubmit transaction ([#102](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/102) ) ([6c258b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6c258b625dc7edb1d028b771647ff25b12c2b07d) ) * Add noop support and refactor status ([#134](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/134) ) ([f0e3a17](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f0e3a177a536c53fe8eff834243d417bb673b744) ) * Add queue processing support ([#6](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/6) ) ([3ebbac2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3ebbac25f1ecb403dec7d090d39882a85227d883) ) * Add release workflow ([#148](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/148) ) ([bd9a7e9](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bd9a7e91a300e6650b08f799aecea4478bb4b974) ) * Add sign tx for evm local signer ([#65](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/65) ) ([b17fb36](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b17fb3625677f1dbcf1ddf3963db13b9b88ca25e) ) * add support for relayer paused and system disabled state ([#13](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/13) ) ([44968a2](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/44968a29ec4f1cf1166c2ad726f2c9a1bac246c3) ) * Add worldchain testnet support ([#137](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/137) ) ([25751ef](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/25751ef97b7b9fbe0c4b53fab5b762d1696f8c93) ) * Adding job tests ([#110](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/110) ) ([4d2dd98](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d2dd98efedacaded8d4ace118c43dbe25907278) ) * enabling it to listen on all interfaces - allows for easy docker config ([74a59da](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/74a59da79b314160baf35ec9750e372fbad0f360) ) * enabling it to listen on all interfaces - allows for easy docker config ([23f94c0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/23f94c07ce46254f7b80df77ce8c4fc59fb4eef6) ) * improve examples ([#119](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/119) ) ([7e59aa6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7e59aa64f75f3470807396b293e71cd68d3292d1) ) * Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120) ) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896) ) * Improve Redis startup logic ([#120](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/120) ) ([8618ecf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8618ecf00b4739891fe4ce98caf14f729face896) ) * initial repo setup ([d8815b6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/d8815b6752931003536aa427370ca8fb1c57231c) ) * Integrate Netlify with antora ([#74](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/74) ) ([09e3d48](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/09e3d4894b54c58754b373da239e9d564df69aa9) ) * Plat 5744 implement an api key authentication mechanism ([#11](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/11) ) ([8891887](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/88918872d51ab10632ec6d590689d52e59dfd640) ) * Plat 5768 setup metrics endpoint ([#50](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/50) ) ([7c292a5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7c292a572a7aef8213969fc72cadca74f9016fe8) ) * Plat 6434 improve authorization header validation ([#122](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/122) ) ([eed7c31](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/eed7c31e938c7b6ecaa82774ca5d3a508bb89281) ) * Plat-5749 implement basic webhook notifications service ([#12](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/12) ) ([1b47b64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b47b64c318208eb7dc2ec6d62020fab30ccafbb) ) * Plat-5802 openapi sdk client ([#109](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/109) ) ([1b4b681](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1b4b681a3755f60e2934548a9666c60a4465dabb) ) * PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101) ) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f) ) * PLAT-6026 Imp cancel transaction ([#101](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/101) ) ([1e5cc47](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1e5cc47bdc54acafeeefb60489db410b42722b0f) ) * Plat-6118 implement logic for syncing relayer state upon service start ([#19](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/19) ) ([2ba3629](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ba36292a0b8d0d67ddab42d2845a6a0d5f31e3a) ) * Plat-6153 add network definitions for Solana networks ([#26](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/26) ) ([ff453d5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ff453d59724eeaa194ccf7f83993ce8d649f7432) ) * Plat-6154 add support for solana local signer ([#29](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/29) ) ([40caead](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/40caeadde5f08200410912b98943346971084163) ) * plat-6158 implement Solana rpc service ([#36](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/36) ) ([8fb50a8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8fb50a833e7f9b1773dbe4ca1d77a9609a5d5ec1) ) * Plat-6159 extend relayer config file solana policies ([#38](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/38) ) ([4f4602b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4602b754e71539937447c1743a7f069317598b) ) * Plat-6164 implement feeestimate rpc method ([#61](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/61) ) ([43b016c](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/43b016c4e5faa5ee1fedcdadccf3bc768962178e) ) * Plat-6165 implement transfertransaction rpc method ([#63](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/63) ) ([c59a3b8](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c59a3b8894c32470adf10770f4804e272aa829d3) ) * Plat-6167 implement signtransaction rpc method ([#57](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/57) ) ([ad7a1ff](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ad7a1ffe41eb868f54737c1f1b44a52c6d02d172) ) * Plat-6169 implement getsupportedtokens rpc method ([#45](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/45) ) ([3f91199](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3f9119981acd7f92618ba6ec12c3039563368202) ) * Plat-6170 add vault hosted signer support ([#99](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/99) ) ([7a9491d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7a9491d4094fc21bc87551c68687b4f44f3edd18) ) * Plat-6207 implement trait abstraction relayer ([#43](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/43) ) ([abeb7cf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/abeb7cfccc9e70b26ddd0d41d736352d57d6ade9) ) * Plat-6216 adding network symbol support ([#37](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/37) ) ([21f798f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/21f798fc114de47ae0ed7e127e496bb50ca081a8) ) * Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42) ) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57) ) * Plat-6236 adding validation payload ([#42](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/42) ) ([a5ff165](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a5ff165df14f48d47adee03e8e2c8ef5a899ff57) ) * Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44) ) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1) ) * Plat-6239 whitelist policy validation ([#44](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/44) ) ([3adb45e](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3adb45e17b8b23c70e09e422cfca051ebab266f1) ) * Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49) ) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0) ) * Plat-6248 implementation dummy of legacy price ([#49](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/49) ) ([6319d64](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6319d64bf27fd75f5192165df885156ca91ea9f0) ) * Plat-6267 add utility script for generating local keystore files ([#69](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/69) ) ([b5df7f6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/b5df7f6b0450118c9123de46689fa115efcdec94) ) * Plat-6291 add webhook notifications for rpc methods ([#72](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/72) ) ([2f35d81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2f35d81b3711cf2f87dbc6df31b9e0f90432164e) ) * Plat-6299 clean transaction response ([#76](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/76) ) ([fc5dd05](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc5dd05154bca4a1d740cef058bb797cd3f513a0) ) * Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78) ) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7) ) * Plat-6300 returning the balance of the relayer ([#78](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/78) ) ([e0ce8e0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/e0ce8e04f3950c094c9af3e3413d61cd7162c8e7) ) * Plat-6304 use Authorization header instead of x api key ([#94](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/94) ) ([34e8a81](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/34e8a813234ee6aaf2a6956f6dd45f82e47e7861) ) * Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83) ) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e) ) * Plat-6309 Fetching eip1559 prices ([#83](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/83) ) ([68d574f](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/68d574fcb159ae3b6502167a9bcf34bb1a56ea7e) ) * plat-6340 store private keys securely in memory ([#104](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/104) ) ([28c2fab](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/28c2fab84f3db6b9d971126cf917263da395c421) ) * PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98) ) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe) ) * PLAT-6350 - Sign EIP-1559 ([#98](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/98) ) ([673e420](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/673e4202f9d98bfd02512090fa3daacfa40831fe) ) * PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100) ) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8) ) * PLAT-6374 EIP-1559 default if network support it and not explicit false ([#100](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/100) ) ([c982dde](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c982ddefeba93381ac7d2c5e09f616a60820b8b8) ) * PLAT-6416 Use generics transaction factory ([#105](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/105) ) ([7b94662](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/7b946625af77c6aabd336d34646e9ae62ece3b6a) ) * plat-6433 add minimum length validations for config sensitive values ([#125](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/125) ) ([31453c5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/31453c5586ca4fef70e7ea0e2dcd0260a8a721a6) ) * Plat-6441 document upcoming work ([#131](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/131) ) ([377a8bb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/377a8bb57ff5b3b23abb58d1c3378489c40218cf) ) * PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117) ) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9) ) * PLAT-6442 - Abstraction and unit tests relayer domain ([#117](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/117) ) ([643194a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/643194acd9079ac3ac157e909f0b30199af8b0c9) ) * Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127) ) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938) ) * Plat-6457 Ignore utoipa ([#127](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/127) ) ([234854a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/234854afbf30a9a94fa3365f60f035e53e068938) ) * Plat-6459 create mermaid architecture diagram ([#126](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/126) ) ([3de147b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3de147b907c28d3e9a8a38a2d6b8cd665253c423) ) * plat-6476 Add support to collect transaction fee ([#135](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/135) ) ([4f4a07b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f4a07b2846d2980bbf09734602315702ded9dbe) ) * Plat-6479 added support for rpc custom endpoints ([#138](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/138) ) ([3df3d49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/3df3d49ec6a662698a90630811d717920b7cdf3b) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Pricing validation on receiving payload EVM ([#59](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/59) ) ([1206d42](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1206d4241dbda84bc861f501d322f6bd33234f0b) ) * Signer service ([#8](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/8) ) ([4f85b7b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4f85b7bf5b6aa83903ed8febdfe244d54e803642) ) * Speed support transaction ([#62](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/62) ) ([a572af6](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/a572af65ca4f664dce13e705eac37b56dee306fa) ) * Tx submissions and status mgmt ([#81](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/81) ) ([9f829f1](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9f829f1c59c4221c9cf38c6cb1ff36351a348cd1) ) * Update transaction status to mined/expired ([#85](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/85) ) ([8f5ee53](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8f5ee53bbe64d55ccf8015a1c8d203cf5e391f08) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-4) * Codecov changes and adjustments ([#113](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/113) ) ([6e62dcf](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/6e62dcf212a917421c7559566136c018e17c38f5) ) * Docs link ([#128](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/128) ) ([8263828](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/82638284cf13a4da376624362f5353b57365302a) ) * Docs path for crate ([#129](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/129) ) ([51cf556](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/51cf556411c9c1f79dbee7f4c3aa25df7fe2af49) ) * **docs:** replaced Monitor for Relayer ([2ff196b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/2ff196bf772668556210a895d4f83315e579577f) ) * Documentation name for antora ([#121](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/121) ) ([63c36f5](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/63c36f5393b1369a169c8617b20952bca30aef0c) ) * Environment variables ([#124](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/124) ) ([8d31131](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/8d31131c087a6d0a64ae2dadecb5ae395ad1b575) ) * Fix the codecov yaml syntax ([#108](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/108) ) ([ab9ab5b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/ab9ab5b0c9313d083cd47c71d7faade867c58deb) ) * Flaky logging tests ([#89](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/89) ) ([bc909cc](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/bc909cc336613bb5a191c562632278bd3c270b09) ) * Plat 6286 write tests for metrics and middleware functions ([#70](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/70) ) ([18124fb](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/18124fbbfbc26f300648a7a4050ebf9be72465ac) ) * PLAT-6426 Increase test coverage ([#118](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/118) ) ([1fa41f0](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/1fa41f0f225c9d515690738e960073396dce66ce) ) * PLAT-6478 create unit test for use of on relayers dotenv ([#139](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/139) ) ([509e166](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/509e1664518823ef3844e52e818707f3371ddbff) ) * plat-6480 allow transfering wrapped sol tokens ([#132](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/132) ) ([f04e66a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/f04e66a568c877c2a4c5c5378fb6017c2e41d2c6) ) ### [📚 Documentation](https://docs.openzeppelin.com/relayer/changelog#-documentation) * add cargo docs ([#75](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/75) ) ([c4dd8e3](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c4dd8e30525ccaeb563560bc2ef87cdcec5b1790) ) * Add testing instructions ([#107](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/107) ) ([c7c2ed7](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/c7c2ed7772d99b4b68ced9fbf8835fa9e46da5e1) ) * Adding configuration documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/48) ) ([929cc1b](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/929cc1bf1e0c6b3be872daf6654abe24eb79b907) ) * Fixing formatting and location of files ([#41](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/41) ) ([4d4f153](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/4d4f1530f466a5bd597d0338559ccb33815286f0) ) * Move README to a similar format to Monitor ([#39](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/39) ) ([5985339](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/59853396b3786a972ce7bbc793d4dbacc62fe6c0) ) * Readability improvements ([#133](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/133) ) ([9220727](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/9220727cc2b4349052c2d96a48c5d9c3012b38b9) ) * Small doc updates - policy field descriptions ([#51](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/51) ) ([cc83c49](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/cc83c496bbe2593018b03c414a864691c967ff41) ) * Small fixes and Antora docs improvements ([#40](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/40) ) ([655d16d](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/655d16dc658a74b7413ce785dee5b8e33cfb40f7) ) * TG link and other minor doc updates ([#116](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/116) ) ([fc68b6a](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/fc68b6afa844d2c2638d031fce44fcc514d59a7d) ) * Update API docs. Fix Dockerfiles ([#77](https://github.com/OpenZeppelin/openzeppelin-relayer/issues/77) ) ([0bd6bfe](https://github.com/OpenZeppelin/openzeppelin-relayer/commit/0bd6bfea69d60c1a7e9d6b8a690ba1a2d0e44b74) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/v0.1.0) [Plugins\ \ Previous Page](https://docs.openzeppelin.com/relayer/plugins) [Overview\ \ Next Page](https://docs.openzeppelin.com/monitor) ### On this page [](https://docs.openzeppelin.com/relayer/changelog#v110---2025-08-11) [v1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.1.0) - 2025-08-11[](https://docs.openzeppelin.com/relayer/changelog#110-2025-08-11) [1.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v1.0.0...v1.1.0) (2025-08-11)[🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features) [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes) [](https://docs.openzeppelin.com/relayer/changelog#v100---2025-06-30) [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v1.0.0) - 2025-06-30[](https://docs.openzeppelin.com/relayer/changelog#100-2025-06-30) [1.0.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.2.0...v1.0.0) (2025-06-30)[🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-1) [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-1) [](https://docs.openzeppelin.com/relayer/changelog#v020---2025-05-14) [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.2.0) - 2025-05-14[](https://docs.openzeppelin.com/relayer/changelog#020-2025-05-14) [0.2.0](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.1...v0.2.0) (2025-05-14)[🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-2) [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-2) [](https://docs.openzeppelin.com/relayer/changelog#v011---2025-04-08) [v0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.1) - 2025-04-08[](https://docs.openzeppelin.com/relayer/changelog#011-2025-04-08) [0.1.1](https://github.com/OpenZeppelin/openzeppelin-relayer/compare/v0.1.0...v0.1.1) (2025-04-08)[🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-3) [⚙️ Miscellaneous Chores](https://docs.openzeppelin.com/relayer/changelog#%EF%B8%8F-miscellaneous-chores) [](https://docs.openzeppelin.com/relayer/changelog#v010---2025-04-07) [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-relayer/releases/tag/v0.1.0) - 2025-04-07[0.1.0 (2025-04-07)](https://docs.openzeppelin.com/relayer/changelog#010-2025-04-07) [🚀 Features](https://docs.openzeppelin.com/relayer/changelog#-features-3) [🐛 Bug Fixes](https://docs.openzeppelin.com/relayer/changelog#-bug-fixes-4) [📚 Documentation](https://docs.openzeppelin.com/relayer/changelog#-documentation) --- # Contracts for Compact | OpenZeppelin Docs Contracts for Compact ===================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) **A library for secure smart contract development** written in Compact for [Midnight](https://midnight.network/) . This library consists of modules to build custom smart contracts. This repo contains highly experimental code. Expect rapid iteration. **Use at your own risk.** [Usage](https://docs.openzeppelin.com/contracts-compact#usage) --------------------------------------------------------------- Make sure you have [nvm](https://github.com/nvm-sh/nvm) and [yarn](https://yarnpkg.com/getting-started/install) installed on your machine. Follow Midnight's [Compact Developer Tools](https://docs.midnight.network/blog/compact-developer-tools) installation guide and confirm that `compact` is in the `PATH` env variable. $ compact compile --version Compactc version: 0.24.0 0.24.0 ### [Installation](https://docs.openzeppelin.com/contracts-compact#installation) Create a directory for your project. mkdir my-project cd my-project Initialize git and add OpenZeppelin Contracts for Compact as a submodule. git init && \ git submodule add https://github.com/OpenZeppelin/compact-contracts.git `cd` into it and then install dependencies and prepare the environment. nvm install && \ yarn && \ SKIP_ZK=true yarn compact ### [Write a custom contract using library modules](https://docs.openzeppelin.com/contracts-compact#write-a-custom-contract-using-library-modules) In the root of `my-project`, create a custom contract using OpenZeppelin Compact modules. Import the modules through `compact-contracts/node_modules/@openzeppelin-compact/contracts/...`. Import modules through `node_modules` rather than directly to avoid state conflicts between shared dependencies. Installing the library will be easier once it's available as an NPM package. // MyContract.compact pragma language_version >= 0.16.0; import CompactStandardLibrary; import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/access/Ownable" prefix Ownable_; import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/security/Pausable" prefix Pausable_; import "./compact-contracts/node_modules/@openzeppelin-compact/contracts/src/token/FungibleToken" prefix FungibleToken_; constructor( _name: Opaque<"string">, _symbol: Opaque<"string">, _decimals: Uint<8>, _recipient: Either, _amount: Uint<128>, _initOwner: Either, ) { Ownable_initialize(_initOwner); FungibleToken_initialize(_name, _symbol, _decimals); FungibleToken__mint(_recipient, _amount); } export circuit transfer( to: Either, value: Uint<128>, ): Boolean { Pausable_assertNotPaused(); return FungibleToken_transfer(to, value); } export circuit pause(): [] { Ownable_assertOnlyOwner(); Pausable__pause(); } export circuit unpause(): [] { Ownable_assertOnlyOwner(); Pausable__unpause(); } (...) ### [Compile the contract](https://docs.openzeppelin.com/contracts-compact#compile-the-contract) In the project root, compile the contract using Compact's dev tools. % compact compile MyContract.compact artifacts/MyContract Compiling 3 circuits: circuit "pause" (k=10, rows=125) circuit "transfer" (k=11, rows=1180) circuit "unpause" (k=10, rows=121) Overall progress [====================] 3/3 ### On this page [Usage](https://docs.openzeppelin.com/contracts-compact#usage) [Installation](https://docs.openzeppelin.com/contracts-compact#installation) [Write a custom contract using library modules](https://docs.openzeppelin.com/contracts-compact#write-a-custom-contract-using-library-modules) [Compile the contract](https://docs.openzeppelin.com/contracts-compact#compile-the-contract) --- # Testing Guide | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Testing Guide ============= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document provides information about testing OpenZeppelin Monitor, including running tests, generating coverage reports, and understanding the test structure. [Test Organization](https://docs.openzeppelin.com/monitor/testing#test-organization) ------------------------------------------------------------------------------------- The project includes comprehensive test suites organized into different categories: ### [Test Types](https://docs.openzeppelin.com/monitor/testing#test-types) * _**Unit Tests**_: Located within `src/` modules alongside the code they test * _**Integration Tests**_: Located in `tests/integration/` directory * _**Property-based Tests**_: Located in `tests/properties/` directory * _**Mock Implementations**_: Located in `tests/integration/mocks/` ### [Test Structure](https://docs.openzeppelin.com/monitor/testing#test-structure) tests/ ├── integration/ # Integration tests │ ├── blockchain/ # Blockchain client tests │ ├── blockwatcher/ # Block monitoring tests │ ├── filters/ # Filter logic tests │ ├── fixtures/ # Test data and configurations │ ├── mocks/ # Mock implementations │ └── ... ├── properties/ # Property-based tests │ ├── filters/ # Filter property tests │ ├── notifications/ # Notification property tests │ └── ... └── integration.rs # Integration test entry point [Running Tests](https://docs.openzeppelin.com/monitor/testing#running-tests) ----------------------------------------------------------------------------- ### [All Tests](https://docs.openzeppelin.com/monitor/testing#all-tests) Run the complete test suite: RUST_TEST_THREADS=1 cargo test `RUST_TEST_THREADS=1` is required to prevent test conflicts when accessing shared resources like configuration files or network connections. ### [Specific Test Categories](https://docs.openzeppelin.com/monitor/testing#specific-test-categories) _**Property-based Tests:**_ RUST_TEST_THREADS=1 cargo test properties _**Integration Tests:**_ RUST_TEST_THREADS=1 cargo test integration _**Unit Tests Only:**_ RUST_TEST_THREADS=1 cargo test --lib [Coverage Reports](https://docs.openzeppelin.com/monitor/testing#coverage-reports) ----------------------------------------------------------------------------------- ### [Prerequisites](https://docs.openzeppelin.com/monitor/testing#prerequisites) Install the coverage tool: rustup component add llvm-tools-preview cargo install cargo-llvm-cov ### [Generating Coverage](https://docs.openzeppelin.com/monitor/testing#generating-coverage) _**HTML Coverage Report:**_ RUST_TEST_THREADS=1 cargo +stable llvm-cov --html --open This generates an HTML report in `target/llvm-cov/html/` and opens it in your browser. _**Terminal Coverage Report:**_ RUST_TEST_THREADS=1 cargo +stable llvm-cov [Troubleshooting](https://docs.openzeppelin.com/monitor/testing#troubleshooting) --------------------------------------------------------------------------------- ### [Common Issues](https://docs.openzeppelin.com/monitor/testing#common-issues) _**Tests hanging or timing out:**_ * Ensure `RUST_TEST_THREADS=1` is set * Verify mock setups are correct _**Coverage tool not found:**_ * Install with `cargo install cargo-llvm-cov` * Add component with `rustup component add llvm-tools-preview` _**Permission errors:**_ * Ensure test directories are writable * Check file permissions on test fixtures ### [Debug Output](https://docs.openzeppelin.com/monitor/testing#debug-output) Enable debug logging for tests: RUST_LOG=debug RUST_TEST_THREADS=1 cargo test -- --nocapture [Contributing Tests](https://docs.openzeppelin.com/monitor/testing#contributing-tests) --------------------------------------------------------------------------------------- When contributing new features: 1. _**Add comprehensive tests**_ for new functionality 2. _**Ensure all tests pass**_ locally before submitting 3. _**Include both unit and integration tests**_ where appropriate 4. _**Update test documentation**_ if adding new test patterns 5. _**Maintain or improve code coverage**_ For more information about contributing, see the project’s contributing guidelines. [Error Handling\ \ Previous Page](https://docs.openzeppelin.com/monitor/error) [Contribution guidelines\ \ Next Page](https://docs.openzeppelin.com/monitor/contribution) ### On this page [Test Organization](https://docs.openzeppelin.com/monitor/testing#test-organization) [Test Types](https://docs.openzeppelin.com/monitor/testing#test-types) [Test Structure](https://docs.openzeppelin.com/monitor/testing#test-structure) [Running Tests](https://docs.openzeppelin.com/monitor/testing#running-tests) [All Tests](https://docs.openzeppelin.com/monitor/testing#all-tests) [Specific Test Categories](https://docs.openzeppelin.com/monitor/testing#specific-test-categories) [Coverage Reports](https://docs.openzeppelin.com/monitor/testing#coverage-reports) [Prerequisites](https://docs.openzeppelin.com/monitor/testing#prerequisites) [Generating Coverage](https://docs.openzeppelin.com/monitor/testing#generating-coverage) [Troubleshooting](https://docs.openzeppelin.com/monitor/testing#troubleshooting) [Common Issues](https://docs.openzeppelin.com/monitor/testing#common-issues) [Debug Output](https://docs.openzeppelin.com/monitor/testing#debug-output) [Contributing Tests](https://docs.openzeppelin.com/monitor/testing#contributing-tests) --- # Project Structure | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Project Structure ================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document describes the project structure and organization of the OpenZeppelin Monitor codebase, including the source code layout, configuration files, and development resources. [Project Layout](https://docs.openzeppelin.com/monitor/project-structure#project-layout) ----------------------------------------------------------------------------------------- The project follows a standard Rust project layout with additional directories for configuration, documentation, and operational resources: openzeppelin-monitor/ ├── src/ # Source code │ ├── bootstrap/ # Bootstrap functions for the application │ ├── models/ # Data structures and types │ ├── repositories/ # Configuration storage │ ├── services/ # Core business logic │ ├── utils/ # Helper functions │ ├── config/ # Configuration files ├── tests/ # Integration and property-based tests ├── data/ # Runtime data storage ├── docs/ # Documentation ├── scripts/ # Utility scripts ├── cmd/ # Metrics and monitoring ├── examples/ # Example configuration files └── ... other root files (Cargo.toml, README.md, etc.) [Source Code Organization](https://docs.openzeppelin.com/monitor/project-structure#source-code-organization) ------------------------------------------------------------------------------------------------------------- ### [`src/` Directory](https://docs.openzeppelin.com/monitor/project-structure#src-directory) The main source code directory contains the core implementation files organized into several modules: #### [`bootstrap/`](https://docs.openzeppelin.com/monitor/project-structure#bootstrap) Application initialization and setup for `main.rs`: * Handles service initialization and dependency injection * Manages the startup sequence and service lifecycle #### [`models/`](https://docs.openzeppelin.com/monitor/project-structure#models) Core data structures and types: * `blockchain/`: Platform-specific implementations * `evm/`: Ethereum Virtual Machine specific types * `stellar/`: Stellar blockchain specific types * `config/`: Configuration loading and validation * `core/`: Core domain models * `security/`: Security and secret management #### [`repositories/`](https://docs.openzeppelin.com/monitor/project-structure#repositories) Configuration storage: * Handles loading and validating configuration files * Provides storage interfaces for monitors, networks, and triggers * Implements validation of configuration references #### [`services/`](https://docs.openzeppelin.com/monitor/project-structure#services) Core business logic: * `blockchain/`: Blockchain client interfaces * `transports/`: Transport clients * `evm/`: Ethereum Virtual Machine transport client * `stellar/`: Stellar transport client * `clients/`: Client implementations * `evm/`: Ethereum Virtual Machine client * `stellar/`: Stellar client * `blockwatcher/`: Block monitoring and processing * `filter/`: Transaction and event filtering * `filters/`: Filter implementations * `evm/`: Ethereum Virtual Machine filter * `stellar/`: Stellar filter * `notification/`: Alert handling * `trigger/`: Trigger evaluation and execution * `script/`: Script execution utilities #### [`utils/`](https://docs.openzeppelin.com/monitor/project-structure#utils) Helper functions: * `cron_utils`: Cron schedule utilities * `expression`: Expression evaluation * `logging/`: Logging utilities * `macros/`: Macros for common functionality * `metrics/`: Metrics utilities * `monitor/`: Monitor configuration test utilities * `tests/`: Contains test utilities and helper functions * `builders/`: Test builder patterns implementing fluent interfaces for creating test fixtures * `evm/`: Builder implementations specific to Ethereum Virtual Machine (EVM) testing * `stellar/`: Builder implementations specific to Stellar blockchain testing [Configuration and Data](https://docs.openzeppelin.com/monitor/project-structure#configuration-and-data) --------------------------------------------------------------------------------------------------------- ### [`config/` Directory](https://docs.openzeppelin.com/monitor/project-structure#config-directory) Contains JSON configuration files for: * _**Network configurations**_ (`networks/`) * Connection details for blockchain networks * RPC endpoints and network parameters * _**Monitor configurations**_ (`monitors/`) * Monitoring rules and conditions * Network and trigger references * _**Trigger configurations**_ (`triggers/`) * Notification settings * Script definitions * _**Filter configurations**_ (`filters/`) * Match filter scripts The `examples/config/` directory contains example JSON configuration files for each (network, monitor, trigger and filters). ### [`data/` Directory](https://docs.openzeppelin.com/monitor/project-structure#data-directory) Runtime data storage: * Block processing state * Operational data * Temporary files The `data/`, `logs/` and `config/` directories are gitignored except for example files. These directories are mounted to persist the configs and runtime data. [Examples and Resources](https://docs.openzeppelin.com/monitor/project-structure#examples-and-resources) --------------------------------------------------------------------------------------------------------- ### [`examples/` Directory](https://docs.openzeppelin.com/monitor/project-structure#examples-directory) Provides practical examples and sample configurations to help users get started: * Demonstrates typical service configurations for various networks * Acts as a quick-start guide for customizing the monitor * Serves as a reference for best practices in configuration [Metrics and Monitoring](https://docs.openzeppelin.com/monitor/project-structure#metrics-and-monitoring) --------------------------------------------------------------------------------------------------------- ### [`cmd/prometheus/` Directory](https://docs.openzeppelin.com/monitor/project-structure#cmdprometheus-directory) Prometheus exporters and monitoring infrastructure: * `dashboards/`: Grafana dashboards * `datasources/`: Prometheus datasources * `prometheus.yml`: Prometheus configuration * `grafana.ini`: Grafana configuration [Testing and Documentation](https://docs.openzeppelin.com/monitor/project-structure#testing-and-documentation) --------------------------------------------------------------------------------------------------------------- ### [`tests/` Directory](https://docs.openzeppelin.com/monitor/project-structure#tests-directory) Contains comprehensive test suites: * Integration tests * Property-based tests * Mock implementations * Test utilities and helpers ### [`docs/` Directory](https://docs.openzeppelin.com/monitor/project-structure#docs-directory) Project documentation: * User guides * API documentation * Configuration examples * Architecture diagrams ### [`scripts/` Directory](https://docs.openzeppelin.com/monitor/project-structure#scripts-directory) Utility scripts for: * Development workflows * Documentation generation * Build processes * Deployment helpers [Development Tools](https://docs.openzeppelin.com/monitor/project-structure#development-tools) ----------------------------------------------------------------------------------------------- ### [Pre-commit Hooks](https://docs.openzeppelin.com/monitor/project-structure#pre-commit-hooks) Located in the project root: * Code formatting checks * Linting rules * Commit message validation ### [Build Configuration](https://docs.openzeppelin.com/monitor/project-structure#build-configuration) Core build files: * `Cargo.toml`: Project dependencies and metadata * `rustfmt.toml`: Code formatting rules * `rust-toolchain.toml`: Rust version and components [Docker Support](https://docs.openzeppelin.com/monitor/project-structure#docker-support) ----------------------------------------------------------------------------------------- The project includes Docker configurations for different environments: * `Dockerfile.development`: Development container setup * `Dockerfile.production`: Production-ready container * Before running the docker compose set your env variables in `.env` according to your needs For detailed information about running the monitor in containers, see the Docker deployment [section](https://docs.openzeppelin.com/monitor#docker-installation) in the user documentation. [Architecture Guide\ \ Previous Page](https://docs.openzeppelin.com/monitor/architecture) [RPC Client\ \ Next Page](https://docs.openzeppelin.com/monitor/rpc) ### On this page [Project Layout](https://docs.openzeppelin.com/monitor/project-structure#project-layout) [Source Code Organization](https://docs.openzeppelin.com/monitor/project-structure#source-code-organization) [`src/` Directory](https://docs.openzeppelin.com/monitor/project-structure#src-directory) [`bootstrap/`](https://docs.openzeppelin.com/monitor/project-structure#bootstrap) [`models/`](https://docs.openzeppelin.com/monitor/project-structure#models) [`repositories/`](https://docs.openzeppelin.com/monitor/project-structure#repositories) [`services/`](https://docs.openzeppelin.com/monitor/project-structure#services) [`utils/`](https://docs.openzeppelin.com/monitor/project-structure#utils) [Configuration and Data](https://docs.openzeppelin.com/monitor/project-structure#configuration-and-data) [`config/` Directory](https://docs.openzeppelin.com/monitor/project-structure#config-directory) [`data/` Directory](https://docs.openzeppelin.com/monitor/project-structure#data-directory) [Examples and Resources](https://docs.openzeppelin.com/monitor/project-structure#examples-and-resources) [`examples/` Directory](https://docs.openzeppelin.com/monitor/project-structure#examples-directory) [Metrics and Monitoring](https://docs.openzeppelin.com/monitor/project-structure#metrics-and-monitoring) [`cmd/prometheus/` Directory](https://docs.openzeppelin.com/monitor/project-structure#cmdprometheus-directory) [Testing and Documentation](https://docs.openzeppelin.com/monitor/project-structure#testing-and-documentation) [`tests/` Directory](https://docs.openzeppelin.com/monitor/project-structure#tests-directory) [`docs/` Directory](https://docs.openzeppelin.com/monitor/project-structure#docs-directory) [`scripts/` Directory](https://docs.openzeppelin.com/monitor/project-structure#scripts-directory) [Development Tools](https://docs.openzeppelin.com/monitor/project-structure#development-tools) [Pre-commit Hooks](https://docs.openzeppelin.com/monitor/project-structure#pre-commit-hooks) [Build Configuration](https://docs.openzeppelin.com/monitor/project-structure#build-configuration) [Docker Support](https://docs.openzeppelin.com/monitor/project-structure#docker-support) --- # Architecture Guide | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Architecture Guide ================== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This document describes the high-level architecture of OpenZeppelin Monitor, including the core components, their interactions, and the overall system design. It provides a technical overview of how the service processes blockchain data and triggers notifications based on configurable conditions. [System Overview](https://docs.openzeppelin.com/monitor/architecture#system-overview) -------------------------------------------------------------------------------------- OpenZeppelin Monitor is organized as a data processing pipeline that spans from blockchain data collection to notification delivery. The system follows a modular architecture with distinct components for each step in the monitoring process, designed for scalability and extensibility. ### [High-Level Architecture](https://docs.openzeppelin.com/monitor/architecture#high-level-architecture) The diagram below shows the core processing pipeline of OpenZeppelin Monitor, from blockchain networks and configuration through to notification channels: [Component Architecture](https://docs.openzeppelin.com/monitor/architecture#component-architecture) ---------------------------------------------------------------------------------------------------- The system consists of several core services that are initialized at startup and work together to process blockchain data and trigger notifications. The service initialization and dependencies are managed through the bootstrap module. ### [Service Initialization Flow](https://docs.openzeppelin.com/monitor/architecture#service-initialization-flow) ### [Core Components](https://docs.openzeppelin.com/monitor/architecture#core-components) #### [Block Processing Components](https://docs.openzeppelin.com/monitor/architecture#block-processing-components) * _**BlockWatcherService**_: Orchestrates the block monitoring process by polling blockchain networks for new blocks and coordinating the processing pipeline. * _**BlockTracker**_: Tracks processed block numbers to prevent duplicate processing and ensure data consistency across service restarts. * _**BlockStorage**_: Persists block processing state for recovery and maintains the last processed block number for each network. #### [Client Layer Components](https://docs.openzeppelin.com/monitor/architecture#client-layer-components) * _**ClientPool**_: Manages blockchain client instances and provides network connectivity with connection pooling and failover capabilities. * _**EVMClient**_: Handles communication with Ethereum Virtual Machine compatible networks (Ethereum, Polygon, BSC, etc.). * _**StellarClient**_: Manages connections to Stellar blockchain networks with protocol-specific optimizations. #### [Processing Pipeline Components](https://docs.openzeppelin.com/monitor/architecture#processing-pipeline-components) * _**FilterService**_: Applies monitor filters to blockchain data, evaluating conditions and match expressions to identify relevant transactions and events. * _**TriggerExecutionService**_: Executes triggers based on matched monitor conditions, evaluating trigger logic and preparing notification payloads. * _**NotificationService**_: Delivers notifications through configured channels (Slack, Email, Discord, Telegram, Webhooks, Scripts). #### [Configuration Management Components](https://docs.openzeppelin.com/monitor/architecture#configuration-management-components) * _**MonitorService**_: Manages monitor configurations and provides access to active monitors with validation and lifecycle management. * _**NetworkService**_: Manages network configurations and provides network details for client connections and monitoring operations. * _**TriggerService**_: Manages trigger configurations and provides trigger details for notification execution. ### [Service Responsibilities](https://docs.openzeppelin.com/monitor/architecture#service-responsibilities) The following table describes the key responsibilities of each service in the OpenZeppelin Monitor architecture: | Service | Responsibility | | --- | --- | | **MonitorService** | Manages monitor configurations and provides access to active monitors | | **NetworkService** | Manages network configurations and provides network details | | **TriggerService** | Manages trigger configurations and provides trigger details | | **FilterService** | Filters blockchain data based on monitor conditions and match expressions | | **TriggerExecutionService** | Executes triggers based on matched monitor conditions | | **NotificationService** | Delivers notifications through configured channels | | **BlockWatcherService** | Polls blockchain networks for new blocks and coordinates processing | | **BlockTracker** | Tracks processed block numbers to prevent duplicate processing | | **BlockStorage** | Persists block processing state for recovery | | **ClientPool** | Manages blockchain client instances and provides network connectivity | ### [Block Processing Workflow](https://docs.openzeppelin.com/monitor/architecture#block-processing-workflow) The following _runtime flow_ illustrates how data moves through the system, from blockchain networks to notification channels. This sequence represents the core monitoring loop that executes for each configured network. ### [Data Flow Architecture](https://docs.openzeppelin.com/monitor/architecture#data-flow-architecture) #### [1\. Block Discovery Phase](https://docs.openzeppelin.com/monitor/architecture#1-block-discovery-phase) The `BlockWatcherService` initiates the monitoring cycle by: * Retrieving the last processed block number from `BlockStorage` * Querying the blockchain for the latest block number * Calculating the range of new blocks to process #### [2\. Data Retrieval Phase](https://docs.openzeppelin.com/monitor/architecture#2-data-retrieval-phase) The `BlockchainClient` fetches block data: * Connects to the appropriate blockchain network via RPC * Retrieves full block data including transactions and events * Handles network-specific data formats and protocols #### [3\. Filtering Phase](https://docs.openzeppelin.com/monitor/architecture#3-filtering-phase) The `FilterService` processes each block: * Applies monitor-specific filters to transactions and events * Evaluates match expressions and conditions * Identifies relevant data that matches monitoring criteria #### [4\. Trigger Evaluation Phase](https://docs.openzeppelin.com/monitor/architecture#4-trigger-evaluation-phase) The `TriggerExecutionService` processes matches: * Evaluates trigger conditions for matched data * Prepares notification payloads with relevant context * Determines which notification channels to activate #### [5\. Notification Delivery Phase](https://docs.openzeppelin.com/monitor/architecture#5-notification-delivery-phase) The `NotificationService` delivers alerts: * Formats messages for each notification channel * Handles channel-specific delivery protocols * Manages delivery retries and error handling #### [6\. State Persistence Phase](https://docs.openzeppelin.com/monitor/architecture#6-state-persistence-phase) The `BlockStorage` updates processing state: * Records the latest processed block number * Ensures data consistency for recovery scenarios * Maintains processing history for debugging ### [Error Handling and Resilience](https://docs.openzeppelin.com/monitor/architecture#error-handling-and-resilience) The architecture includes several resilience mechanisms: * _**Connection Pooling**_: The `ClientPool` manages multiple connections to prevent single points of failure * _**State Recovery**_: `BlockStorage` enables the service to resume from the last known good state after restarts * _**Retry Logic**_: Notification delivery includes configurable retry mechanisms for transient failures * _**Graceful Degradation**_: Individual component failures don’t cascade to the entire system For detailed information about RPC logic and network communication, see the [RPC section](https://docs.openzeppelin.com/monitor/rpc) . [Configuration Architecture](https://docs.openzeppelin.com/monitor/architecture#configuration-architecture) ------------------------------------------------------------------------------------------------------------ The system uses a JSON-based configuration system organized into distinct categories: ### [Configuration Categories](https://docs.openzeppelin.com/monitor/architecture#configuration-categories) * _**Network Configurations**_: Define blockchain network connections, RPC endpoints, and network parameters * _**Monitor Configurations**_: Specify monitoring rules, conditions, and network/trigger references * _**Trigger Configurations**_: Define notification settings and script definitions * _**Filter Configurations**_: Contain match filter scripts for data filtering ### [Configuration Validation](https://docs.openzeppelin.com/monitor/architecture#configuration-validation) The system implements comprehensive validation: * Cross-reference validation between monitors, networks, and triggers * Schema validation for all configuration files * Runtime validation of configuration references during service startup For configuration examples and best practices, see the [Configuration Guidelines](https://docs.openzeppelin.com/monitor#configuration-guidelines) section in the user documentation. [Extensibility Points](https://docs.openzeppelin.com/monitor/architecture#extensibility-points) ------------------------------------------------------------------------------------------------ The architecture is designed for extensibility in several key areas: ### [Blockchain Support](https://docs.openzeppelin.com/monitor/architecture#blockchain-support) * _**Client Layer**_: New blockchain protocols can be added by implementing the `BlockchainClient` trait * _**Transport Layer**_: Protocol-specific transport clients handle network communication details * _**Filter Layer**_: Chain-specific filters process protocol-dependent data formats ### [Notification Channels](https://docs.openzeppelin.com/monitor/architecture#notification-channels) * _**Channel Plugins**_: New notification channels can be added by implementing the notification interface * _**Script Support**_: Custom notification logic can be implemented using Python, JavaScript, or Bash scripts ### [Monitoring Logic](https://docs.openzeppelin.com/monitor/architecture#monitoring-logic) * _**Expression Engine**_: Flexible expression evaluation for complex monitoring conditions * _**Script Triggers**_: Custom trigger logic can be implemented using supported scripting languages [Performance Considerations](https://docs.openzeppelin.com/monitor/architecture#performance-considerations) ------------------------------------------------------------------------------------------------------------ The architecture is optimized for: * _**Concurrent Processing**_: Multiple networks can be monitored simultaneously * _**Efficient Block Processing**_: Batch processing of blocks to minimize RPC calls * _**Memory Management**_: Streaming processing of large blocks to prevent memory issues * _**Connection Reuse**_: Client pooling reduces connection overhead [Security Architecture](https://docs.openzeppelin.com/monitor/architecture#security-architecture) -------------------------------------------------------------------------------------------------- The system implements several security measures: * _**Secure Protocols**_: Support for HTTPS/WSS * _**Secret Management**_: Secure handling of API keys and sensitive configuration data * _**Input Validation**_: Comprehensive validation of all external inputs and configurations [Related Documentation](https://docs.openzeppelin.com/monitor/architecture#related-documentation) -------------------------------------------------------------------------------------------------- For detailed information about the project structure, source code organization, and development resources, see the [Project Structure](https://docs.openzeppelin.com/monitor/project-structure) guide. For information about RPC logic and network communication, see the [RPC section](https://docs.openzeppelin.com/monitor/rpc) . For configuration examples and best practices, see the [Configuration Guidelines](https://docs.openzeppelin.com/monitor#configuration-guidelines) section in the user documentation. ### On this page [System Overview](https://docs.openzeppelin.com/monitor/architecture#system-overview) [High-Level Architecture](https://docs.openzeppelin.com/monitor/architecture#high-level-architecture) [Component Architecture](https://docs.openzeppelin.com/monitor/architecture#component-architecture) [Service Initialization Flow](https://docs.openzeppelin.com/monitor/architecture#service-initialization-flow) [Core Components](https://docs.openzeppelin.com/monitor/architecture#core-components) [Block Processing Components](https://docs.openzeppelin.com/monitor/architecture#block-processing-components) [Client Layer Components](https://docs.openzeppelin.com/monitor/architecture#client-layer-components) [Processing Pipeline Components](https://docs.openzeppelin.com/monitor/architecture#processing-pipeline-components) [Configuration Management Components](https://docs.openzeppelin.com/monitor/architecture#configuration-management-components) [Service Responsibilities](https://docs.openzeppelin.com/monitor/architecture#service-responsibilities) [Block Processing Workflow](https://docs.openzeppelin.com/monitor/architecture#block-processing-workflow) [Data Flow Architecture](https://docs.openzeppelin.com/monitor/architecture#data-flow-architecture) [1\. Block Discovery Phase](https://docs.openzeppelin.com/monitor/architecture#1-block-discovery-phase) [2\. Data Retrieval Phase](https://docs.openzeppelin.com/monitor/architecture#2-data-retrieval-phase) [3\. Filtering Phase](https://docs.openzeppelin.com/monitor/architecture#3-filtering-phase) [4\. Trigger Evaluation Phase](https://docs.openzeppelin.com/monitor/architecture#4-trigger-evaluation-phase) [5\. Notification Delivery Phase](https://docs.openzeppelin.com/monitor/architecture#5-notification-delivery-phase) [6\. State Persistence Phase](https://docs.openzeppelin.com/monitor/architecture#6-state-persistence-phase) [Error Handling and Resilience](https://docs.openzeppelin.com/monitor/architecture#error-handling-and-resilience) [Configuration Architecture](https://docs.openzeppelin.com/monitor/architecture#configuration-architecture) [Configuration Categories](https://docs.openzeppelin.com/monitor/architecture#configuration-categories) [Configuration Validation](https://docs.openzeppelin.com/monitor/architecture#configuration-validation) [Extensibility Points](https://docs.openzeppelin.com/monitor/architecture#extensibility-points) [Blockchain Support](https://docs.openzeppelin.com/monitor/architecture#blockchain-support) [Notification Channels](https://docs.openzeppelin.com/monitor/architecture#notification-channels) [Monitoring Logic](https://docs.openzeppelin.com/monitor/architecture#monitoring-logic) [Performance Considerations](https://docs.openzeppelin.com/monitor/architecture#performance-considerations) [Security Architecture](https://docs.openzeppelin.com/monitor/architecture#security-architecture) [Related Documentation](https://docs.openzeppelin.com/monitor/architecture#related-documentation) --- # Multisig Account | OpenZeppelin Docs OpenZeppelin Contracts[Account Abstraction](https://docs.openzeppelin.com/contracts/5.x/account-abstraction) [Accounts](https://docs.openzeppelin.com/contracts/5.x/accounts) Multisig Account ================ Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) A multi-signature (multisig) account is a smart account that requires multiple authorized signers to approve operations before execution. Unlike traditional accounts controlled by a single private key, multisigs distribute control among multiple parties, eliminating single points of failure. For example, a 2-of-3 multisig requires signatures from at least 2 out of 3 possible signers. Popular implementations like [Safe](https://safe.global/) (formerly Gnosis Safe) have become the standard for securing valuable assets. Multisigs provide enhanced security through collective authorization, customizable controls for ownership and thresholds, and the ability to rotate signers without changing the account address. [Beyond Standard Signature Verification](https://docs.openzeppelin.com/contracts/5.x/multisig#beyond-standard-signature-verification) -------------------------------------------------------------------------------------------------------------------------------------- As discussed in the [accounts section](https://docs.openzeppelin.com/contracts/5.x/accounts#signature-validation) , the standard approach for smart contracts to verify signatures is [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) , which defines an `isValidSignature(hash, signature)`. However, it is limited in two important ways: 1. It assumes the signer has an EVM address 2. It treats the signer as a single identity This becomes problematic when implementing multisig accounts where: * You may want to use signers that don’t have EVM addresses (like keys from hardware devices) * Each signer needs to be individually verified rather than treated as a collective identity * You need a threshold system to determine when enough valid signatures are present The [SignatureChecker](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol) library is useful for verifying EOA and ERC-1271 signatures, but it’s not designed for more complex arrangements like threshold-based multisigs. [ERC-7913 Signers](https://docs.openzeppelin.com/contracts/5.x/multisig#erc-7913-signers) ------------------------------------------------------------------------------------------ [ERC-7913](https://eips.ethereum.org/EIPS/eip-7913) extends the concept of signer representation to include keys that don’t have EVM addresses, addressing this limitation. OpenZeppelin implements this standard through three contracts: ### [SignerERC7913](https://docs.openzeppelin.com/contracts/5.x/multisig#signererc7913) The [`SignerERC7913`](https://docs.openzeppelin.com/contracts/5.x/api/utils#SignerERC7913) contract allows a single ERC-7913 formatted signer to control an account. The signer is represented as a `bytes` object that concatenates a verifier address and a key: `verifier || key`. // contracts/MyAccountERC7913.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {SignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/SignerERC7913.sol"; contract MyAccountERC7913 is Account, SignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { constructor() EIP712("MyAccount7913", "1") {} function initialize(bytes memory signer) public initializer { _setSigner(signer); } function setSigner(bytes memory signer) public onlyEntryPointOrSelf { _setSigner(signer); } /// @dev Allows the entry point as an authorized executor. function _erc7821AuthorizedExecutor( address caller, bytes32 mode, bytes calldata executionData ) internal view virtual override returns (bool) { return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); } } Leaving an account uninitialized may leave it unusable since no public key was associated with it. ### [MultiSignerERC7913](https://docs.openzeppelin.com/contracts/5.x/multisig#multisignererc7913) The [`MultiSignerERC7913`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913) contract extends this concept to support multiple signers with a threshold-based signature verification system. // contracts/MyAccountMultiSigner.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {MultiSignerERC7913} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913.sol"; contract MyAccountMultiSigner is Account, MultiSignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { constructor() EIP712("MyAccountMultiSigner", "1") {} function initialize(bytes[] memory signers, uint256 threshold) public initializer { _addSigners(signers); _setThreshold(threshold); } function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _addSigners(signers); } function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _removeSigners(signers); } function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { _setThreshold(threshold); } /// @dev Allows the entry point as an authorized executor. function _erc7821AuthorizedExecutor( address caller, bytes32 mode, bytes calldata executionData ) internal view virtual override returns (bool) { return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); } } This implementation is ideal for standard multisig setups where each signer has equal authority, and a fixed number of approvals is required. The `MultiSignerERC7913` contract provides several key features for managing multi-signature accounts. It maintains a set of authorized signers and implements a threshold-based system that requires a minimum number of signatures to approve operations. The contract includes an internal interface for managing signers, allowing for the addition and removal of authorized parties. `MultiSignerERC7913` safeguards to ensure that the threshold remains achievable based on the current number of active signers, preventing situations where operations could become impossible to execute. The contract also provides public functions for querying signer information: [`isSigner(bytes memory signer)`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913-isSigner-bytes-) to check if a given signer is authorized, [`getSigners(uint64 start, uint64 end)`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913-getSigners-uint64-uint64-) to retrieve a paginated list of authorized signers, and [`getSignerCount()`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913-getSignerCount) to get the total number of signers. These functions are useful when validating signatures, implementing customized access control logic, or building user interfaces that need to display signer information. ### [MultiSignerERC7913Weighted](https://docs.openzeppelin.com/contracts/5.x/multisig#multisignererc7913weighted) For more sophisticated governance structures, the [`MultiSignerERC7913Weighted`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913Weighted) contract extends `MultiSignerERC7913` by assigning different weights to each signer. // contracts/MyAccountMultiSignerWeighted.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Account} from "@openzeppelin/community-contracts/account/Account.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ERC7739} from "@openzeppelin/community-contracts/utils/cryptography/signers/ERC7739.sol"; import {ERC7821} from "@openzeppelin/community-contracts/account/extensions/ERC7821.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {MultiSignerERC7913Weighted} from "@openzeppelin/community-contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol"; contract MyAccountMultiSignerWeighted is Account, MultiSignerERC7913Weighted, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { constructor() EIP712("MyAccountMultiSignerWeighted", "1") {} function initialize(bytes[] memory signers, uint256[] memory weights, uint256 threshold) public initializer { _addSigners(signers); _setSignerWeights(signers, weights); _setThreshold(threshold); } function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _addSigners(signers); } function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _removeSigners(signers); } function setThreshold(uint256 threshold) public onlyEntryPointOrSelf { _setThreshold(threshold); } function setSignerWeights(bytes[] memory signers, uint256[] memory weights) public onlyEntryPointOrSelf { _setSignerWeights(signers, weights); } /// @dev Allows the entry point as an authorized executor. function _erc7821AuthorizedExecutor( address caller, bytes32 mode, bytes calldata executionData ) internal view virtual override returns (bool) { return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); } } This implementation is perfect for scenarios where different signers should have varying levels of authority, such as: * Board members with different voting powers * Organizational structures with hierarchical decision-making * Hybrid governance systems combining core team and community members * Execution setups like "social recovery" where you trust particular guardians more than others The `MultiSignerERC7913Weighted` contract extends `MultiSignerERC7913` with a weighting system. Each signer can have a custom weight, and operations require the total weight of signing participants to meet or exceed the threshold. Signers without explicit weights default to a weight of 1. When setting up a weighted multisig, ensure the threshold value 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 at least two signers (e.g., one with weight 1 and one with weight 3). [Setting Up a Multisig Account](https://docs.openzeppelin.com/contracts/5.x/multisig#setting-up-a-multisig-account) -------------------------------------------------------------------------------------------------------------------- To create a multisig account, you need to: 1. Define your signers 2. Determine your threshold 3. Initialize your account with these parameters The example below demonstrates setting up a 2-of-3 multisig account with different types of signers: // Example setup code function setupMultisigAccount() external { // Create signers using different types of keys bytes memory ecdsaSigner = alice; // EOA address (20 bytes) // P256 signer with format: verifier || pubKey bytes memory p256Signer = abi.encodePacked( p256Verifier, bobP256PublicKeyX, bobP256PublicKeyY ); // RSA signer with format: verifier || pubKey bytes memory rsaSigner = abi.encodePacked( rsaVerifier, abi.encode(charlieRSAPublicKeyE, charlieRSAPublicKeyN) ); // Create array of signers bytes[] memory signers = new bytes[](3); signers[0] = ecdsaSigner; signers[1] = p256Signer; signers[2] = rsaSigner; // Set threshold to 2 (2-of-3 multisig) uint256 threshold = 2; // Initialize the account myMultisigAccount.initialize(signers, threshold); } For a weighted multisig, you would also specify weights: // Example setup for weighted multisig function setupWeightedMultisigAccount() external { // Create array of signers (same as above) bytes[] memory signers = new bytes[](3); signers[0] = ecdsaSigner; signers[1] = p256Signer; signers[2] = rsaSigner; // Assign weights to signers (Alice:1, Bob:2, Charlie:3) uint256[] memory weights = new uint256[](3); weights[0] = 1; weights[1] = 2; weights[2] = 3; // Set threshold to 4 (requires at least Bob+Charlie or all three) uint256 threshold = 4; // Initialize the weighted account myWeightedMultisigAccount.initialize(signers, weights, threshold); } The [`_validateReachableThreshold`](https://docs.openzeppelin.com/contracts/5.x/api/utils/cryptography#MultiSignerERC7913-_validateReachableThreshold--) function ensures that the sum of weights for all active signers meets or exceeds the threshold. Any customization built on top of the multisigner contracts must ensure the threshold is always reachable. For multisig accounts, the signature is a complex structure that contains both the signers and their individual signatures. The format follows ERC-7913’s specification and must be properly encoded. ### [Signature Format](https://docs.openzeppelin.com/contracts/5.x/multisig#signature-format) The multisig signature is encoded as: abi.encode( bytes[] signers, // Array of signers sorted by `keccak256` bytes[] signatures // Array of signatures corresponding to each signer ) Where: * `signers` is an array of the signers participating in this particular signature * `signatures` is an array of the individual signatures corresponding to each signer To avoid duplicate signers, the contract uses `keccak256` to generate a unique id for each signer. When providing a multisignature, the `signers` array should be sorted in ascending order by `keccak256`, and the `signatures` array must match the order of their corresponding signers. [EOA Delegation\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/eoa-delegation) [Overview\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/tokens) ### On this page [Beyond Standard Signature Verification](https://docs.openzeppelin.com/contracts/5.x/multisig#beyond-standard-signature-verification) [ERC-7913 Signers](https://docs.openzeppelin.com/contracts/5.x/multisig#erc-7913-signers) [SignerERC7913](https://docs.openzeppelin.com/contracts/5.x/multisig#signererc7913) [MultiSignerERC7913](https://docs.openzeppelin.com/contracts/5.x/multisig#multisignererc7913) [MultiSignerERC7913Weighted](https://docs.openzeppelin.com/contracts/5.x/multisig#multisignererc7913weighted) [Setting Up a Multisig Account](https://docs.openzeppelin.com/contracts/5.x/multisig#setting-up-a-multisig-account) [Signature Format](https://docs.openzeppelin.com/contracts/5.x/multisig#signature-format) --- # Quick Start Guide | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Quick Start Guide ================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) OpenZeppelin Monitor is a powerful tool for monitoring blockchain events and transactions. This guide will help you get up and running quickly with practical examples for both EVM and Stellar networks. [What You'll Learn](https://docs.openzeppelin.com/monitor/quickstart#what-youll-learn) --------------------------------------------------------------------------------------- * How to set up OpenZeppelin Monitor locally or with Docker * How to configure monitoring for USDC transfers on Ethereum * How to monitor DEX swaps on Stellar * How to set up notifications via Slack and email [Prerequisites](https://docs.openzeppelin.com/monitor/quickstart#prerequisites) -------------------------------------------------------------------------------- Before you begin, ensure you have the following installed: * _**Rust 2021 edition**_ - Required for building from source * _**Docker**_ - Optional, for containerized deployment * _**Git**_ - For cloning the repository If you don’t have Rust installed, visit [https://rustup.rs/](https://rustup.rs/) to install it. [Quick Setup Options](https://docs.openzeppelin.com/monitor/quickstart#quick-setup-options) -------------------------------------------------------------------------------------------- We provide two setup paths to get you started: ### [Option 1: Automated Setup (Recommended)](https://docs.openzeppelin.com/monitor/quickstart#option-1-automated-setup-recommended) For the fastest setup experience, use our automated script that handles everything for you. #### [What the Automated Setup Does](https://docs.openzeppelin.com/monitor/quickstart#what-the-automated-setup-does) The `setup_and_run.sh` script provides a complete solution that: * _**Builds the monitor application**_ from source * _**Copies example configurations**_ from `examples/` to `config/` * Network configurations for major blockchains * Pre-configured monitor examples (USDC transfers, Stellar DEX swaps) * Required filter scripts and basic trigger notifications * _**Validates all configurations**_ to ensure proper setup * _**Optionally runs the monitor**_ to verify everything works #### [Running the Automated Setup](https://docs.openzeppelin.com/monitor/quickstart#running-the-automated-setup) 1. _**Clone the repository:**_ git clone https://github.com/openzeppelin/openzeppelin-monitor cd openzeppelin-monitor 2. _**Make the script executable:**_ chmod +x setup_and_run.sh 3. _**Run the automated setup:**_ ./setup_and_run.sh The script provides colored output and clear guidance throughout the process. #### [After Automated Setup](https://docs.openzeppelin.com/monitor/quickstart#after-automated-setup) Once complete, you’ll have: * A fully built OpenZeppelin Monitor * Example configurations ready for customization * Clear guidance on next steps _**Next Steps:**_ . Customize the copied configurations in `config/` directories . Update RPC URLs and notification credentials . Run the monitor with `./openzeppelin-monitor` The setup script creates working configurations with placeholder values. _**Remember to update your files with actual RPC endpoints and notification credentials**_ before starting real monitoring. ### [Option 2: Manual Setup](https://docs.openzeppelin.com/monitor/quickstart#option-2-manual-setup) For users who prefer more control over the setup process. #### [Building from Source](https://docs.openzeppelin.com/monitor/quickstart#building-from-source) 1. _**Clone and build:**_ git clone https://github.com/openzeppelin/openzeppelin-monitor cd openzeppelin-monitor cargo build --release 2. _**Move the binary to project root:**_ mv ./target/release/openzeppelin-monitor . #### [Docker Setup](https://docs.openzeppelin.com/monitor/quickstart#docker-setup) For containerized deployment: 1. _**Start services:**_ docker compose up By default, Docker Compose uses `Dockerfile.development`. For production, set: `DOCKERFILE=Dockerfile.production` before running the command. #### [Docker Management Commands](https://docs.openzeppelin.com/monitor/quickstart#docker-management-commands) | Command | Description | | --- | --- | | `docker ps -a` | Verify container status | | `docker compose down` | Stop services (without metrics) | | `docker compose --profile metrics down` | Stop services (with metrics) | | `docker compose logs -f` | View logs (follow mode) | [Environment Configuration](https://docs.openzeppelin.com/monitor/quickstart#environment-configuration) -------------------------------------------------------------------------------------------------------- ### [Logging Configuration](https://docs.openzeppelin.com/monitor/quickstart#logging-configuration) Configure logging verbosity by setting the `RUST_LOG` environment variable: | Level | Description | | --- | --- | | `error` | Only error messages | | `warn` | Warnings and errors | | `info` | General information (recommended) | | `debug` | Detailed debugging information | | `trace` | Very detailed trace information | export RUST_LOG=info ### [Local Configuration](https://docs.openzeppelin.com/monitor/quickstart#local-configuration) Copy the example environment file and customize it: cp .env.example .env For detailed configuration options, see [Basic Configuration](https://docs.openzeppelin.com/monitor#basic-configuration) . [Practical Examples](https://docs.openzeppelin.com/monitor/quickstart#practical-examples) ------------------------------------------------------------------------------------------ Now let’s set up real monitoring scenarios. Choose the example that matches your needs: ### [Example 1: Monitor USDC Transfers (Ethereum)](https://docs.openzeppelin.com/monitor/quickstart#example-1-monitor-usdc-transfers-ethereum) This example monitors large USDC transfers on Ethereum mainnet and sends notifications when transfers exceed 10,000 USDC. #### [Step 1: Network Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-1-network-configuration) Create the Ethereum mainnet configuration: # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/networks/ethereum_mainnet.json config/networks/ethereum_mainnet.json _**Key Configuration Details:**_ "network_type": "EVM", "slug": "ethereum_mainnet", "name": "Ethereum Mainnet", "rpc_urls": [\ {\ "type_": "rpc",\ "url": {\ "type": "plain",\ "value": "YOUR_RPC_URL_HERE"\ ,\ "weight": 100\ }\ ], "chain_id": 1, "block_time_ms": 12000, "confirmation_blocks": 12, "cron_schedule": "0 */1 * * * *", "max_past_blocks": 18, "store_blocks": false } _**Important:**_ Replace `YOUR_RPC_URL_HERE` with your actual Ethereum RPC endpoint. You can use providers like Infura, Alchemy, or run your own node. #### [Step 2: Monitor Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-2-monitor-configuration) Set up the USDC transfer monitor: # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/monitors/evm_transfer_usdc.json config/monitors/evm_transfer_usdc.json cp examples/config/filters/evm_filter_block_number.sh config/filters/evm_filter_block_number.sh _**Monitor Configuration Overview:**_ "name": "Large Transfer of USDC Token", "paused": false, "networks": ["ethereum_mainnet"], "addresses": [\ {\ "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",\ "contract_spec": [\ {\ "anonymous": false,\ "inputs": [\ {\ "indexed": true,\ "internalType": "address",\ "name": "from",\ "type": "address"\ ,\ \ "indexed": true,\ "internalType": "address",\ "name": "to",\ "type": "address"\ ,\ \ "indexed": false,\ "internalType": "uint256",\ "name": "value",\ "type": "uint256"\ \ ],\ "name": "Transfer",\ "type": "event"\ }\ ]\ }\ ], "match_conditions": "functions": [], "events": [\ {\ "signature": "Transfer(address,address,uint256)",\ "expression": "value > 10000000000"\ \ ], "transactions": [\ \ "status": "Success",\ "expression": null\ \ ] }, "trigger_conditions": [\ \ "script_path": "./config/filters/evm_filter_block_number.sh",\ "language": "bash",\ "arguments": ["--verbose"],\ "timeout_ms": 1000\ \ ], "triggers": ["evm_large_transfer_usdc_slack", "evm_large_transfer_usdc_email"] } * The `expression: "value > 10000000000"` monitors transfers over 10,000 USDC (USDC has 6 decimals) * Remove the `trigger_conditions` array to disable additional filtering * The USDC contract address `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` is the official USDC contract on Ethereum mainnet #### [Step 3: Notification Setup](https://docs.openzeppelin.com/monitor/quickstart#step-3-notification-setup) ##### [Slack Notifications](https://docs.openzeppelin.com/monitor/quickstart#slack-notifications) # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json _**Slack Configuration:**_ "evm_large_transfer_usdc_slack": { "name": "Large Transfer Slack Notification", "trigger_type": "slack", "config": { "slack_url": { "type": "plain", "value": "SLACK_WEBHOOK_URL" , "message": "title": "large_transfer_slack triggered", "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" } } } } To get a Slack webhook URL: 1. Go to [https://api.slack.com/apps](https://api.slack.com/apps) 2. Create a new app or select existing one 3. Enable "Incoming Webhooks" 4. Create a webhook for your channel ##### [Email Notifications](https://docs.openzeppelin.com/monitor/quickstart#email-notifications) # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/triggers/email_notifications.json config/triggers/email_notifications.json _**Email Configuration:**_ "evm_large_transfer_usdc_email": { "name": "Large Transfer Email Notification", "trigger_type": "email", "config": { "host": "smtp.gmail.com", "port": 465, "username": { "type": "plain", "value": "[email protected]" , "password": "type": "plain", "value": "SMTP_PASSWORD" , "message": "title": "large_transfer_usdc_email triggered", "body": "Large transfer of ${events.0.args.value USDC from $events.0.args.from to $events.0.args.to | https://etherscan.io/tx/$transaction.hash#eventlog" }, "sender": "[email protected]", "recipients": [\ "[email protected]",\ "[email protected]"\ ] } } } For Gmail, you’ll need to use an "App Password" instead of your regular password. Enable 2FA and generate an app password in your Google Account settings. #### [Step 4: Run the Monitor](https://docs.openzeppelin.com/monitor/quickstart#step-4-run-the-monitor) _**Local Deployment:**_ ./openzeppelin-monitor _**Docker Deployment:**_ cargo make docker-compose-up #### [What Happens Next](https://docs.openzeppelin.com/monitor/quickstart#what-happens-next) Once running, the monitor will: 1. Check for new Ethereum blocks every minute 2. Watch for USDC transfers over 10,000 USDC 3. Send notifications via Slack and email when large transfers occur #### [Customization Options](https://docs.openzeppelin.com/monitor/quickstart#customization-options) * _**Adjust threshold:**_ Modify `"value > 10000000000"` to change the minimum transfer amount * _**Monitor other tokens:**_ Create new monitor configurations for different ERC20 tokens * _**Add more networks:**_ Configure additional EVM networks (Polygon, BSC, etc.) ### [Example 2: Monitor DEX Swaps (Stellar)](https://docs.openzeppelin.com/monitor/quickstart#example-2-monitor-dex-swaps-stellar) This example monitors large DEX swaps on Stellar mainnet. #### [Step 1: Network Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-1-network-configuration-1) Create the Stellar mainnet configuration: # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/networks/stellar_mainnet.json config/networks/stellar_mainnet.json _**Key Configuration Details:**_ "network_type": "Stellar", "slug": "stellar_mainnet", "name": "Stellar Mainnet", "rpc_urls": [\ {\ "type_": "rpc",\ "url": {\ "type": "plain",\ "value": "YOUR_RPC_URL_HERE"\ ,\ "weight": 100\ }\ ], "network_passphrase": "Public Global Stellar Network ; September 2015", "block_time_ms": 5000, "confirmation_blocks": 2, "cron_schedule": "0 */1 * * * *", "max_past_blocks": 20, "store_blocks": true } #### [Step 2: Monitor Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-2-monitor-configuration-1) Set up the DEX swap monitor: # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/monitors/stellar_swap_dex.json config/monitors/stellar_swap_dex.json cp examples/config/filters/stellar_filter_block_number.sh config/filters/stellar_filter_block_number.sh _**Monitor Configuration Overview:**_ "name": "Large Swap By Dex", "paused": false, "networks": ["stellar_mainnet"], "addresses": [\ {\ "address": "CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE",\ "contract_spec": [\ {\ "function_v0": {\ "doc": "",\ "name": "swap",\ "inputs": [\ {\ "doc": "",\ "name": "user",\ "type_": "address"\ ,\ \ "doc": "",\ "name": "in_idx",\ "type_": "u32"\ ,\ \ "doc": "",\ "name": "out_idx",\ "type_": "u32"\ ,\ \ "doc": "",\ "name": "in_amount",\ "type_": "u128"\ ,\ \ "doc": "",\ "name": "out_min",\ "type_": "u128"\ \ ],\ "outputs": ["u128"]\ }\ }\ ]\ }\ ], "match_conditions": "functions": [\ {\ "signature": "swap(Address,U32,U32,U128,U128)",\ "expression": "out_min > 1000000000"\ \ ], "events": [], "transactions": [\ \ "status": "Success",\ "expression": null\ \ ] }, "trigger_conditions": [\ \ "script_path": "./config/filters/stellar_filter_block_number.sh",\ "language": "bash",\ "arguments": ["--verbose"],\ "timeout_ms": 1000\ \ ], "triggers": ["stellar_large_swap_by_dex_slack"] } * The `contract_spec` field is optional for Stellar contracts. If not provided, the monitor automatically fetches the contract’s SEP-48 interface from the chain * You can explore Stellar contract interfaces using the [Stellar Contract Explorer](https://lab.stellar.org/smart-contracts/contract-explorer) * The expression `"out_min > 1000000000"` monitors swaps with minimum output over 1 billion tokens #### [Step 3: Notification Setup](https://docs.openzeppelin.com/monitor/quickstart#step-3-notification-setup-1) Set up Slack notifications for Stellar swaps: # Only necessary if you haven't already run the automated setup script (Option 1: Automated Setup) cp examples/config/triggers/slack_notifications.json config/triggers/slack_notifications.json _**Slack Configuration:**_ "stellar_large_swap_by_dex_slack": { "name": "Large Swap By Dex Slack Notification", "trigger_type": "slack", "config": { "slack_url": { "type": "plain", "value": "slack-webhook-url" , "message": "title": "large_swap_by_dex_slack triggered", "body": "${monitor.name triggered because of a large swap of $functions.0.args.out_min tokens | https://stellar.expert/explorer/public/tx/$transaction.hash" } } } } #### [Step 4: Run the Monitor](https://docs.openzeppelin.com/monitor/quickstart#step-4-run-the-monitor-1) _**Local Deployment:**_ ./openzeppelin-monitor _**Docker Deployment:**_ cargo make docker-compose-up #### [What Happens Next](https://docs.openzeppelin.com/monitor/quickstart#what-happens-next-1) Once running, the monitor will: 1. Check for new Stellar blocks every minute 2. Watch for large DEX swaps 3. Send notifications via Slack when large swaps occur [Next Steps](https://docs.openzeppelin.com/monitor/quickstart#next-steps) -------------------------------------------------------------------------- Now that you have OpenZeppelin Monitor running, here are some suggestions for what to do next: ### [Testing and Validation](https://docs.openzeppelin.com/monitor/quickstart#testing-and-validation) * [Test your configuration](https://docs.openzeppelin.com/monitor#testing-your-configuration) against specific block numbers * Verify your RPC endpoints are working correctly * Test notification channels with small transactions ### [Security and Best Practices](https://docs.openzeppelin.com/monitor/quickstart#security-and-best-practices) * [Configure secure secret management](https://docs.openzeppelin.com/monitor#secret-management) for sensitive data * Use environment variables or Hashicorp Cloud Vault for credentials * Regularly update your RPC endpoints and monitor configurations ### [Advanced Configuration](https://docs.openzeppelin.com/monitor/quickstart#advanced-configuration) * Explore additional examples in the [`examples/config/monitors` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/monitors) * Set up monitoring for multiple networks simultaneously * Configure custom filter scripts for complex conditions ### [Getting Help](https://docs.openzeppelin.com/monitor/quickstart#getting-help) * Check the [GitHub Issues](https://github.com/OpenZeppelin/openzeppelin-monitor/issues) for known problems * Review the [User Documentation](https://docs.openzeppelin.com/monitor) for detailed configuration options * Join the OpenZeppelin community for support Start with simple monitoring scenarios and gradually add complexity. This helps you understand how the system works and makes troubleshooting easier. [Overview\ \ Previous Page](https://docs.openzeppelin.com/monitor) [Architecture Guide\ \ Next Page](https://docs.openzeppelin.com/monitor/architecture) ### On this page [What You'll Learn](https://docs.openzeppelin.com/monitor/quickstart#what-youll-learn) [Prerequisites](https://docs.openzeppelin.com/monitor/quickstart#prerequisites) [Quick Setup Options](https://docs.openzeppelin.com/monitor/quickstart#quick-setup-options) [Option 1: Automated Setup (Recommended)](https://docs.openzeppelin.com/monitor/quickstart#option-1-automated-setup-recommended) [What the Automated Setup Does](https://docs.openzeppelin.com/monitor/quickstart#what-the-automated-setup-does) [Running the Automated Setup](https://docs.openzeppelin.com/monitor/quickstart#running-the-automated-setup) [After Automated Setup](https://docs.openzeppelin.com/monitor/quickstart#after-automated-setup) [Option 2: Manual Setup](https://docs.openzeppelin.com/monitor/quickstart#option-2-manual-setup) [Building from Source](https://docs.openzeppelin.com/monitor/quickstart#building-from-source) [Docker Setup](https://docs.openzeppelin.com/monitor/quickstart#docker-setup) [Docker Management Commands](https://docs.openzeppelin.com/monitor/quickstart#docker-management-commands) [Environment Configuration](https://docs.openzeppelin.com/monitor/quickstart#environment-configuration) [Logging Configuration](https://docs.openzeppelin.com/monitor/quickstart#logging-configuration) [Local Configuration](https://docs.openzeppelin.com/monitor/quickstart#local-configuration) [Practical Examples](https://docs.openzeppelin.com/monitor/quickstart#practical-examples) [Example 1: Monitor USDC Transfers (Ethereum)](https://docs.openzeppelin.com/monitor/quickstart#example-1-monitor-usdc-transfers-ethereum) [Step 1: Network Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-1-network-configuration) [Step 2: Monitor Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-2-monitor-configuration) [Step 3: Notification Setup](https://docs.openzeppelin.com/monitor/quickstart#step-3-notification-setup) [Slack Notifications](https://docs.openzeppelin.com/monitor/quickstart#slack-notifications) [Email Notifications](https://docs.openzeppelin.com/monitor/quickstart#email-notifications) [Step 4: Run the Monitor](https://docs.openzeppelin.com/monitor/quickstart#step-4-run-the-monitor) [What Happens Next](https://docs.openzeppelin.com/monitor/quickstart#what-happens-next) [Customization Options](https://docs.openzeppelin.com/monitor/quickstart#customization-options) [Example 2: Monitor DEX Swaps (Stellar)](https://docs.openzeppelin.com/monitor/quickstart#example-2-monitor-dex-swaps-stellar) [Step 1: Network Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-1-network-configuration-1) [Step 2: Monitor Configuration](https://docs.openzeppelin.com/monitor/quickstart#step-2-monitor-configuration-1) [Step 3: Notification Setup](https://docs.openzeppelin.com/monitor/quickstart#step-3-notification-setup-1) [Step 4: Run the Monitor](https://docs.openzeppelin.com/monitor/quickstart#step-4-run-the-monitor-1) [What Happens Next](https://docs.openzeppelin.com/monitor/quickstart#what-happens-next-1) [Next Steps](https://docs.openzeppelin.com/monitor/quickstart#next-steps) [Testing and Validation](https://docs.openzeppelin.com/monitor/quickstart#testing-and-validation) [Security and Best Practices](https://docs.openzeppelin.com/monitor/quickstart#security-and-best-practices) [Advanced Configuration](https://docs.openzeppelin.com/monitor/quickstart#advanced-configuration) [Getting Help](https://docs.openzeppelin.com/monitor/quickstart#getting-help) --- # Error Handling | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Error Handling ============== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/monitor/error#overview) ----------------------------------------------------------------- The OpenZeppelin Monitor uses a structured error handling system that provides rich context and tracing capabilities across service boundaries. Let’s start with a real-world example of how errors flow through our system. [Error Flow Example](https://docs.openzeppelin.com/monitor/error#error-flow-example) ------------------------------------------------------------------------------------- Let’s follow how an error propagates through our blockchain monitoring system: **Low-level Transport (`endpoint_manager.rs`)** // Creates basic errors with specific context async fn send_raw_request(...) -> Result let response = client.post(...) .await .map_err(|e| anyhow::anyhow!("Failed to send request: {", e))?; if !status.is_success() return Err(anyhow::anyhow!("HTTP error {: {}", status, error_body)); } } **Client Layer (`evm/client.rs`)** // Adds business context to low-level errors async fn get_transaction_receipt(...) -> Result let response = self.alloy_client .send_raw_request(...) .await .with_context(|| format!("Failed to get transaction receipt: {", tx_hash))?; if receipt_data.is_null() return Err(anyhow::anyhow!("Transaction receipt not found")); } **Filter Layer (`evm/filter.rs`)** // Converts to domain-specific errors async fn filter_block(...) -> Result, FilterError> let receipts = match futures::future::join_all(receipt_futures).await { Ok(receipts) => receipts, Err(e) => { return Err(FilterError::network_error( format!("Failed to get transaction receipts for block {", block_num), Some(e.into()), None, )); } }; } When this error occurs, it produces the following log: ERROR filter_block: openzeppelin_monitor::utils::error: Error occurred, error.message: Failed to get transaction receipts for block 15092829, error.trace_id: a464d73c-5992-4cb5-a002-c8d705bfef8d, error.timestamp: 2025-03-14T09:42:03.412341+00:00, error.chain: Failed to get receipt for transaction 0x7722194b65953085fe1e9ec01003f1d7bdd6258a0ea5c91a59da80419513d95d Caused by: HTTP error 429 Too Many Requests: "code":-32007,"message":"[Exceeded request limit per second]" network: ethereum_mainnet [Error Structure](https://docs.openzeppelin.com/monitor/error#error-structure) ------------------------------------------------------------------------------- ### [Error Context](https://docs.openzeppelin.com/monitor/error#error-context) Every error in our system includes detailed context information: pub struct ErrorContext /// The error message pub message: String, /// The source error (if any) pub source: Option>, /// Unique trace ID for error tracking pub trace_id: String, /// Timestamp when the error occurred pub timestamp: DateTime, /// Optional key-value metadata pub metadata: HashMap, ### [Domain-Specific Error Types](https://docs.openzeppelin.com/monitor/error#domain-specific-error-types) | Module | Error Type | Description | | --- | --- | --- | | `**Configuration**` | `ConfigError` | \* `ValidationError` - Configuration validation failures \* `ParseError` - Configuration parsing issues \* `FileError` - File system related errors \* `Other` - Unclassified errors | | `**Security**` | `SecurityError` | \* `ValidationError` - Security validation failures \* `ParseError` - Security data parsing issues \* `NetworkError` - Security service connectivity issues \* `Other` - Unclassified security-related errors | | `**Blockchain Service**` | `BlockChainError` | \* `ConnectionError` - Network connectivity issues \* `RequestError` - Malformed requests or invalid responses \* `BlockNotFound` - Requested block not found \* `TransactionError` - Transaction processing failures \* `InternalError` - Internal client errors \* `ClientPoolError` - Client pool related issues \* `Other` - Unclassified errors | | `**Block Watcher Service**` | `BlockWatcherError` | \* `SchedulerError` - Block watching scheduling issues \* `NetworkError` - Network connectivity problems \* `ProcessingError` - Block processing failures \* `StorageError` - Storage operation failures \* `BlockTrackerError` - Block tracking issues \* `Other` - Unclassified errors | | `**Filter Service**` | `FilterError` | \* `BlockTypeMismatch` - Block type validation failures \* `NetworkError` - Network connectivity issues \* `InternalError` - Internal processing errors \* `Other` - Unclassified errors | | `**Notification Service**` | `NotificationError` | \* `NetworkError` - Network connectivity issues \* `ConfigError` - Configuration problems \* `InternalError` - Internal processing errors \* `ExecutionError` - Script execution failures \* `Other` - Unclassified errors | | `**Repository**` | `RepositoryError` | \* `ValidationError` - Data validation failures \* `LoadError` - Data loading issues \* `InternalError` - Internal processing errors \* `Other` - Unclassified errors | | `**Script Utils**` | `ScriptError` | \* `NotFound` - Resource not found errors \* `ExecutionError` - Script execution failures \* `ParseError` - Script parsing issues \* `SystemError` - System-level errors \* `Other` - Unclassified errors | | `**Trigger Service**` | `TriggerError` | \* `NotFound` - Resource not found errors \* `ExecutionError` - Trigger execution failures \* `ConfigurationError` - Trigger configuration issues \* `Other` - Unclassified errors | | `**Monitor Executor**` | `MonitorExecutionError` | \* `NotFound` - Resource not found errors \* `ExecutionError` - Monitor execution failures \* `Other` - Unclassified errors | [Error Handling Guidelines](https://docs.openzeppelin.com/monitor/error#error-handling-guidelines) --------------------------------------------------------------------------------------------------- ### [When to Use Each Pattern](https://docs.openzeppelin.com/monitor/error#when-to-use-each-pattern) | Scenario | Approach | | --- | --- | | Crossing Domain Boundaries | Convert to domain-specific error type using custom error constructors | | Within Same Domain | Use `.with_context()` to add information while maintaining error type | | External API Boundaries | Always convert to your domain’s error type to avoid leaking implementation details | ### [Error Creation Examples](https://docs.openzeppelin.com/monitor/error#error-creation-examples) **Creating a Configuration Error without a source** let error = ConfigError::validation_error( "Invalid network configuration", None, Some(HashMap::from([\ ("network", "ethereum"),\ ("field", "rpc_url")\ ])) ); **Creating a Configuration Error with a source** let io_error = std::io::Error::new(std::io::ErrorKind::Other, "Failed to read file"); let error = ConfigError::validation_error( "Invalid network configuration", Some(io_error.into()), None ); ### [Tracing with #\[instrument\]](https://docs.openzeppelin.com/monitor/error#tracing-with-instrument) #[instrument(skip_all, fields(network = %_network.slug))] async fn filter_block( &self, client: &T, _network: &Network, block: &BlockType, monitors: &[Monitor], ) -> Result, FilterError> tracing::debug!("Processing block {", block_number); // ... } Key aspects: 1. `skip_all` - Skips automatic instrumentation of function parameters for performance 2. `fields(...)` - Adds specific fields we want to track (like network slug) 3. `tracing::debug!` - Adds debug-level spans for important operations [Custom scripts\ \ Previous Page](https://docs.openzeppelin.com/monitor/scripts) [Testing\ \ Next Page](https://docs.openzeppelin.com/monitor/testing) ### On this page [Overview](https://docs.openzeppelin.com/monitor/error#overview) [Error Flow Example](https://docs.openzeppelin.com/monitor/error#error-flow-example) [Error Structure](https://docs.openzeppelin.com/monitor/error#error-structure) [Error Context](https://docs.openzeppelin.com/monitor/error#error-context) [Domain-Specific Error Types](https://docs.openzeppelin.com/monitor/error#domain-specific-error-types) [Error Handling Guidelines](https://docs.openzeppelin.com/monitor/error#error-handling-guidelines) [When to Use Each Pattern](https://docs.openzeppelin.com/monitor/error#when-to-use-each-pattern) [Error Creation Examples](https://docs.openzeppelin.com/monitor/error#error-creation-examples) [Tracing with #\[instrument\]](https://docs.openzeppelin.com/monitor/error#tracing-with-instrument) --- # RPC Client | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) RPC Client ========== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [Overview](https://docs.openzeppelin.com/monitor/rpc#overview) --------------------------------------------------------------- The OpenZeppelin Monitor includes a robust RPC client implementation with automatic endpoint rotation and fallback capabilities. This ensures reliable blockchain monitoring even when individual RPC endpoints experience issues. * Multiple RPC endpoint support with weighted load balancing * Automatic fallback on endpoint failures * Rate limit handling (429 responses) * Connection health checks * Thread-safe endpoint rotation [Configuration](https://docs.openzeppelin.com/monitor/rpc#configuration) ------------------------------------------------------------------------- ### [RPC URLs](https://docs.openzeppelin.com/monitor/rpc#rpc-urls) RPC endpoints are configured in the network configuration files with weights for load balancing: { "rpc_urls": [\ {\ "type_": "rpc",\ "url": {"type": "plain", "value": "https://primary-endpoint.example.com"},\ "weight": 100\ },\ {\ "type_": "rpc",\ "url": {"type": "plain", "value": "https://backup-endpoint.example.com"},\ "weight": 50\ }\ ] } For high-availability setups, configure at least 3 (private) RPC endpoints with appropriate weights to ensure continuous operation even if multiple endpoints fail. ### [Configuration Fields](https://docs.openzeppelin.com/monitor/rpc#configuration-fields) | Field | Type | Description | | --- | --- | --- | | `type_` | `String` | Type of endpoint (currently only "rpc" is supported) | | `url.type` | `String` | Secret type ("Plain", "Environment", or "HashicorpCloudVault") | | `url.value` | `String` | The RPC endpoint URL | | `weight` | `Number` | Load balancing weight (0-100) | [Endpoint Management](https://docs.openzeppelin.com/monitor/rpc#endpoint-management) ------------------------------------------------------------------------------------- The endpoint manager handles: * Initial endpoint selection based on weights * Automatic rotation on failures * Connection health checks * Thread-safe endpoint updates Each blockchain network type has its own specialized transport client that wraps the base `HttpTransportClient`. The transport clients are implemented as: 1. **Core HTTP Transport**: `HttpTransportClient` provides core HTTP functionality, including the integrated retryable client. 2. **Network-Specific Transports**: * `EVMTransportClient` for EVM networks * `StellarTransportClient` for Stellar networks ### [Rotation Strategy](https://docs.openzeppelin.com/monitor/rpc#rotation-strategy) The RPC client includes an automatic rotation strategy for handling specific types of failures: * For 429 (Too Many Requests) responses: * Immediately rotates to a fallback URL * Retries the request with the new endpoint * Continues this process until successful or all endpoints are exhausted #### [Configuration Options](https://docs.openzeppelin.com/monitor/rpc#configuration-options) The error codes that trigger RPC endpoint rotation can be customized in the `src/services/blockchain/transports/mod.rs` file. pub const ROTATE_ON_ERROR_CODES: [u16; 1] = [429]; ### [Retry Strategy](https://docs.openzeppelin.com/monitor/rpc#retry-strategy) The transport layer uses a combination of same-endpoint retries and endpoint rotation to handle transient failures and maintain service availability. #### [Same-Endpoint Retry (via `reqwest-retry`)](https://docs.openzeppelin.com/monitor/rpc#same-endpoint-retry-via-reqwest-retry) The `HttpTransportClient` (and by extension, EVM and Stellar clients) utilizes a `reqwest_middleware::ClientWithMiddleware`. This client is configured during initialization using the `utils::http::create_retryable_http_client` utility. This utility layers `reqwest_retry::RetryTransientMiddleware` on top of a shared base `reqwest::Client`. This middleware handles: * Automatic retries for transient HTTP errors (e.g., 5xx server errors, network timeouts) for requests made to the **currently active RPC URL**. * An exponential backoff policy between these retry attempts. * Parameters like the number of retries, backoff durations, and jitter are defined in an `RetryConfig` struct (see [Configuration Options](https://docs.openzeppelin.com/monitor/rpc#configuration-options) ). * This same-endpoint retry mechanism is independent of, and operates before, the endpoint rotation logic. If all same-endpoint retries fail for the current URL, the error is then processed by the `EndpointManager`. #### [Endpoint Rotation (via `EndpointManager`)](https://docs.openzeppelin.com/monitor/rpc#endpoint-rotation-via-endpointmanager) If all same-endpoint retries fail for the currently active RPC URL, or if certain HTTP status codes (e.g., 429 Too Many Requests, as defined in `ROTATE_ON_ERROR_CODES`) are received, the `EndpointManager` (used by `HttpTransportClient`) will attempt to rotate to a healthy fallback URL. This ensures that if one endpoint becomes persistently unavailable, the system can switch to an alternative. The health check for a fallback URL also benefits from the same-endpoint retry mechanism. #### [Configuration Options](https://docs.openzeppelin.com/monitor/rpc#configuration-options-1) The same-endpoint retry behavior is configured via the `RetryConfig` struct, which is used by `create_retryable_http_client` to set up the `ExponentialBackoff` policy for `reqwest-retry`. The default settings for `RetryConfig` result in an `ExponentialBackoff` policy approximately equivalent to: // This illustrates the default policy created by RetryConfig::default() // and create_retryable_http_client. let http_retry_config = RetryConfig::default(); let retry_policy = ExponentialBackoff::builder() .base(http_retry_config.base_for_backoff) .retry_bounds(http_retry_config.initial_backoff, http_retry_config.max_backoff) .jitter(http_retry_config.jitter) .build_with_max_retries(http_retry_config.max_retries); The configurable options are defined in the `RetryConfig` struct: // In utils::http pub struct RetryConfig { /// Maximum number of retries for transient errors (after the initial attempt). pub max_retries: u32, /// Initial backoff duration before the first retry. pub initial_backoff: Duration, /// Maximum backoff duration for retries. pub max_backoff: Duration, /// Base for the exponential backoff calculation (e.g., 2). pub base_for_backoff: u64, /// Jitter to apply to the backoff duration. pub jitter: Jitter, } The client architecture ensures efficient resource use and consistent retry behavior: 1. A single base `reqwest::Client` is created by `HttpTransportClient` with optimized connection pool settings. This base client is shared. 2. The `create_retryable_http_client` utility takes this base client and an `RetryConfig` to produce a `ClientWithMiddleware`. 3. This `ClientWithMiddleware` (the "retryable client") is then used for all HTTP operations within `HttpTransportClient`, including initial health checks, requests sent via `EndpointManager`, and `try_connect` calls during rotation. This ensures all operations benefit from the configured retry policy and the shared connection pool. Each transport client may define its own retry policy: // src/services/transports/http.rs pub struct HttpTransportClient { pub client: ClientWithMiddleware, endpoint_manager: EndpointManager, test_connection_payload: Option, } // Example of client creation with retry mechanism // Use default retry policy let http_retry_config = RetryConfig::default(); // Create the base HTTP client let base_http_client = reqwest::ClientBuilder::new() .pool_idle_timeout(Duration::from_secs(90)) .pool_max_idle_per_host(32) .timeout(Duration::from_secs(30)) .connect_timeout(Duration::from_secs(20)) .build() .context("Failed to create base HTTP client")?; // Create a retryable HTTP client with the base client and retry policy let retryable_client = create_retryable_http_client( &http_retry_config, base_http_client, Some(TransientErrorRetryStrategy), // Use custom or default retry strategy ); ### [Implementation Details](https://docs.openzeppelin.com/monitor/rpc#implementation-details) The `EndpointManager` uses the retry-enabled `ClientWithMiddleware` provided by `HttpTransportClient` for its attempts on the primary URL. If these attempts (including internal `reqwest-retry` retries) ultimately fail with an error that warrants rotation (e.g., a 429 status code, or persistent network errors), then `EndpointManager` initiates the URL rotation sequence. [List of RPC Calls](https://docs.openzeppelin.com/monitor/rpc#list-of-rpc-calls) --------------------------------------------------------------------------------- Below is a list of RPC calls made by the monitor for each network type for each iteration of the cron schedule. As the number of blocks being processed increases, the number of RPC calls grows, potentially leading to rate limiting issues or increased costs if not properly managed. **EVM** * RPC Client initialization (per active network): `net_version` * Fetching the latest block number (per cron iteration): `eth_blockNumber` * Fetching block data (per block): `eth_getBlockByNumber` * Fetching block logs (per block): `eth_getLogs` * Fetching transaction receipt (only when needed): * When monitor condition requires receipt-specific fields (e.g., `gas_used`) * When monitoring transaction status and no logs are present to validate status **Stellar** * RPC Client initialization (per active network): `getNetwork` * Fetching the latest ledger (per cron iteration): `getLatestLedger` * Fetching ledger data (batched up to 200 in a single request): `getLedgers` * During block filtering, for each monitored contract without an ABI in config: * Fetching contract instance data: `getLedgerEntries` * Fetching contract WASM code: `getLedgerEntries` * Fetching transactions (batched up to 200 in a single request): `getTransactions` * Fetching events (batched up to 200 in a single request): `getEvents` [Best Practices](https://docs.openzeppelin.com/monitor/rpc#best-practices) --------------------------------------------------------------------------- * Configure multiple private endpoints with appropriate weights * Use geographically distributed endpoints when possible * Monitor endpoint health and adjust weights as needed * Set appropriate retry policies based on network characteristics [Troubleshooting](https://docs.openzeppelin.com/monitor/rpc#troubleshooting) ----------------------------------------------------------------------------- ### [Common Issues](https://docs.openzeppelin.com/monitor/rpc#common-issues) * **429 Too Many Requests**: Increase the number of fallback URLs, adjust weights or reduce monitoring frequency * **Connection Timeouts**: Check endpoint health and network connectivity * **Invalid Responses**: Verify endpoint compatibility with your network type ### [Logging](https://docs.openzeppelin.com/monitor/rpc#logging) Enable debug logging for detailed transport information: RUST_LOG=debug This will show: * Endpoint rotations * Connection attempts * Request/response details [Project Structure\ \ Previous Page](https://docs.openzeppelin.com/monitor/project-structure) [Custom scripts\ \ Next Page](https://docs.openzeppelin.com/monitor/scripts) ### On this page [Overview](https://docs.openzeppelin.com/monitor/rpc#overview) [Configuration](https://docs.openzeppelin.com/monitor/rpc#configuration) [RPC URLs](https://docs.openzeppelin.com/monitor/rpc#rpc-urls) [Configuration Fields](https://docs.openzeppelin.com/monitor/rpc#configuration-fields) [Endpoint Management](https://docs.openzeppelin.com/monitor/rpc#endpoint-management) [Rotation Strategy](https://docs.openzeppelin.com/monitor/rpc#rotation-strategy) [Configuration Options](https://docs.openzeppelin.com/monitor/rpc#configuration-options) [Retry Strategy](https://docs.openzeppelin.com/monitor/rpc#retry-strategy) [Same-Endpoint Retry (via `reqwest-retry`)](https://docs.openzeppelin.com/monitor/rpc#same-endpoint-retry-via-reqwest-retry) [Endpoint Rotation (via `EndpointManager`)](https://docs.openzeppelin.com/monitor/rpc#endpoint-rotation-via-endpointmanager) [Configuration Options](https://docs.openzeppelin.com/monitor/rpc#configuration-options-1) [Implementation Details](https://docs.openzeppelin.com/monitor/rpc#implementation-details) [List of RPC Calls](https://docs.openzeppelin.com/monitor/rpc#list-of-rpc-calls) [Best Practices](https://docs.openzeppelin.com/monitor/rpc#best-practices) [Troubleshooting](https://docs.openzeppelin.com/monitor/rpc#troubleshooting) [Common Issues](https://docs.openzeppelin.com/monitor/rpc#common-issues) [Logging](https://docs.openzeppelin.com/monitor/rpc#logging) --- # OpenZeppelin Hardhat Upgrades API | OpenZeppelin Docs [Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) OpenZeppelin Hardhat Upgrades API ================================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Both `deployProxy` and `upgradeProxy` functions will return instances of [ethers.js contracts](https://docs.ethers.io/v5/api/contract/contract) , and require [ethers.js contract factories](https://docs.ethers.io/v5/api/contract/contract-factory) as arguments. For [beacons](https://docs.openzeppelin.com/contracts/5.x/api/proxy#beacon) , `deployBeacon` and `upgradeBeacon` will both return an upgradable beacon instance that can be used with a beacon proxy. All deploy and upgrade functions validate that the implementation contract is upgrade-safe, and will fail otherwise. [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) ----------------------------------------------------------------------------------------------------- The following options are common to some functions. * `kind`: (`"uups" | "transparent" | "beacon"`) The kind of proxy to deploy, upgrade or import, or the kind of proxy that the implementation will be used with. `deployProxy()` and `upgradeProxy()` only support the values `"uups" | "transparent"`. Defaults to `"transparent"`. See [Transparent vs UUPS](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups) . * `unsafeAllow`: (`ValidationError[]`) Selectively disable one or more validation errors or warnings: * `"external-library-linking"`: Allows a deployment with external libraries linked to the implementation contract. (External libraries are otherwise [not yet supported](https://docs.openzeppelin.com/upgrades-plugins/faq#why-cant-i-use-external-libraries) .) * `"struct-definition"`, `"enum-definition"`: Used to be necessary to deploy a contract with structs or enums. No longer necessary. * `"state-variable-assignment"`: Allows assigning state variables in a contract even though they will be stored in the implementation. * `"state-variable-immutable"`: Allows use of immutable variables, which are not unsafe * `"constructor"`: Allows defining a constructor. See `constructorArgs`. * `"delegatecall"`, `"selfdestruct"`: Allow the use of these operations. Incorrect use of this option can put funds at risk of permanent loss. See [Can I safely use `delegatecall` and `selfdestruct`?](https://docs.openzeppelin.com/upgrades-plugins/faq#can-i-safely-use-delegatecall-and-selfdestruct) * `"missing-public-upgradeto"`: Allow UUPS implementations that do not contain a public `upgradeTo` or `upgradeToAndCall` function. Enabling this option is likely to cause a revert due to the built-in UUPS safety mechanism. * `"internal-function-storage"`: Allow internal functions in storage variables. Internal functions are code pointers which will no longer be valid after an upgrade, so they must be reassigned during upgrades. See [How can I use internal functions in storage variables?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-use-internal-functions-in-storage-variables) * `"missing-initializer"`: Allows implementations where an initializer function is not detected. * `"missing-initializer-call"`: Allows implementations where a parent initializer is not called from the child initializer. * `"duplicate-initializer-call"`: Allows implementations where a parent initializer is called more than once from the child initializer. * `"incorrect-initializer-order"`: Allows implementations where parent initializers are not called in linearized order. **Note**: This condition shows a warning by default, and setting this option will silence the warning. * `unsafeAllowRenames`: (`boolean`) Configure storage layout check to allow variable renaming. * `unsafeSkipStorageCheck`: (`boolean`) upgrades the proxy or beacon without first checking for storage layout compatibility errors. This is a dangerous option meant to be used as a last resort. * `constructorArgs`: (`unknown[]`) Provide arguments for the constructor of the implementation contract. Note that these are different from initializer arguments, and will be used in the deployment of the implementation contract itself. Can be used to initialize immutable variables. * `initialOwner`: (`string`) the address to set as the initial owner of a transparent proxy’s admin or initial owner of a beacon. Defaults to the externally owned account that is deploying the transparent proxy or beacon. Not supported for UUPS proxies. * **Since:** `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` * `unsafeSkipProxyAdminCheck`: (`boolean`) Skips checking the `initialOwner` option when deploying a transparent proxy. When deploying a transparent proxy, the `initialOwner` must be the address of an EOA or a contract that can call functions on a ProxyAdmin. It must not be a ProxyAdmin contract itself. Use this if you encounter an error due to this check and are sure that the `initialOwner` is not a ProxyAdmin contract. * **Since:** `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` * `timeout`: (`number`) Timeout in milliseconds to wait for the transaction confirmation when deploying an implementation contract. Defaults to `60000`. Use `0` to wait indefinitely. * `pollingInterval`: (`number`) Polling interval in milliseconds between checks for the transaction confirmation when deploying an implementation contract. Defaults to `5000`. * `redeployImplementation`: (`"always" | "never" | "onchange"`) Determines whether the implementation contract will be redeployed. Defaults to `"onchange"`. * If set to `"always"`, the implementation contract is always redeployed even if it was previously deployed with the same bytecode. This can be used with the `salt` option when deploying a proxy through OpenZeppelin Defender to ensure that the implementation contract is deployed with the same salt as the proxy. * If set to `"never"`, the implementation contract is never redeployed. If the implementation contract was not previously deployed or is not found in the network file, an error will be thrown. * If set to `"onchange"`, the implementation contract is redeployed only if the bytecode has changed from previous deployments. * `txOverrides`: (`ethers.Overrides`) An ethers.js [Overrides](https://docs.ethers.org/v6/api/contract/#Overrides) object to override transaction parameters, such as `gasLimit` and `gasPrice`. Applies to all transactions sent by a function with this option, even if the function sends multiple transactions. For OpenZeppelin Defender deployments, only the `gasLimit`, `gasPrice`, `maxFeePerGas`, and `maxPriorityFeePerGas` parameters are supported. * `useDefenderDeploy`: (`boolean`) Deploy contracts using OpenZeppelin Defender instead of ethers.js. See [Using with OpenZeppelin Defender](https://docs.openzeppelin.com/upgrades-plugins/defender-deploy) . * `verifySourceCode`: (`boolean`) When using OpenZeppelin Defender deployments, whether to verify source code on block explorers. Defaults to `true`. * `relayerId`: (`string`) When using OpenZeppelin Defender deployments, the ID of the relayer to use for the deployment. Defaults to the relayer configured for your deployment environment on Defender. * `salt`: (`string`) When using OpenZeppelin Defender deployments, if this is not set, deployments will be performed using the CREATE opcode. If this is set, deployments will be performed using the CREATE2 opcode with the provided salt. Note that deployments using a Safe are done using CREATE2 and require a salt. _**Warning:**_ CREATE2 affects `msg.sender` behavior. See [Caveats](https://docs.openzeppelin.com/defender/tutorial/deploy#caveats) for more information. * `metadata`: (`commitHash?: string; tag?: string; [k: string]: any;`) When using OpenZeppelin Defender deployments, you can use this to identify, tag, or classify deployments. See [Metadata](https://docs.openzeppelin.com/defender/module/deploy#metadata) . * `proxyFactory`: (`ethers.ContractFactory`) Customizes the ethers contract factory to use for deploying the proxy, allowing a custom proxy contract to be deployed. See [factories.ts](https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/plugin-hardhat/src/utils/factories.ts) for the default contract factory for each kind of proxy. * **Since:** `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` * `deployFunction`: (`(hre, opts, factory, ...args) => Promise`) Customizes the function used to deploy the proxy. Can be used along with the `proxyFactory` option to override constructor parameters for custom proxy deployments. See [deploy.ts](https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/plugin-hardhat/src/utils/deploy.ts) for the default deploy function. * **Since:** `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` Note that the options `unsafeAllow` can also be specified in a more granular way directly in the source code if using Solidity >=0.8.2. See [How can I disable some of the checks?](https://docs.openzeppelin.com/upgrades-plugins/faq#how-can-i-disable-some-of-the-checks) The following options have been deprecated. * `unsafeAllowLinkedLibraries`: Equivalent to including `"external-library-linking"` in `unsafeAllow`. * `unsafeAllowCustomTypes`: Equivalent to including `"struct-definition"` and `"enum-definition"` in `unsafeAllow`. No longer necessary. * `useDeployedImplementation`: (`boolean`) Equivalent to setting `redeployImplementation` to `"never"`. [deployProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deployproxy) ----------------------------------------------------------------------------------------------- async function deployProxy( Contract: ethers.ContractFactory, args: unknown[] = [], opts?: initializer?: string | false, unsafeAllow?: ValidationError[], constructorArgs?: unknown[], initialOwner?: string, unsafeSkipProxyAdminCheck?: boolean, timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, kind?: 'uups' | 'transparent', useDefenderDeploy?: boolean, proxyFactory?: ethers.ContractFactory, deployFunction?: () => Promise, , ): Promise Creates a UUPS or Transparent proxy given an ethers contract factory to use as implementation, and returns a contract instance with the proxy address and the implementation interface. If `args` is set, will call an initializer function `initialize` with the supplied args during proxy deployment. If you call `deployProxy` several times for the same implementation contract, several proxies will be deployed, but only one implementation contract will be used. **Parameters:** * `Contract` - an ethers contract factory to use as the implementation. * `args` - arguments for the initializer function. * `opts` - an object with options: * `initializer`: set a different initializer function to call (see [Specifying Fragments](https://docs.ethers.io/v5/api/utils/abi/interface/#Interface--specifying-fragments) ), or specify `false` to disable initialization. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * a contract instance with the proxy address and the implementation interface. [upgradeProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#upgradeproxy) ------------------------------------------------------------------------------------------------- async function upgradeProxy( proxy: string | ethers.Contract, Contract: ethers.ContractFactory, opts?: call?: string | { fn: string; args?: unknown[] , unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, constructorArgs?: unknown[], timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, kind?: 'uups' | 'transparent', }, ): Promise Upgrades a UUPS or Transparent proxy at a specified address to a new implementation contract, and returns a contract instance with the proxy address and the new implementation interface. **Parameters:** * `proxy` - the proxy address or proxy contract instance. * `Contract` - an ethers contract factory to use as the new implementation. * `opts` - an object with options: * `call`: enables the execution of an arbitrary function call during the upgrade process. This call is described using a function name, signature, or selector (see [Specifying Fragments](https://docs.ethers.io/v5/api/utils/abi/interface/#Interface--specifying-fragments) ), and optional arguments. It is batched into the upgrade transaction, making it safe to call migration initializing functions. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * a contract instance with the proxy address and the new implementation interface. [deployBeacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deploybeacon) ------------------------------------------------------------------------------------------------- async function deployBeacon( Contract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], constructorArgs?: unknown[], initialOwner?: string, timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, , ): Promise Creates an [upgradable beacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) given an ethers contract factory to use as implementation, and returns the beacon contract instance. **Parameters:** * `Contract` - an ethers contract factory to use as the implementation. * `opts` - an object with options: * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * the beacon contract instance. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [upgradeBeacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#upgradebeacon) --------------------------------------------------------------------------------------------------- async function upgradeBeacon( beacon: string | ethers.Contract, Contract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, constructorArgs?: unknown[], timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, , ): Promise Upgrades an [upgradable beacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) at a specified address to a new implementation contract, and returns the beacon contract instance. **Parameters:** * `beacon` - the beacon address or beacon contract instance. * `Contract` - an ethers contract factory to use as the new implementation. * `opts` - an object with options: * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * the beacon contract instance. **Since**: * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [deployBeaconProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deploybeaconproxy) ----------------------------------------------------------------------------------------------------------- async function deployBeaconProxy( beacon: string | ethers.Contract, attachTo: ethers.ContractFactory, args: unknown[] = [], opts?: initializer?: string | false, txOverrides?: ethers.Overrides, useDefenderDeploy?: boolean, proxyFactory?: ethers.ContractFactory, deployFunction?: () => Promise, , ): Promise Creates a [Beacon proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) given an existing beacon contract address and an ethers contract factory corresponding to the beacon’s current implementation contract, and returns a contract instance with the beacon proxy address and the implementation interface. If `args` is set, will call an initializer function `initialize` with the supplied args during proxy deployment. **Parameters:** * `beacon` - the beacon address or beacon contract instance. * `attachTo` - an ethers contract factory corresponding to the beacon’s current implementation contract. * `args` - arguments for the initializer function. * `opts` - an object with options: * `initializer`: set a different initializer function to call (see [Specifying Fragments](https://docs.ethers.io/v5/api/utils/abi/interface/#Interface--specifying-fragments) ), or specify `false` to disable initialization. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * a contract instance with the beacon proxy address and the implementation interface. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [forceImport](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#forceimport) ----------------------------------------------------------------------------------------------- async function forceImport( address: string, deployedImpl: ethers.ContractFactory, opts?: kind?: 'uups' | 'transparent' | 'beacon', , ): Promise Forces the import of an existing proxy, beacon, or implementation contract deployment to be used with this plugin. Provide the address of an existing proxy, beacon or implementation, along with the ethers contract factory of the implementation contract that was deployed. When importing a proxy or beacon, the `deployedImpl` argument must be the contract factory of the **current** implementation contract version that is being used, not the version that you are planning to upgrade to. Use this function to recreate a lost [network file](https://docs.openzeppelin.com/upgrades-plugins/network-files) by importing previous deployments, or to register proxies or beacons for upgrading even if they were not originally deployed by this plugin. Supported for UUPS, Transparent, and Beacon proxies, as well as beacons and implementation contracts. **Parameters:** * `address` - the address of an existing proxy, beacon or implementation. * `deployedImpl` - the ethers contract factory of the implementation contract that was deployed. * `opts` - an object with options: * `kind`: (`"uups" | "transparent" | "beacon"`) forces a proxy to be treated as a UUPS, Transparent, or Beacon proxy. If not provided, the proxy kind will be automatically detected. **Returns:** * a contract instance representing the imported proxy, beacon or implementation. **Since** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [validateImplementation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#validateimplementation) --------------------------------------------------------------------------------------------------------------------- async function validateImplementation( Contract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], kind?: 'uups' | 'transparent' | 'beacon', , ): Promise Validates an implementation contract without deploying it. **Parameters:** * `Contract` - the ethers contract factory of the implementation contract. * `opts` - an object with options: * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [deployImplementation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deployimplementation) ----------------------------------------------------------------------------------------------------------------- async function deployImplementation( Contract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], constructorArgs?: unknown[], timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, getTxResponse?: boolean, kind?: 'uups' | 'transparent' | 'beacon', useDefenderDeploy?: boolean, , ): Promise Validates and deploys an implementation contract, and returns its address. **Parameters:** * `Contract` - an ethers contract factory to use as the implementation. * `opts` - an object with options: * `getTxResponse`: if set to `true`, causes this function to return an ethers transaction response corresponding to the deployment of the new implementation contract instead of its address. Note that if the new implementation contract was originally imported as a result of `forceImport`, only the address will be returned. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * the address or an ethers transaction response corresponding to the deployment of the implementation contract. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [validateUpgrade](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#validateupgrade) ------------------------------------------------------------------------------------------------------- async function validateUpgrade( referenceAddressOrContract: string | ethers.ContractFactory, newContract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, kind?: 'uups' | 'transparent' | 'beacon', , ): Promise Validates a new implementation contract without deploying it and without actually upgrading to it. Compares the current implementation contract to the new implementation contract to check for storage layout compatibility errors. If `referenceAddressOrContract` is the current implementation address, the `kind` option is required. **Parameters:** * `referenceAddressOrContract` - a proxy or beacon address that uses the current implementation, or an address or ethers contract factory corresponding to the current implementation. * `newContract` - the new implementation contract. * `opts` - an object with options: * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` **Examples:** Validate upgrading an existing proxy to a new contract (replace `PROXY_ADDRESS` with the address of your proxy): const ethers, upgrades = require('hardhat'); const BoxV2 = await ethers.getContractFactory('BoxV2'); await upgrades.validateUpgrade(PROXY_ADDRESS, BoxV2); Validate upgrading between two contract implementations: const ethers, upgrades = require('hardhat'); const Box = await ethers.getContractFactory('Box'); const BoxV2 = await ethers.getContractFactory('BoxV2'); await upgrades.validateUpgrade(Box, BoxV2); [prepareUpgrade](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#prepareupgrade) ----------------------------------------------------------------------------------------------------- async function prepareUpgrade( referenceAddressOrContract: string | ethers.Contract, Contract: ethers.ContractFactory, opts?: unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, constructorArgs?: unknown[], timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', txOverrides?: ethers.Overrides, getTxResponse?: boolean, kind?: 'uups' | 'transparent' | 'beacon', useDefenderDeploy?: boolean, , ): Promise Validates and deploys a new implementation contract, and returns its address. If `referenceAddressOrContract` is the current implementation address, the `kind` option is required. Use this method to prepare an upgrade to be run from an admin address you do not control directly or cannot use from Hardhat. **Parameters:** * `referenceAddressOrContract` - the proxy or beacon or implementation address or contract instance. * `Contract` - the new implementation contract. * `opts` - an object with options: * `getTxResponse`: if set to `true`, causes this function to return an ethers transaction response corresponding to the deployment of the new implementation contract instead of its address. Note that if the new implementation contract was originally imported as a result of `forceImport`, only the address will be returned. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * the address or an ethers transaction response corresponding to the deployment of the new implementation contract. [defender.deployContract](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defenderdeploycontract) ---------------------------------------------------------------------------------------------------------------------- async function deployContract( Contract: ethers.ContractFactory, args: unknown[] = [], opts?: unsafeAllowDeployContract?: boolean, pollingInterval?: number, , ): Promise Deploys a non-upgradeable contract using OpenZeppelin Defender, and returns a contract instance. Throws an error if the contract looks like an implementation contract. Do not use this function to deploy implementations of upgradeable contracts, because upgrade safety validations are not performed with this function. For implementation contracts, use [deployImplementation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deployimplementation) instead. **Parameters:** * `Contract` - an ethers contract factory to use as the contract to deploy. * `opts` - an object with options: * `unsafeAllowDeployContract`: if set to `true`, allows the contract to be deployed even if it looks like an implementation contract. Defaults to `false`. * `pollingInterval`: polling interval in milliseconds between checks for the transaction confirmation when calling `.waitForDeployment()` on the resulting contract instance. Defaults to `5000`. **Returns:** * the contract instance. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [defender.getDeployApprovalProcess](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defendergetdeployapprovalprocess) ------------------------------------------------------------------------------------------------------------------------------------------ async function getDeployApprovalProcess( ): Promise< approvalProcessId: string, address?: string, viaType?: 'EOA' | 'Contract' | 'Multisig' | 'Safe' | 'Gnosis Multisig' | 'Relayer' | 'Unknown' | 'Timelock Controller' | 'ERC20' | 'Governor' | 'Fireblocks', > Gets the default deploy approval process configured for your deployment environment on OpenZeppelin Defender. **Returns:** * an object with the default deploy approval process ID and the associated address, such as a Relayer, EOA, or multisig wallet address. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [defender.getUpgradeApprovalProcess](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defendergetupgradeapprovalprocess) -------------------------------------------------------------------------------------------------------------------------------------------- async function getUpgradeApprovalProcess( ): Promise< approvalProcessId: string, address?: string, viaType?: 'EOA' | 'Contract' | 'Multisig' | 'Safe' | 'Gnosis Multisig' | 'Relayer' | 'Unknown' | 'Timelock Controller' | 'ERC20' | 'Governor' | 'Fireblocks', > Gets the default upgrade approval process configured for your deployment environment on OpenZeppelin Defender. For example, this is useful for determining the default multisig wallet that you can use in your scripts to assign as the owner of your proxy. **Returns:** * an object with the default upgrade approval process ID and the associated address, such as a multisig or governor contract address. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [defender.proposeUpgradeWithApproval](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defenderproposeupgradewithapproval) ---------------------------------------------------------------------------------------------------------------------------------------------- async function proposeUpgradeWithApproval( proxyAddress: string, ImplFactory: ContractFactory, opts?: unsafeAllow?: ValidationError[], unsafeAllowRenames?: boolean, unsafeSkipStorageCheck?: boolean, constructorArgs?: unknown[], timeout?: number, pollingInterval?: number, redeployImplementation?: 'always' | 'never' | 'onchange', kind?: 'uups' | 'transparent' | 'beacon', useDefenderDeploy?: boolean, approvalProcessId?: string, , ): Promise< proposalId: string, url: string, txResponse?: ethers.providers.TransactionResponse, > Proposes an upgrade using an upgrade approval process on OpenZeppelin Defender. Similar to `prepareUpgrade`. This method validates and deploys the new implementation contract, but also proposes an upgrade using an upgrade approval process on OpenZeppelin Defender. Supported for UUPS or Transparent proxies. Not currently supported for beacon proxies or beacons. For beacons, use `prepareUpgrade` along with a transaction proposal on Defender to upgrade the beacon to the deployed implementation. **Parameters:** * `proxyAddress` - the proxy address. * `ImplFactory` - the new implementation contract. * `opts` - an object with options: * `approvalProcessId`: The ID of the upgrade approval process. Defaults to the upgrade approval process configured for your deployment environment on Defender. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Returns:** * an object with the Defender proposal ID, the URL of the proposal in Safe App if applicable, and the ethers transaction response corresponding to the deployment of the new implementation contract. Note that if the new implementation contract was originally imported as a result of `forceImport`, the ethers transaction response will be undefined. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [admin.changeProxyAdmin](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#adminchangeproxyadmin) -------------------------------------------------------------------------------------------------------------------- async function changeProxyAdmin( proxyAddress: string, newAdmin: string, signer?: ethers.Signer, opts?: txOverrides?: ethers.Overrides, ): Promise Changes the admin for a specific proxy. This function is not supported with admins or proxies from OpenZeppelin Contracts 5.x. **Parameters:** * `proxyAddress` - the address of the proxy to change. * `newAdmin` - the new admin address. * `signer` - the signer to use for the transaction. * `opts` - an object with options: * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . [admin.transferProxyAdminOwnership](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#admintransferproxyadminownership) ------------------------------------------------------------------------------------------------------------------------------------------ async function transferProxyAdminOwnership( proxyAddress: string, newOwner: string, signer?: ethers.Signer, opts?: silent?: boolean, txOverrides?: ethers.Overrides, ): Promise Changes the owner of the proxy admin contract for a specific proxy. The `proxyAddress` parameter is required since `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` **Parameters:** * `proxyAddress` - the address of the proxy whose admin ownership is to be transferred. * `newOwner` - the new owner address for the proxy admin contract. * `signer` - the signer to use for the transaction. * `opts` - an object with options: * `silent`: if set to `true`, silences console logging about each proxy affected by the admin ownership transfer. * additional options as described in [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) . **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [erc1967](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#erc1967) --------------------------------------------------------------------------------------- async function erc1967.getImplementationAddress(proxyAddress: string): Promise; async function erc1967.getBeaconAddress(proxyAddress: string): Promise; async function erc1967.getAdminAddress(proxyAddress: string): Promise; Functions in this module provide access to the [ERC1967](https://eips.ethereum.org/EIPS/eip-1967) variables of a proxy contract. **Parameters:** * `proxyAddress` - the proxy address. **Returns:** * the implementation, beacon, or admin address depending on the function called. [beacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#beacon) ------------------------------------------------------------------------------------- async function beacon.getImplementationAddress(beaconAddress: string): Promise; This module provides a convenience function to get the implementation address from a beacon contract. **Parameters:** * `beaconAddress` - the beacon address. **Returns:** * the implementation address. **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` [silenceWarnings](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#silencewarnings) ------------------------------------------------------------------------------------------------------- function silenceWarnings() This function is useful for tests, but its use in production deployment scripts is discouraged. Silences all subsequent warnings about the use of unsafe flags. Prints a last warning before doing so. [verify](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#verify) ------------------------------------------------------------------------------------- Extends [hardhat-verify](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify) 's `verify` task to completely verify a proxy on Etherscan. This supports verifying proxy contracts that were deployed by the Hardhat Upgrades plugin. The arguments are the same as for hardhat-verify’s `verify` task. If the provided address is a proxy, this task will verify the proxy’s implementation contract, the proxy itself and any proxy-related contracts, as well as link the proxy to the implementation contract’s ABI on Etherscan. If the provided address is not a proxy, the regular `verify` task from hardhat-verify will be run on the address instead. The following contracts will be verified when you run this task on your proxy address: * Your implementation contract * [ERC1967Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy) or [TransparentUpgradeableProxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) or [BeaconProxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) (for UUPS, transparent, or beacon proxies, respectively) * [ProxyAdmin](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) (with transparent proxies) * [UpgradeableBeacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) (with beacon proxies) **Since:** * `@openzeppelin/[[email protected]](https://docs.openzeppelin.com/cdn-cgi/l/email-protection) ` **Usage:** To use this task, ensure you have hardhat-verify installed: npm install --save-dev @nomicfoundation/hardhat-verify Then import the `@nomicfoundation/hardhat-verify` plugin along with the `@openzeppelin/hardhat-upgrades` plugin in your Hardhat configuration. For example, if you are using JavaScript, import the plugins in `hardhat.config.js`: require("@nomicfoundation/hardhat-verify"); require("@openzeppelin/hardhat-upgrades"); Or if you are using TypeScript, import the plugins in `hardhat.config.ts`: import "@nomicfoundation/hardhat-verify"; import "@openzeppelin/hardhat-upgrades"; Finally, follow [hardhat-verify’s usage documentation](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#usage) to configure your Etherscan API key and run the `verify` task from the command line with the proxy address: npx hardhat verify --network mainnet PROXY_ADDRESS or programmatically using the [`verify:verify` subtask](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#using-programmatically) : await hre.run("verify:verify", address: PROXY_ADDRESS, ); Note that you do not need to include constructor arguments when verifying if your implementation contract only uses initializers. However, if your implementation contract has an actual constructor with arguments (such as to set immutable variables), then include constructor arguments according to the usage information for the [task](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#usage) or [subtask](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#using-programmatically) . ### On this page [Common Options](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#common-options) [deployProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deployproxy) [upgradeProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#upgradeproxy) [deployBeacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deploybeacon) [upgradeBeacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#upgradebeacon) [deployBeaconProxy](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deploybeaconproxy) [forceImport](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#forceimport) [validateImplementation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#validateimplementation) [deployImplementation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#deployimplementation) [validateUpgrade](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#validateupgrade) [prepareUpgrade](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#prepareupgrade) [defender.deployContract](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defenderdeploycontract) [defender.getDeployApprovalProcess](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defendergetdeployapprovalprocess) [defender.getUpgradeApprovalProcess](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defendergetupgradeapprovalprocess) [defender.proposeUpgradeWithApproval](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#defenderproposeupgradewithapproval) [admin.changeProxyAdmin](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#adminchangeproxyadmin) [admin.transferProxyAdminOwnership](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#admintransferproxyadminownership) [erc1967](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#erc1967) [beacon](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#beacon) [silenceWarnings](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#silencewarnings) [verify](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades#verify) --- # Custom Scripts | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Custom Scripts ============== Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) OpenZeppelin Monitor allows you to implement custom scripts for additional filtering of monitor matches and custom notification handling. _**Security Risk:**_ Only run scripts that you trust and fully understand. Malicious scripts can harm your system or expose sensitive data. Always review script contents and verify their source before execution. [Custom Filter Scripts](https://docs.openzeppelin.com/monitor/scripts#custom-filter-scripts) --------------------------------------------------------------------------------------------- Custom filter scripts allow you to apply additional conditions to matches detected by the monitor. This helps you refine the alerts you receive based on criteria specific to your use case. ### [Implementation Guide](https://docs.openzeppelin.com/monitor/scripts#implementation-guide) 1. Create a script in one of the supported languages: * Bash * Python * JavaScript 2. Your script will receive a JSON object with the following structure: * EVM { "args": ["--verbose"], "monitor_match": { "EVM": { "matched_on": { "events": [], "functions": [\ {\ "expression": null,\ "signature": "transfer(address,uint256)"\ }\ ], "transactions": [\ {\ "expression": null,\ "status": "Success"\ }\ ] }, "matched_on_args": { "events": null, "functions": [\ {\ "args": [\ {\ "indexed": false,\ "kind": "address",\ "name": "to",\ "value": "0x94d953b148d4d7143028f397de3a65a1800f97b3"\ },\ {\ "indexed": false,\ "kind": "uint256",\ "name": "value",\ "value": "434924400"\ }\ ],\ "hex_signature": "a9059cbb",\ "signature": "transfer(address,uint256)"\ }\ ] }, "monitor": { "addresses": [\ {\ "contract_spec": null,\ "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"\ }\ ], "match_conditions": { "events": [\ {\ "expression": "value > 10000000000",\ "signature": "Transfer(address,address,uint256)"\ }\ ], "functions": [\ {\ "expression": null,\ "signature": "transfer(address,uint256)"\ }\ ], "transactions": [\ {\ "expression": null,\ "status": "Success"\ }\ ] }, "name": "Large Transfer of USDC Token", "networks": ["ethereum_mainnet"], "paused": false, "trigger_conditions": [\ {\ "arguments": ["--verbose"],\ "language": "Bash",\ "script_path": "./config/filters/evm_filter_block_number.sh",\ "timeout_ms": 1000\ }\ ], "triggers": ["evm_large_transfer_usdc_script"] }, "receipt": { "blockHash": "0x...", "blockNumber": "0x...", "contractAddress": null, "cumulativeGasUsed": "0x...", "effectiveGasPrice": "0x...", "from": "0x...", "gasUsed": "0xb068", "status": "0x1", "to": "0x...", "transactionHash": "0x...", "transactionIndex": "0x1fc", "type": "0x2" }, "logs": [\ {\ "address": "0xd1f2586790a5bd6da1e443441df53af6ec213d83",\ "topics": [\ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\ "0x00000000000000000000000060af8cf92e5aa9ead4a592d657cd6debecfbc616",\ "0x000000000000000000000000d1f2586790a5bd6da1e443441df53af6ec213d83"\ ],\ "data": "0x00000000000000000000000000000000000000000000106015728793d21f77ac",\ "blockNumber": "0x1451aca",\ "transactionHash": "0xa39d1b9b3edda74414bd6ffaf6596f8ea12cf0012fd9a930f71ed69df6ff34d0",\ "transactionIndex": "0x0",\ "blockHash": "0x9432868b7fc57e85f0435ca3047f6a76add86f804b3c1af85647520061e30f80",\ "logIndex": "0x2",\ "removed": false\ }\ ], "transaction": { "accessList": [], "blockHash": "0x...", "blockNumber": "0x1506545", "chainId": "0x1", "from": "0x...", "gas": "0x7a120", "gasPrice": "0x...", "hash": "0x...", "maxFeePerGas": "0x...", "maxPriorityFeePerGas": "0x...", "nonce": "0x14779f", "to": "0x...", "transactionIndex": "0x...", "type": "0x2", "value": "0x0" } } } } * Stellar { "args": ["--verbose"], "monitor_match": { "Stellar": { "monitor": { "name": "Large Swap By Dex", "networks": ["stellar_mainnet"], "paused": false, "addresses": [\ {\ "address": "GCXYK...",\ "contract_spec": null\ }\ ], "match_conditions": { "functions": [\ {\ "signature": "swap(Address,U32,U32,U128,U128)",\ "expression": "out_min > 1000000000"\ }\ ], "events": [], "transactions": [] }, "trigger_conditions": [\ {\ "arguments": ["--verbose"],\ "language": "Bash",\ "script_path": "./config/filters/stellar_filter_block_number.sh",\ "timeout_ms": 1000\ }\ ], "triggers": ["stellar_large_transfer_usdc_script"] }, "transaction": { "status": "SUCCESS", "txHash": "2b5a0c...", "applicationOrder": 3, "feeBump": false, "envelopeXdr": "AAAAAA...", "envelopeJson": { "type": "ENVELOPE_TYPE_TX", "tx": {/* transaction details */} }, "resultXdr": "AAAAAA...", "resultJson": /* result details */, "resultMetaXdr": "AAAAAA...", "resultMetaJson": /* metadata details */, "diagnosticEventsXdr": ["AAAAAA..."], "diagnosticEventsJson": [/* event details */], "ledger": 123456, "createdAt": 1679644800, "decoded": { "envelope": {/* decoded envelope */}, "result": /* decoded result */, "meta": /* decoded metadata */ } }, "ledger": { "hash": "abc1...", "sequence": 123456, "ledgerCloseTime": "2024-03-20T10:00:00Z", "headerXdr": "AAAAAA...", "headerJson": {/* header details */}, "metadataXdr": "AAAAAA...", "metadataJSON": /* metadata details */ }, "matched_on": { "functions": [\ {\ "signature": "swap(Address,U32,U32,U128,U128)",\ "expression": "out_min > 1000000000"\ }\ ], "events": [], "transactions": [] }, "matched_on_args": { "functions": [], "events": null } } } } ### [Script Output Requirements](https://docs.openzeppelin.com/monitor/scripts#script-output-requirements) * Your script should print a boolean value indicating whether the match should be filtered. * Print `true` if the match should be filtered out (not trigger an alert). * Print `false` if the match should be processed (trigger an alert). * Only the **last** printed line will be considered for evaluation. ### [Example Filter Script (Bash)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-bash) #!/bin/bash main() { # Read JSON input from stdin input_json=$(cat) # Parse arguments from the input JSON and initialize verbose flag verbose=false args=$(echo "$input_json" | jq -r '.args[]? // empty') if [ ! -z "$args" ]; then while IFS= read -r arg; do if [ "$arg" = "--verbose" ]; then verbose=true echo "Verbose mode enabled" fi done <<< "$args" fi # Extract the monitor match data from the input monitor_data=$(echo "$input_json" | jq -r '.monitor_match') if [ "$verbose" = true ]; then echo "Input JSON received:" fi # Extract blockNumber from the EVM receipt or transaction block_number_hex=$(echo "$monitor_data" | jq -r '.EVM.transaction.blockNumber' || echo "") # Validate that block_number_hex is not empty if [ -z "$block_number_hex" ]; then echo "Invalid JSON or missing blockNumber" echo "false" exit 1 fi # Remove 0x prefix if present and clean the string block_number_hex=$(echo "$block_number_hex" | tr -d '\n' | tr -d ' ') block_number_hex=${block_number_hex#0x} if [ "$verbose" = true ]; then echo "Extracted block number (hex): $block_number_hex" fi # Convert hex to decimal with error checking if ! block_number=$(printf "%d" $((16#$block_number_hex)) 2>/dev/null); then echo "Failed to convert hex to decimal" echo "false" exit 1 fi if [ "$verbose" = true ]; then echo "Converted block number (decimal): $block_number" fi # Check if even or odd using modulo is_even=$((block_number % 2)) if [ $is_even -eq 0 ]; then echo "Block number $block_number is even" echo "Verbose mode: $verbose" echo "true" exit 0 else echo "Block number $block_number is odd" echo "Verbose mode: $verbose" echo "false" exit 0 fi } # Call main function main ### [Example Filter Script (JavaScript)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-javascript) #!/usr/bin/env node try { let inputData = ''; // Read from stdin process.stdin.on('data', chunk => { inputData += chunk; }); process.stdin.on('end', () => { const data = JSON.parse(inputData); const monitorMatch = data.monitor_match; const args = data.args; // Extract block_number let blockNumber = null; if (monitorMatch.EVM) { const hexBlock = monitorMatch.EVM.transaction?.blockNumber; if (hexBlock) { // Convert hex string to integer blockNumber = parseInt(hexBlock, 16); } } if (blockNumber === null) { console.log('false'); return; } const result = blockNumber % 2 === 0; console.log(`Block number ${blockNumber} is ${result ? 'even' : 'odd'}`); console.log(result.toString()); }); } catch (e) { console.log(`Error processing input: ${e}`); console.log('false'); } ### [Example Filter Script (Python)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-python) #!/usr/bin/env python3 import sys import json def main(): try: # Read input from stdin input_data = sys.stdin.read() if not input_data: print("No input JSON provided", flush=True) return False # Parse input JSON try: data = json.loads(input_data) monitor_match = data['monitor_match'] args = data['args'] except json.JSONDecodeError as e: print(f"Invalid JSON input: {e}", flush=True) return False # Extract block_number block_number = None if "EVM" in monitor_match: hex_block = monitor_match['EVM']['transaction'].get('blockNumber') if hex_block: # Convert hex string to integer block_number = int(hex_block, 16) if block_number is None: print("Block number is None") return False result = block_number % 2 == 0 print(f"Block number {block_number} is {'even' if result else 'odd'}", flush=True) return result except Exception as e: print(f"Error processing input: {e}", flush=True) return False if __name__ == "__main__": result = main() # Print the final boolean result print(str(result).lower(), flush=True) This examples script filters EVM transactions based on their block number: * Returns `true` (filter out) for transactions in even-numbered blocks * Returns `false` (allow) for transactions in odd-numbered blocks * Accepts a `--verbose` flag for detailed logging * Explore other examples in the [`examples/config/filters` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/filters) . ### [Integration](https://docs.openzeppelin.com/monitor/scripts#integration) Integrate your custom filter script with the monitor by following the [configuration guidelines](https://docs.openzeppelin.com/monitor#trigger-conditions-custom-filters) . Trigger conditions are executed sequentially based on their position in the trigger conditions array. Every filter must return `false` for the match to be included and are only considered if they were executed successfully. [Custom Notification Scripts](https://docs.openzeppelin.com/monitor/scripts#custom-notification-scripts) --------------------------------------------------------------------------------------------------------- Custom notification scripts allow you to define how alerts are delivered when specific conditions are met. This can include sending alerts to different channels or formatting notifications in a particular way. ### [Implementation Guide](https://docs.openzeppelin.com/monitor/scripts#implementation-guide-1) 1. Create a script in one of the supported languages: * Bash * Python * JavaScript 2. Your script will receive the same JSON input format as [filter scripts](https://docs.openzeppelin.com/monitor/scripts#implementation-guide) ### [Script Output Requirements](https://docs.openzeppelin.com/monitor/scripts#script-output-requirements-1) * A non-zero exit code indicates an error occurred * Error messages should be written to `stderr` * A zero exit code indicates successful execution ### [Example Notification Script (Bash)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-bash) #!/bin/bash main() { # Read JSON input from stdin input_json=$(cat) # Parse arguments from the input JSON and initialize verbose flag verbose=false args=$(echo "$input_json" | jq -r '.args[]? // empty') if [ ! -z "$args" ]; then while IFS= read -r arg; do if [ "$arg" = "--verbose" ]; then verbose=true echo "Verbose mode enabled" fi done <<< "$args" fi # Extract the monitor match data from the input monitor_data=$(echo "$input_json" | jq -r '.monitor_match') # Validate input if [ -z "$input_json" ]; then echo "No input JSON provided" exit 1 fi # Validate JSON structure if ! echo "$input_json" | jq . >/dev/null 2>&1; then echo "Invalid JSON input" exit 1 fi if [ "$verbose" = true ]; then echo "Input JSON received:" echo "$input_json" | jq '.' echo "Monitor match data:" echo "$monitor_data" | jq '.' fi # Process args if they exist args_data=$(echo "$input_json" | jq -r '.args') if [ "$args_data" != "null" ]; then echo "Args: $args_data" fi # If we made it here, everything worked echo "Verbose mode: $verbose" # return a non zero exit code and an error message echo "Error: This is a test error" >&2 exit 1 } # Call main function main ### [Example Notification Script (JavaScript)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-javascript) #!/usr/bin/env node try { let inputData = ''; // Read from stdin process.stdin.on('data', chunk => { inputData += chunk; }); process.stdin.on('end', () => { // Parse input JSON const data = JSON.parse(inputData); const monitorMatch = data.monitor_match; const args = data.args; // Log args if they exist if (args && args.length > 0) { console.log(`Args: ${JSON.stringify(args)}`); } // Validate monitor match data if (!monitorMatch) { console.log("No monitor match data provided"); return; } }); } catch (e) { console.log(`Error processing input: ${e}`); } ### [Example Notification Script (Python)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-python) #!/usr/bin/env python3 import sys import json def main(): try: # Read input from stdin input_data = sys.stdin.read() if not input_data: print("No input JSON provided", flush=True) return # Parse input JSON try: data = json.loads(input_data) monitor_match = data['monitor_match'] args = data['args'] if args: print(f"Args: {args}") except json.JSONDecodeError as e: print(f"Invalid JSON input: {e}", flush=True) return except Exception as e: print(f"Error processing input: {e}", flush=True) if __name__ == "__main__": main() This examples demonstrates how to: * Process the input JSON data * Handle verbose mode for debugging * Return error messages via `stderr` * Set appropriate exit codes * Explore other examples in the [`examples/config/triggers/scripts` directory](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/main/examples/config/triggers/scripts) . ### [Integration](https://docs.openzeppelin.com/monitor/scripts#integration-1) Integrate your custom notification script with the triggers by following the [configuration guidelines](https://docs.openzeppelin.com/monitor#custom-script-notifications) . [Performance Considerations](https://docs.openzeppelin.com/monitor/scripts#performance-considerations) ------------------------------------------------------------------------------------------------------- * **File descriptor limits**: Each script execution requires file descriptors for `stdin`, `stdout`, and `stderr` * Ensure your system allows at least 2,048 open file descriptors * Check your current limit on Unix-based systems with `ulimit -n` * Temporarily increase the limit with `ulimit -n 2048` * For permanent changes, modify `/etc/security/limits.conf` or equivalent for your system * **Script timeout**: Configure appropriate timeout values in your trigger conditions to prevent long-running scripts from blocking the pipeline * The `timeout_ms` parameter controls how long a script can run before being terminated * **Resource usage**: Complex scripts may consume significant CPU or memory resources * Consider optimizing resource-intensive operations in your scripts * Monitor system performance during high-volume periods * **Script reloading**: Since scripts are loaded at startup, any modifications to script files require restarting the monitor to take effect [RPC Client\ \ Previous Page](https://docs.openzeppelin.com/monitor/rpc) [Error Handling\ \ Next Page](https://docs.openzeppelin.com/monitor/error) ### On this page [Custom Filter Scripts](https://docs.openzeppelin.com/monitor/scripts#custom-filter-scripts) [Implementation Guide](https://docs.openzeppelin.com/monitor/scripts#implementation-guide) [Script Output Requirements](https://docs.openzeppelin.com/monitor/scripts#script-output-requirements) [Example Filter Script (Bash)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-bash) [Example Filter Script (JavaScript)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-javascript) [Example Filter Script (Python)](https://docs.openzeppelin.com/monitor/scripts#example-filter-script-python) [Integration](https://docs.openzeppelin.com/monitor/scripts#integration) [Custom Notification Scripts](https://docs.openzeppelin.com/monitor/scripts#custom-notification-scripts) [Implementation Guide](https://docs.openzeppelin.com/monitor/scripts#implementation-guide-1) [Script Output Requirements](https://docs.openzeppelin.com/monitor/scripts#script-output-requirements-1) [Example Notification Script (Bash)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-bash) [Example Notification Script (JavaScript)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-javascript) [Example Notification Script (Python)](https://docs.openzeppelin.com/monitor/scripts#example-notification-script-python) [Integration](https://docs.openzeppelin.com/monitor/scripts#integration-1) [Performance Considerations](https://docs.openzeppelin.com/monitor/scripts#performance-considerations) --- # WebAuthn Smart Accounts | OpenZeppelin Docs Learn WebAuthn Smart Accounts ======================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Account abstraction is becoming a vital tool to advance onchain technology for everyday users, making it easier to create and use a wallet without needing to handle a private key. One of the most popular forms of this is through [Passkeys](https://www.webauthn.me/passkeys) , which use the WebAuthn standard to create cryptographic [Authentication Assertions](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion) across multiple devices and ecosystems. OpenZeppelin's `WebAuthn.sol` contract enables smart accounts to verify these WebAuthn assertions onchain. This creates a powerful and secure user experience that leverages biometrics and industry-standard cryptography for wallet interactions. In this tutorial we'll show you how you can build fullstack application that allows users to create smart accounts with WebAuthn passkeys and conduct an example user operation like minting an NFT. [Prerequisites](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#prerequisites) --------------------------------------------------------------------------------------------------------- Before we get started make sure you have the following installed * [`Node.js`](https://nodejs.org/en/download) * [`pnpm`](https://pnpm.io/installation) * [`Foundry`](https://getfoundry.sh/introduction/installation) Once you have confirmed those are all installed, let's make sure we have a wallet setup with Foundry. If you already have one setup and funded with testnet eth, you can skip this part. ### [Wallet Setup](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#wallet-setup) To make a new wallet run the following command: Shell cast wallet new -p ~/.foundry/keystores sepolia This will prompt you for a password and then create a new keypair and encrypt the private key locally, which is much safer than working with plain text private keys. The public address should be printed when you create the wallet but you can retrieve it at any time with the following command: Shell cast wallet address --account sepolia Make sure to only use this wallet for testnet funds! ### [Project Structure](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#project-structure) For context our final project will look something like this . └── contracts // Smart contracts └── server // Secure server environment └── shared // Shared addresses and ABIs └── client // Web UI Let's make an empty directory that will store all of this and then `cd` into it. Shell mkdir webauthn-tutorial cd webauthn-tutorial With the initial structure setup we can move on to initializing the different projects. [Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#contracts) ------------------------------------------------------------------------------------------------- While inside `webauthn-tutorial` run the command below to setup a new foundry project for our contracts, then move into it. Shell forge init contracts cd contracts Inside the `contracts` project go ahead and delete the default `Counter` files like so: Shell rm src/* test/* script/* ### [Setup](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup) Next we'll install the OpenZeppelin contracts library which will include everything else we need to setup a WebAuthn account and factory. Shell foundry install OpenZeppelin/[email protected] For our contracts we need to make three files inside of `src`: * `AccountWebAuthn.sol` - Account implementation using WebAuthn signatures * `AccountFactory.sol` - Account factory * `MyNFT.sol` - Example NFT contract for testing User Operations Inside `AccountWebAuthn.sol` paste in the following code: AccountWebAuthn.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Account} from "@openzeppelin/contracts/account/Account.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol"; import {ERC7821} from "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {SignerWebAuthn} from "@openzeppelin/contracts/utils/cryptography/signers/SignerWebAuthn.sol"; import {SignerP256} from "@openzeppelin/contracts/utils/cryptography/signers/SignerP256.sol"; contract AccountWebAuthn is Initializable, Account, EIP712, ERC7739, ERC7821, SignerWebAuthn, ERC721Holder, ERC1155Holder { constructor() EIP712("AccountWebAuthn", "1") SignerP256( 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 ) {} function initializeWebAuthn(bytes32 qx, bytes32 qy) public initializer { _setSigner(qx, qy); // Set the P256 public key } /** * @dev Override to allow EntryPoint to execute transactions */ function _erc7821AuthorizedExecutor( address caller, bytes32 mode, bytes calldata executionData ) internal view override returns (bool) { return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); } } Let's break down the key components of our WebAuthn account implementation: Our contract inherits from `Account.sol`, which provides the core ERC-4337 functionality, along with `EIP712.sol` for typed data signatures. We also include `ERC721Holder.sol` and `ERC1155Holder.sol` to enable the account to receive NFTs and multi-tokens. The `ERC7739.sol` extension enables readable typed signatures that prevent replay attacks, while `ERC7821.sol` provides the minimal batch executor interface for transaction batching. The account uses a factory pattern with minimal proxies (like `Clones.sol`) for gas-efficient deployment. Since each account is deployed as a proxy, we use an initializer function instead of a constructor to set up the account's state after deployment. WebAuthn verification relies on `P256.sol` elliptic curve operations, which require a valid public key during contract construction. To work around this factory pattern constraint, we provide a dummy public key in the constructor and set the real WebAuthn public key through the `initializeWebAuthn` function. Once initialized, the signer cannot be changed. Now paste the following code into `AccountFactory.sol`: AccountFactory.sol // contracts/AccountFactory.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /** * @dev A factory contract to create accounts on demand. */ contract AccountFactory { using Clones for address; using Address for address; address private immutable _impl; constructor(address impl_) { require(impl_.code.length > 0); _impl = impl_; } /// @dev Predict the address of the account function predictAddress(bytes calldata callData) public view returns (address) { return _impl.predictDeterministicAddress(keccak256(callData), address(this)); } /// @dev Create clone accounts on demand function cloneAndInitialize(bytes calldata callData) public returns (address) { address predicted = predictAddress(callData); if (predicted.code.length == 0) { _impl.cloneDeterministic(keccak256(callData)); predicted.functionCall(callData); } return predicted; } } The factory will take an implementation address which it will use for creating new accounts. There are two public functions; one is to `predictAddress` so we could fund the account before creating if we wanted to, and the second is `cloneAndInitialize` which will create the new account from our implementation address. Finally we'll add the code for `MyNFT.sol`: MyNFT.sol // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Contracts ^5.4.0 pragma solidity ^0.8.27; import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; contract MyNFT is ERC721, Ownable { uint256 private _nextTokenId; constructor(address initialOwner) ERC721("MyNFT", "MYNFT") Ownable(initialOwner) {} function safeMint(address to) public returns (uint256) { uint256 tokenId = _nextTokenId++; _safeMint(to, tokenId); return tokenId; } } This is a really simple NFT contract that has minting enabled, with the small exception that we've removed the `onlyOwner` modifier from the `safeMint` function to make it simpler for our smart account to interact with it. ### [Deployment](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#deployment) With all of our contracts put together we can make a new file under the `script` directory called `Deploy.s.sol` and put the following code inside: Deploy.s.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import "forge-std/Script.sol"; import "../src/AccountWebAuthn.sol"; import "../src/AccountFactory.sol"; import "../src/MyNFT.sol"; contract Deploy is Script { function run() external { uint256 deployerPrivateKey; // Use Anvil's first default account if no private key is provided // Anvil account #0: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 if (vm.envOr("PRIVATE_KEY", uint256(0)) == 0) { deployerPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; console.log("Using Anvil default account"); } else { deployerPrivateKey = vm.envUint("PRIVATE_KEY"); console.log("Using provided private key"); } vm.startBroadcast(deployerPrivateKey); // Deploy AccountWebAuthn implementation AccountWebAuthn accountImpl = new AccountWebAuthn(); console.log("AccountWebAuthn implementation deployed at:", address(accountImpl)); // Deploy AccountFactory with the implementation address AccountFactory accountFactory = new AccountFactory(address(accountImpl)); console.log("AccountFactory deployed at:", address(accountFactory)); // Deploy test NFT MyNFT nftContract = new MyNFT(vm.addr(deployerPrivateKey)); console.log("AccountWebAuthn implementation deployed at:", address(nftContract)); console.log("Deployed by:", vm.addr(deployerPrivateKey)); vm.stopBroadcast(); } } This deployment script will do the following: * Setup the broadcast with our `PRIVATE_KEY` * Deploy the `AccountWebAuthn` implementation contract * Deploy the `AccountFactory` and pass in the recently deployed `AccountWebAuthn` implementation address * Deploy the `MyNFT` contract with our deployer address as the owner Before we can run this script we need to create a `.env` file with the following content: export RPC_URL=https://sepolia.drpc.org export PRIVATE_KEY=$(cast wallet private-key --account sepolia) Thanks to `cast` we can use our wallet private key without keeping it in plain text and instead make it a shell environment variable that can be accessed by Foundry. We're using a public RPC url here but you may want to use one from Alchemy or your DRPC account that won't have rate limits. With that we can go ahead and run the deployment: Shell source .env forge script script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast --verify This should deploy all three contracts and print the addresses for each in the terminal, as well as save them to `broadcast`. ### [Setup Shared Directory](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-shared-directory) By compiling and deploying these contracts we've created the ABI's and Addresses we need across the other pieces of our app. To make it easier to access these constants, let's make make a new directory called `shared`. Shell cd .. # Move out of contracts mkdir shared cd shared Inside the folder create two files and put in the following content: Shell touch index.ts index.ts export * from "./EntrypointV08"; export const FACTORY_ADDRESS = "0xf403e5e9230a233dde99d1c6adffa9d1e81dbd98"; export const NFT_ADDRESS = "0x1936494b8444aF8585873F478dc826C6Ab76582e"; export const ENTRYPOINT_ADDRESS = "0x4337084d9e255ff0702461cf8895ce9e3b5ff108"; export { abi as accountWebAuthnAbi } from "../contracts/out/AccountWebAuthn.sol/AccountWebAuthn.json"; export { abi as accountFactoryAbi } from "../contracts/out/AccountFactory.sol/AccountFactory.json"; export { abi as myNftAbi } from "../contracts/out/MyNFT.sol/MyNFT.json"; One of the pieces we need to use Account Abstraction is the Entrypoint contract. This is a contract that has the same address across every chain and allows us to submit user operations and have them conducted to our smart accounts. You can create a new file inside `shared` called `EntrypointV08.ts` and paste in the contents below: EntrypointV08.ts export const entryPointAbi = [\ { inputs: [], stateMutability: "nonpayable", type: "constructor" },\ {\ inputs: [\ { internalType: "bool", name: "success", type: "bool" },\ { internalType: "bytes", name: "ret", type: "bytes" },\ ],\ name: "DelegateAndRevert",\ type: "error",\ },\ {\ inputs: [\ { internalType: "uint256", name: "opIndex", type: "uint256" },\ { internalType: "string", name: "reason", type: "string" },\ ],\ name: "FailedOp",\ type: "error",\ },\ {\ inputs: [\ { internalType: "uint256", name: "opIndex", type: "uint256" },\ { internalType: "string", name: "reason", type: "string" },\ { internalType: "bytes", name: "inner", type: "bytes" },\ ],\ name: "FailedOpWithRevert",\ type: "error",\ },\ { inputs: [], name: "InvalidShortString", type: "error" },\ {\ inputs: [{ internalType: "bytes", name: "returnData", type: "bytes" }],\ name: "PostOpReverted",\ type: "error",\ },\ { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" },\ {\ inputs: [{ internalType: "address", name: "sender", type: "address" }],\ name: "SenderAddressResult",\ type: "error",\ },\ {\ inputs: [{ internalType: "address", name: "aggregator", type: "address" }],\ name: "SignatureValidationFailed",\ type: "error",\ },\ {\ inputs: [{ internalType: "string", name: "str", type: "string" }],\ name: "StringTooLong",\ type: "error",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "bytes32",\ name: "userOpHash",\ type: "bytes32",\ },\ {\ indexed: true,\ internalType: "address",\ name: "sender",\ type: "address",\ },\ {\ indexed: false,\ internalType: "address",\ name: "factory",\ type: "address",\ },\ {\ indexed: false,\ internalType: "address",\ name: "paymaster",\ type: "address",\ },\ ],\ name: "AccountDeployed",\ type: "event",\ },\ { anonymous: false, inputs: [], name: "BeforeExecution", type: "event" },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "account",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "totalDeposit",\ type: "uint256",\ },\ ],\ name: "Deposited",\ type: "event",\ },\ { anonymous: false, inputs: [], name: "EIP712DomainChanged", type: "event" },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "bytes32",\ name: "userOpHash",\ type: "bytes32",\ },\ {\ indexed: true,\ internalType: "address",\ name: "sender",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "nonce",\ type: "uint256",\ },\ {\ indexed: false,\ internalType: "bytes",\ name: "revertReason",\ type: "bytes",\ },\ ],\ name: "PostOpRevertReason",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "aggregator",\ type: "address",\ },\ ],\ name: "SignatureAggregatorChanged",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "account",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "totalStaked",\ type: "uint256",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "unstakeDelaySec",\ type: "uint256",\ },\ ],\ name: "StakeLocked",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "account",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "withdrawTime",\ type: "uint256",\ },\ ],\ name: "StakeUnlocked",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "account",\ type: "address",\ },\ {\ indexed: false,\ internalType: "address",\ name: "withdrawAddress",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "amount",\ type: "uint256",\ },\ ],\ name: "StakeWithdrawn",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "bytes32",\ name: "userOpHash",\ type: "bytes32",\ },\ {\ indexed: true,\ internalType: "address",\ name: "sender",\ type: "address",\ },\ {\ indexed: true,\ internalType: "address",\ name: "paymaster",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "nonce",\ type: "uint256",\ },\ { indexed: false, internalType: "bool", name: "success", type: "bool" },\ {\ indexed: false,\ internalType: "uint256",\ name: "actualGasCost",\ type: "uint256",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "actualGasUsed",\ type: "uint256",\ },\ ],\ name: "UserOperationEvent",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "bytes32",\ name: "userOpHash",\ type: "bytes32",\ },\ {\ indexed: true,\ internalType: "address",\ name: "sender",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "nonce",\ type: "uint256",\ },\ ],\ name: "UserOperationPrefundTooLow",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "bytes32",\ name: "userOpHash",\ type: "bytes32",\ },\ {\ indexed: true,\ internalType: "address",\ name: "sender",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "nonce",\ type: "uint256",\ },\ {\ indexed: false,\ internalType: "bytes",\ name: "revertReason",\ type: "bytes",\ },\ ],\ name: "UserOperationRevertReason",\ type: "event",\ },\ {\ anonymous: false,\ inputs: [\ {\ indexed: true,\ internalType: "address",\ name: "account",\ type: "address",\ },\ {\ indexed: false,\ internalType: "address",\ name: "withdrawAddress",\ type: "address",\ },\ {\ indexed: false,\ internalType: "uint256",\ name: "amount",\ type: "uint256",\ },\ ],\ name: "Withdrawn",\ type: "event",\ },\ {\ inputs: [\ { internalType: "uint32", name: "unstakeDelaySec", type: "uint32" },\ ],\ name: "addStake",\ outputs: [],\ stateMutability: "payable",\ type: "function",\ },\ {\ inputs: [{ internalType: "address", name: "account", type: "address" }],\ name: "balanceOf",\ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [\ { internalType: "address", name: "target", type: "address" },\ { internalType: "bytes", name: "data", type: "bytes" },\ ],\ name: "delegateAndRevert",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [{ internalType: "address", name: "account", type: "address" }],\ name: "depositTo",\ outputs: [],\ stateMutability: "payable",\ type: "function",\ },\ {\ inputs: [],\ name: "eip712Domain",\ outputs: [\ { internalType: "bytes1", name: "fields", type: "bytes1" },\ { internalType: "string", name: "name", type: "string" },\ { internalType: "string", name: "version", type: "string" },\ { internalType: "uint256", name: "chainId", type: "uint256" },\ { internalType: "address", name: "verifyingContract", type: "address" },\ { internalType: "bytes32", name: "salt", type: "bytes32" },\ { internalType: "uint256[]", name: "extensions", type: "uint256[]" },\ ],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [{ internalType: "address", name: "account", type: "address" }],\ name: "getDepositInfo",\ outputs: [\ {\ components: [\ { internalType: "uint256", name: "deposit", type: "uint256" },\ { internalType: "bool", name: "staked", type: "bool" },\ { internalType: "uint112", name: "stake", type: "uint112" },\ { internalType: "uint32", name: "unstakeDelaySec", type: "uint32" },\ { internalType: "uint48", name: "withdrawTime", type: "uint48" },\ ],\ internalType: "struct IStakeManager.DepositInfo",\ name: "info",\ type: "tuple",\ },\ ],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [],\ name: "getDomainSeparatorV4",\ outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [\ { internalType: "address", name: "sender", type: "address" },\ { internalType: "uint192", name: "key", type: "uint192" },\ ],\ name: "getNonce",\ outputs: [{ internalType: "uint256", name: "nonce", type: "uint256" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [],\ name: "getPackedUserOpTypeHash",\ outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],\ stateMutability: "pure",\ type: "function",\ },\ {\ inputs: [{ internalType: "bytes", name: "initCode", type: "bytes" }],\ name: "getSenderAddress",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ {\ components: [\ { internalType: "address", name: "sender", type: "address" },\ { internalType: "uint256", name: "nonce", type: "uint256" },\ { internalType: "bytes", name: "initCode", type: "bytes" },\ { internalType: "bytes", name: "callData", type: "bytes" },\ {\ internalType: "bytes32",\ name: "accountGasLimits",\ type: "bytes32",\ },\ {\ internalType: "uint256",\ name: "preVerificationGas",\ type: "uint256",\ },\ { internalType: "bytes32", name: "gasFees", type: "bytes32" },\ { internalType: "bytes", name: "paymasterAndData", type: "bytes" },\ { internalType: "bytes", name: "signature", type: "bytes" },\ ],\ internalType: "struct PackedUserOperation",\ name: "userOp",\ type: "tuple",\ },\ ],\ name: "getUserOpHash",\ outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [\ {\ components: [\ {\ components: [\ { internalType: "address", name: "sender", type: "address" },\ { internalType: "uint256", name: "nonce", type: "uint256" },\ { internalType: "bytes", name: "initCode", type: "bytes" },\ { internalType: "bytes", name: "callData", type: "bytes" },\ {\ internalType: "bytes32",\ name: "accountGasLimits",\ type: "bytes32",\ },\ {\ internalType: "uint256",\ name: "preVerificationGas",\ type: "uint256",\ },\ { internalType: "bytes32", name: "gasFees", type: "bytes32" },\ {\ internalType: "bytes",\ name: "paymasterAndData",\ type: "bytes",\ },\ { internalType: "bytes", name: "signature", type: "bytes" },\ ],\ internalType: "struct PackedUserOperation[]",\ name: "userOps",\ type: "tuple[]",\ },\ {\ internalType: "contract IAggregator",\ name: "aggregator",\ type: "address",\ },\ { internalType: "bytes", name: "signature", type: "bytes" },\ ],\ internalType: "struct IEntryPoint.UserOpsPerAggregator[]",\ name: "opsPerAggregator",\ type: "tuple[]",\ },\ { internalType: "address payable", name: "beneficiary", type: "address" },\ ],\ name: "handleAggregatedOps",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ {\ components: [\ { internalType: "address", name: "sender", type: "address" },\ { internalType: "uint256", name: "nonce", type: "uint256" },\ { internalType: "bytes", name: "initCode", type: "bytes" },\ { internalType: "bytes", name: "callData", type: "bytes" },\ {\ internalType: "bytes32",\ name: "accountGasLimits",\ type: "bytes32",\ },\ {\ internalType: "uint256",\ name: "preVerificationGas",\ type: "uint256",\ },\ { internalType: "bytes32", name: "gasFees", type: "bytes32" },\ { internalType: "bytes", name: "paymasterAndData", type: "bytes" },\ { internalType: "bytes", name: "signature", type: "bytes" },\ ],\ internalType: "struct PackedUserOperation[]",\ name: "ops",\ type: "tuple[]",\ },\ { internalType: "address payable", name: "beneficiary", type: "address" },\ ],\ name: "handleOps",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [{ internalType: "uint192", name: "key", type: "uint192" }],\ name: "incrementNonce",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ { internalType: "bytes", name: "callData", type: "bytes" },\ {\ components: [\ {\ components: [\ { internalType: "address", name: "sender", type: "address" },\ { internalType: "uint256", name: "nonce", type: "uint256" },\ {\ internalType: "uint256",\ name: "verificationGasLimit",\ type: "uint256",\ },\ {\ internalType: "uint256",\ name: "callGasLimit",\ type: "uint256",\ },\ {\ internalType: "uint256",\ name: "paymasterVerificationGasLimit",\ type: "uint256",\ },\ {\ internalType: "uint256",\ name: "paymasterPostOpGasLimit",\ type: "uint256",\ },\ {\ internalType: "uint256",\ name: "preVerificationGas",\ type: "uint256",\ },\ { internalType: "address", name: "paymaster", type: "address" },\ {\ internalType: "uint256",\ name: "maxFeePerGas",\ type: "uint256",\ },\ {\ internalType: "uint256",\ name: "maxPriorityFeePerGas",\ type: "uint256",\ },\ ],\ internalType: "struct EntryPoint.MemoryUserOp",\ name: "mUserOp",\ type: "tuple",\ },\ { internalType: "bytes32", name: "userOpHash", type: "bytes32" },\ { internalType: "uint256", name: "prefund", type: "uint256" },\ { internalType: "uint256", name: "contextOffset", type: "uint256" },\ { internalType: "uint256", name: "preOpGas", type: "uint256" },\ ],\ internalType: "struct EntryPoint.UserOpInfo",\ name: "opInfo",\ type: "tuple",\ },\ { internalType: "bytes", name: "context", type: "bytes" },\ ],\ name: "innerHandleOp",\ outputs: [\ { internalType: "uint256", name: "actualGasCost", type: "uint256" },\ ],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ { internalType: "address", name: "", type: "address" },\ { internalType: "uint192", name: "", type: "uint192" },\ ],\ name: "nonceSequenceNumber",\ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [],\ name: "senderCreator",\ outputs: [\ { internalType: "contract ISenderCreator", name: "", type: "address" },\ ],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }],\ name: "supportsInterface",\ outputs: [{ internalType: "bool", name: "", type: "bool" }],\ stateMutability: "view",\ type: "function",\ },\ {\ inputs: [],\ name: "unlockStake",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ {\ internalType: "address payable",\ name: "withdrawAddress",\ type: "address",\ },\ ],\ name: "withdrawStake",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ {\ inputs: [\ {\ internalType: "address payable",\ name: "withdrawAddress",\ type: "address",\ },\ { internalType: "uint256", name: "withdrawAmount", type: "uint256" },\ ],\ name: "withdrawTo",\ outputs: [],\ stateMutability: "nonpayable",\ type: "function",\ },\ { stateMutability: "payable", type: "receive" },\ ] as const; With that our contracts are all set to go! [Client and Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#client-and-server) ----------------------------------------------------------------------------------------------------------------- In our smart account app we want to have the following flow: * User clicks on UI button to create an account * User is prompted to create a passkey * Passkey is used to create and fund smart account on on our server by our server wallet interacting with the account factory * Client prepares operation to mint an NFT from the NFT contract, then prompts the user to sign the transaction with their passkey * Signature and operation info is sent to the server to be processed through the Entrypoint contract by our server wallet * Server sends a response back to the client with the transaction info In a real world application you might use a bundler instead of a server like we are to process the transactions, but it's helpful to see how it all works end-to-end. With that said we need to setup the client and server repos inside our main project directory. ### [Setup Client](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-client) Make sure you are in the root directory and run the following command pnpm create vite@latest client Go ahead and select the `React` and `Typescript` options, and the defaults that follow. Then move into that client directory and install our other dependencies. Shell cd client pnpm install viem ox While we are here go ahead and create a new file called `utils.ts` inside the `src` directory and put in the following code: utils.ts export function serializeBigInts(obj: any): any { if (typeof obj === "bigint") { return obj.toString(); } if (Array.isArray(obj)) { return obj.map(serializeBigInts); } if (obj !== null && typeof obj === "object") { return Object.fromEntries( Object.entries(obj).map(([key, value]) => [key, serializeBigInts(value)]), ); } return obj; } This will be a helper function to help process `BigInt` types that can't be serialized by JSON when we send data to our server. ### [Setup Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-server) Move back out into the main root directory of the tutorial and then run the following command to create a [Hono](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts) app: pnpm create hono@latest server Select the `cloudflare-worker` option from the templates, then move into the project and install the other dependencies. Shell pnpm install viem pnpm install -D @types/node This server is going to use our same foundry wallet from before to handle transactions that need to be processed on the backend. Let's make another `.env` file with the following contents: export CLOUDFLARE_INCLUDE_PROCESS_ENV=true export RPC_URL=https://sepolia.drpc.org export PRIVATE_KEY=$(cast wallet private-key --account sepolia) It is highly recommended to use an RPC URL that will be performant and not rate limited. Make a free one at DRPC.org or Alchemy! One last thing we need to do is edit the `server/wrangler.jsonc` file by uncommenting the `"compatibility_flags"` field like so: { "$schema": "node_modules/wrangler/config-schema.json", "name": "server", "main": "src/index.ts", "compatibility_date": "2025-10-10", "compatibility_flags": ["nodejs_compat"] } ### [Client & Server Code](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#client--server-code) Now it's time to start putting code into our client app and server to start the flow we want to achieve. Go ahead and open the `client/src/App.tsx` file and put in the following code: App.tsx import { useState } from "react"; import "./App.css"; import { WebAuthnP256 } from "ox"; import { encodeAbiParameters, createPublicClient, http, encodeFunctionData, encodePacked, type Hex, } from "viem"; import { sepolia } from "viem/chains"; import { ENTRYPOINT_ADDRESS, NFT_ADDRESS, entryPointAbi, myNftAbi, accountWebAuthnAbi, } from "../../shared"; import type { PackedUserOperation } from "viem/account-abstraction"; import { serializeBigInts } from "./utils"; const SERVER_URL = "http://localhost:8787"; const publicClient = createPublicClient({ transport: http(), chain: sepolia, }); function App() { const [isLoading, setIsLoading] = useState(false); const [statusMessage, setStatusMessage] = useState(""); const [accountAddress, setAccountAddress] = useState(null); const [mintTxHash, setMintTxHash] = useState(null); async function createAccount() { try { setIsLoading(true); setStatusMessage("Creating WebAuthn credential..."); // Create WebAuthn credential const credential = await WebAuthnP256.createCredential({ name: "wallet-user", }); // Convert BigInt values to hex strings for serialization (with proper padding) const publicKey = { prefix: credential.publicKey.prefix, x: `0x${credential.publicKey.x.toString(16).padStart(64, "0")}`, y: `0x${credential.publicKey.y.toString(16).padStart(64, "0")}`, }; setStatusMessage("Deploying WebAuthn account..."); // Send credential to server for account deployment const response = await fetch(`${SERVER_URL}/account/create`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ credentialId: credential.id, publicKey, }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || "Failed to create account"); } const result = await response.json(); const deployedAddress = result.accountAddress; setAccountAddress(deployedAddress); setStatusMessage("Account deployed! Preparing NFT mint transaction..."); const nonce = await publicClient.readContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "getNonce", args: [deployedAddress, 0n], }); const incrementCallData = encodeFunctionData({ abi: myNftAbi, functionName: "safeMint", args: [deployedAddress], }); const mode = encodePacked( ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], [\ "0x01",\ "0x00",\ "0x00000000",\ "0x00000000",\ "0x00000000000000000000000000000000000000000000",\ ], ); // Encode execution data as array of (address, uint256, bytes)[] const executionData = encodeAbiParameters( [\ {\ type: "tuple[]",\ components: [\ { type: "address" },\ { type: "uint256" },\ { type: "bytes" },\ ],\ },\ ], [[[NFT_ADDRESS, 0n, incrementCallData]]], ); // Encode the execute call on the account using ERC7821 format const callData = encodeFunctionData({ abi: accountWebAuthnAbi, functionName: "execute", args: [mode, executionData], }); const feeData = await publicClient.estimateFeesPerGas(); const userOp: PackedUserOperation = { sender: deployedAddress, nonce, // Already a BigInt from readContract initCode: "0x", callData, accountGasLimits: encodePacked( ["uint128", "uint128"], [\ 1_000_000n, // verificationGasLimit (high for P256 verification)\ 300_000n, // callGasLimit\ ], ), preVerificationGas: 100_000n, gasFees: encodePacked( ["uint128", "uint128"], [\ feeData.maxPriorityFeePerGas, // maxPriorityFeePerGas (1 gwei)\ feeData.maxFeePerGas, // maxFeePerGas (2 gwei)\ ], ), paymasterAndData: "0x", signature: "0x" as Hex, // Placeholder, will be replaced }; const userOpHash = await publicClient.readContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "getUserOpHash", args: [userOp], }); setStatusMessage("Signing transaction with WebAuthn..."); const { signature, metadata } = await WebAuthnP256.sign({ challenge: userOpHash, credentialId: credential.id, }); // Encode the signature in the format expected by OpenZeppelin SignerWebAuthn // The contract expects an ABI-encoded WebAuthnAuth struct: // struct WebAuthnAuth { // bytes32 r; // bytes32 s; // uint256 challengeIndex; // uint256 typeIndex; // bytes authenticatorData; // string clientDataJSON; // } // Prepare signature components const rHex = `0x${signature.r.toString(16).padStart(64, "0")}` as Hex; const sHex = `0x${signature.s.toString(16).padStart(64, "0")}` as Hex; setStatusMessage("Submitting UserOperation to mint NFT..."); const mintRequest = await fetch(`${SERVER_URL}/account/mint`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ rHex, sHex, metadata, userOp: serializeBigInts(userOp), nonce: nonce.toString(), }), }); const mintResponse = await mintRequest.json(); console.log(mintResponse); if (mintResponse.hash) { setMintTxHash(mintResponse.hash); } setStatusMessage("Success! NFT minted to your account."); setIsLoading(false); } catch (err) { console.error("Error creating account:", err); setStatusMessage( `Error: ${err instanceof Error ? err.message : "Unknown error occurred"}`, ); setIsLoading(false); } } return ( <>

WebAuthn Account Abstraction

{statusMessage && (
{isLoading &&
}

{statusMessage}

)} {accountAddress && (

Account Details

Address: {accountAddress}
{mintTxHash && (
NFT Mint Transaction: View on Etherscan ↗
)}
)}
); } export default App; Now inside `server/src/index.ts` paste in the code below: index.ts import { Hono } from "hono"; import { cors } from "hono/cors"; import { logger } from "hono/logger"; import { type Hex, encodeFunctionData, createPublicClient, createWalletClient, http, encodeAbiParameters, } from "viem"; import { accountWebAuthnAbi, FACTORY_ADDRESS, accountFactoryAbi, ENTRYPOINT_ADDRESS, entryPointAbi, } from "../../shared"; import { privateKeyToAccount } from "viem/accounts"; import { sepolia } from "viem/chains"; type Bindings = { RPC_URL: string; PRIVATE_KEY: string; }; const app = new Hono<{ Bindings: Bindings }>(); app.use(cors()); app.use(logger()); app.get("/", (c) => { return c.text("Hello Hono!"); }); app.post("/account/create", async (c) => { try { const publicClient = createPublicClient({ chain: sepolia, transport: http(c.env.RPC_URL), }); const account = privateKeyToAccount(c.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ chain: sepolia, transport: http(c.env.RPC_URL), account, }); const { credentialId, // Can be used to store accounts for future logins publicKey, } = await c.req.json(); // Extract qx and qy from the public key (ensure proper padding) const qx = publicKey.x as Hex; const qy = publicKey.y as Hex; // Encode the initialization call const initCallData = encodeFunctionData({ abi: accountWebAuthnAbi, functionName: "initializeWebAuthn", args: [qx, qy], }); // Predict account address const [predictedAddress] = await publicClient.readContract({ address: FACTORY_ADDRESS, abi: accountFactoryAbi, functionName: "predictAddress", args: [initCallData], }); // Deploy the account const hash = await walletClient.writeContract({ address: FACTORY_ADDRESS, abi: accountFactoryAbi, functionName: "cloneAndInitialize", args: [initCallData], }); // Wait for transaction await publicClient.waitForTransactionReceipt({ hash }); // Fund the account with 0.005 ETH from deployer wallet const fundHash = await walletClient.sendTransaction({ to: predictedAddress, value: 5000000000000000n, // 0.005 ETH in wei }); // Wait for funding transaction await publicClient.waitForTransactionReceipt({ hash: fundHash }); return c.json({ success: true, accountAddress: predictedAddress, transactionHash: hash, fundingTransactionHash: fundHash, publicKey: { qx, qy }, }); } catch (error) { return c.json({ error: ` Failed to create account: ${error} ` }, 500); } }); app.post("/account/mint", async (c) => { const publicClient = createPublicClient({ chain: sepolia, transport: http(c.env.RPC_URL), }); const account = privateKeyToAccount(c.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ chain: sepolia, transport: http(c.env.RPC_URL), account, }); try { const { metadata, rHex, sHex, userOp, nonce: serializedNonce, } = await c.req.json(); const challengeIndex = BigInt(metadata.challengeIndex); const typeIndex = BigInt(metadata.typeIndex); const authenticatorDataHex = metadata.authenticatorData; const clientDataJSON = metadata.clientDataJSON; const nonce = BigInt(serializedNonce); const encodedSignature = encodeAbiParameters( [\ { name: "r", type: "bytes32" },\ { name: "s", type: "bytes32" },\ { name: "challengeIndex", type: "uint256" },\ { name: "typeIndex", type: "uint256" },\ { name: "authenticatorData", type: "bytes" },\ { name: "clientDataJSON", type: "string" },\ ], [\ rHex,\ sHex,\ challengeIndex,\ typeIndex,\ authenticatorDataHex,\ clientDataJSON,\ ], ); const fullUserOp = { ...userOp, nonce, preVerificationGas: BigInt(userOp.preVerificationGas), signature: encodedSignature, }; const { request } = await publicClient.simulateContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "handleOps", args: [[fullUserOp], walletClient.account.address], account: walletClient.account, }); const hash = await walletClient.writeContract(request); const receipt = await publicClient.waitForTransactionReceipt({ hash: hash, }); if (receipt.status === "reverted") { return c.json({ error: ` Failed to Mint: Reverted ` }, 500); } return c.json({ status: "success", hash, }); } catch (error) { return c.json({ error: ` Failed to Mint: ${error} ` }, 500); } }); export default app; Now that's a fair bit of code, so let's do a breakdown of each step and what's happening. ### [Breakdown](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#breakdown) #### [Create and Fund Account](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#create-and-fund-account) The flow starts in the client code where the user clicks on the button and it kicks off `createAccount()`. async function createAccount() { try { setIsLoading(true); setStatusMessage("Creating WebAuthn credential..."); // Create WebAuthn credential const credential = await WebAuthnP256.createCredential({ name: "wallet-user", }); // Convert BigInt values to hex strings for serialization (with proper padding) const publicKey = { prefix: credential.publicKey.prefix, x: `0x${credential.publicKey.x.toString(16).padStart(64, "0")}`, y: `0x${credential.publicKey.y.toString(16).padStart(64, "0")}`, }; setStatusMessage("Deploying WebAuthn account..."); // Send credential to server for account deployment const response = await fetch(`${SERVER_URL}/account/create`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ credentialId: credential.id, publicKey, }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || "Failed to create account"); } const result = await response.json(); // Rest of function The first thing we need is a WebAuthn credential, and thankfully `ox` makes this really easy to do with `WebAuthnP256.createCredential()`. Once we have the credential we need to take the public key coordinates and serlialize the BigInt values into hex strings. Then we send a request to our server to `/account/create` with a JSON body of that `publicKey` as well as a `credentialId`. On the server the incoming requst is handled with this endpoint: app.post("/account/create", async (c) => { try { const publicClient = createPublicClient({ chain: sepolia, transport: http(c.env.RPC_URL), }); const account = privateKeyToAccount(c.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ chain: sepolia, transport: http(c.env.RPC_URL), account, }); const { credentialId, // Can be used to store accounts for future logins publicKey, } = await c.req.json(); // Extract qx and qy from the public key (ensure proper padding) const qx = publicKey.x as Hex; const qy = publicKey.y as Hex; // Encode the initialization call const initCallData = encodeFunctionData({ abi: accountWebAuthnAbi, functionName: "initializeWebAuthn", args: [qx, qy], }); // Predict account address const [predictedAddress] = await publicClient.readContract({ address: FACTORY_ADDRESS, abi: accountFactoryAbi, functionName: "predictAddress", args: [initCallData], }); // Deploy the account const hash = await walletClient.writeContract({ address: FACTORY_ADDRESS, abi: accountFactoryAbi, functionName: "cloneAndInitialize", args: [initCallData], }); // Wait for transaction await publicClient.waitForTransactionReceipt({ hash }); // Fund the account with 0.005 ETH from deployer wallet const fundHash = await walletClient.sendTransaction({ to: predictedAddress, value: 5000000000000000n, // 0.005 ETH in wei }); // Wait for funding transaction await publicClient.waitForTransactionReceipt({ hash: fundHash }); return c.json({ success: true, accountAddress: predictedAddress, transactionHash: hash, fundingTransactionHash: fundHash, publicKey: { qx, qy }, }); } catch (error) { return c.json({ error: ` Failed to create account: ${error} ` }, 500); } }); In this endpoint the server parses the JSON body to grab the serialized coordinates of the public key, then we put together what we need to do in order to predict our address. We don't necessarily need this in our flow, but it's good to know how it works. The predicted address is calculated by creating `initCallData` from `initializeWebAuthn` function and the coordiantes we got from the client. To actually deploy our smart account we'll take the same `initCallData` as the argument, then call `cloneAndInitialize` from the factory. This will return the smart account address, which we can then fund with our server wallet. Finally we can return the result of our process to the client. #### [Prepare and Sign User Operation](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#prepare-and-sign-user-operation) Back in our client we now can start prepping a User Operation. // createAccount() continuted const nonce = await publicClient.readContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "getNonce", args: [deployedAddress, 0n], }); const mintCallData = encodeFunctionData({ abi: myNftAbi, functionName: "safeMint", args: [deployedAddress], }); const mode = encodePacked( ["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"], [\ "0x01",\ "0x00",\ "0x00000000",\ "0x00000000",\ "0x00000000000000000000000000000000000000000000",\ ], ); // Encode execution data as array of (address, uint256, bytes)[] const executionData = encodeAbiParameters( [\ {\ type: "tuple[]",\ components: [\ { type: "address" },\ { type: "uint256" },\ { type: "bytes" },\ ],\ },\ ], [[[NFT_ADDRESS, 0n, mintCallData]]], ); // Encode the execute call on the account using ERC7821 format const callData = encodeFunctionData({ abi: accountWebAuthnAbi, functionName: "execute", args: [mode, executionData], }); const feeData = await publicClient.estimateFeesPerGas(); const userOp: PackedUserOperation = { sender: deployedAddress, nonce, // Already a BigInt from readContract initCode: "0x", callData, accountGasLimits: encodePacked( ["uint128", "uint128"], [\ 1_000_000n, // verificationGasLimit (high for P256 verification)\ 300_000n, // callGasLimit\ ], ), preVerificationGas: 100_000n, gasFees: encodePacked( ["uint128", "uint128"], [\ feeData.maxPriorityFeePerGas, // maxPriorityFeePerGas (1 gwei)\ feeData.maxFeePerGas, // maxFeePerGas (2 gwei)\ ], ), paymasterAndData: "0x", signature: "0x" as Hex, // Placeholder, will be replaced }; const userOpHash = await publicClient.readContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "getUserOpHash", args: [userOp], }); setStatusMessage("Signing transaction with WebAuthn..."); const { signature, metadata } = await WebAuthnP256.sign({ challenge: userOpHash, credentialId: credential.id, }); // Prepare signature components const rHex = `0x${signature.r.toString(16).padStart(64, "0")}` as Hex; const sHex = `0x${signature.s.toString(16).padStart(64, "0")}` as Hex; setStatusMessage("Submitting UserOperation to mint NFT..."); const mintRequest = await fetch(`${SERVER_URL}/account/mint`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ rHex, sHex, metadata, userOp: serializeBigInts(userOp), nonce: nonce.toString(), }), }); Now this starts to get a little confusing as we have a lot of encoding and nesting happening, so let's break it down piece by piece. First we have the `nonce` which we fetch from the Entrypoint contract. Next we need to encode the function data that our smart account wants to perform, which in our case is minting the NFT. Then we have the `mode` and `executionData` which includes the address of our NFT contract and the `mintCallData` we just made. With that `executionData` we can do one final encoding of the `callData` that will be passed to the `execute` function of our smart account. In order to actually run this transaction through `execute` we need to create what's called an User Operation that has all of the details of how it should be performed. We build the `userOp` object to gather the data that will be passed, and then we send that object to the entrypoint contract to get a `userOpHash`. This is what the user's passkey will sign; it's the approval of everything that's been encoded earlier. Once it's signed by the passkey through `WebAuthnP256.sign()` we get the `r` and `s` values from the signature and serialize them as hex strings, and we finally send all of that data to our server to execute the transaction. It's at this point if you wanted to you could send it to a bundler instead which might include a paymaster to handle gas fees. In our case the server wallet will pay gas initially, but then it will be refunded by the entrypoint once the smart account pays the gas fees for the transaciton. #### [Process User Operation on Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#process-user-operation-on-server) To handle processing the user operation we have an endpoint on the server called `/account/mint`: app.post("/account/mint", async (c) => { const publicClient = createPublicClient({ chain: sepolia, transport: http(c.env.RPC_URL), }); const account = privateKeyToAccount(c.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ chain: sepolia, transport: http(c.env.RPC_URL), account, }); try { const { metadata, rHex, sHex, userOp, nonce: serializedNonce, } = await c.req.json(); const challengeIndex = BigInt(metadata.challengeIndex); const typeIndex = BigInt(metadata.typeIndex); const authenticatorDataHex = metadata.authenticatorData; const clientDataJSON = metadata.clientDataJSON; const nonce = BigInt(serializedNonce); const encodedSignature = encodeAbiParameters( [\ { name: "r", type: "bytes32" },\ { name: "s", type: "bytes32" },\ { name: "challengeIndex", type: "uint256" },\ { name: "typeIndex", type: "uint256" },\ { name: "authenticatorData", type: "bytes" },\ { name: "clientDataJSON", type: "string" },\ ], [\ rHex,\ sHex,\ challengeIndex,\ typeIndex,\ authenticatorDataHex,\ clientDataJSON,\ ], ); const fullUserOp = { ...userOp, nonce, preVerificationGas: BigInt(userOp.preVerificationGas), signature: encodedSignature, }; const { request } = await publicClient.simulateContract({ address: ENTRYPOINT_ADDRESS, abi: entryPointAbi, functionName: "handleOps", args: [[fullUserOp], walletClient.account.address], account: walletClient.account, }); const hash = await walletClient.writeContract(request); const receipt = await publicClient.waitForTransactionReceipt({ hash: hash, }); if (receipt.status === "reverted") { return c.json({ error: ` Failed to Mint: Reverted ` }, 500); } return c.json({ status: "success", hash, }); } catch (error) { return c.json({ error: ` Failed to Mint: ${error} ` }, 500); } }); In order for the OpenZeppelin `WebAuthn.sol` to verify our signature and prove that the user authorized the operation, we have to prepare and encode the signature data correctly. Since we had to serialize some of the BigInt values on the client we need to reinstate them. Then we can put together the `encodedSignature` with all our values, many of them being the `metadata` that was produced in the signing process by `WebAuthnP256` from `ox`. Then we need to construct the `fullUserOp` which includes our updated `encodedSignature`, and we can finally submit it to the Entrypoint Contract. Once successful we can return the transaction hash to the user. [Try it!](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#try-it) -------------------------------------------------------------------------------------------- With an overview of how it all works you can test it yourself! In a terminal window run the client dev server: Shell cd client pnpm dev Then in a separate window run the server: Shell cd server source .env pnpm dev You should be able to visit `http://localhost:5173` and click on the `Create Account` button to experience the full flow! Make sure you are on a browser and device that supports passkeys ![image of demo](https://docs.openzeppelin.com/webauthn-demo.png) [Next Steps](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#next-steps) --------------------------------------------------------------------------------------------------- This tutorial is just scratching the surface of what is possible with OpenZeppelin account abstraction. With `AccountWebAuthn.sol` we could customize the logic and build custom use cases such as multifactor authentication, social recovery, time based controls, and more! We would highly encourage you to check out what other pieces you can add into Accounts with the [Wizard](https://wizard.openzeppelin.com/) under the `Accounts` tab. [Preparing for mainnet\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/learn/preparing-for-mainnet) [Overview\ \ Next Page](https://docs.openzeppelin.com/relayer) ### On this page [Prerequisites](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#prerequisites) [Wallet Setup](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#wallet-setup) [Project Structure](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#project-structure) [Contracts](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#contracts) [Setup](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup) [Deployment](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#deployment) [Setup Shared Directory](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-shared-directory) [Client and Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#client-and-server) [Setup Client](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-client) [Setup Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#setup-server) [Client & Server Code](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#client--server-code) [Breakdown](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#breakdown) [Create and Fund Account](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#create-and-fund-account) [Prepare and Sign User Operation](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#prepare-and-sign-user-operation) [Process User Operation on Server](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#process-user-operation-on-server) [Try it!](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#try-it) [Next Steps](https://docs.openzeppelin.com/contracts/5.x/learn/webauthn-smart-accounts#next-steps) --- # Proxy | OpenZeppelin Docs OpenZeppelin Contracts[API Reference](https://docs.openzeppelin.com/contracts/5.x/api) Proxy ===== Smart contract proxy utilities and implementations Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the [Proxy Upgrade Pattern](https://docs.openzeppelin.com/upgrades-plugins/proxies) page. Most of the proxies below are built on an abstract base contract. * [`Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy) : Abstract contract implementing the core delegation functionality. In order to avoid clashes with the storage variables of the implementation contract behind a proxy, we use [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) storage slots. * [`ERC1967Utils`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils) : Internal functions to get and set the storage slots defined in ERC-1967. * [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy) : A proxy using ERC-1967 storage slots. Not upgradeable by default. There are two alternative ways to add upgradeability to an ERC-1967 proxy. Their differences are explained below in [Transparent vs UUPS Proxies](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups-proxies) . * [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) : A proxy with a built-in immutable admin and upgrade interface. * [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable) : An upgradeability mechanism to be included in the implementation contract. **🔥 CAUTION** Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the [OpenZeppelin Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) for Hardhat and Foundry. A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. * [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) : A proxy that retrieves its implementation from a beacon contract. * [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) : A beacon contract with a built in admin that can upgrade the [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) pointing to it. In this pattern, the proxy contract doesn’t hold the implementation address in storage like an ERC-1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call. * [`Clones`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones) : A library that can deploy cheap minimal non-upgradeable proxies. [Transparent vs UUPS Proxies](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups-proxies) ----------------------------------------------------------------------------------------------------------------- The original proxies included in OpenZeppelin followed the [Transparent Proxy Pattern](https://blog.openzeppelin.com/the-transparent-proxy-pattern/) . While this pattern is still provided, our recommendation is now shifting towards UUPS proxies, which are both lightweight and versatile. The name UUPS comes from [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822) , which first documented the pattern. While both of these share the same interface for upgrades, in UUPS proxies the upgrade is handled by the implementation, and can eventually be removed. Transparent proxies, on the other hand, include the upgrade and admin logic in the proxy itself. This means [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) is more expensive to deploy than what is possible with UUPS proxies. UUPS proxies are implemented using an [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy) . Note that this proxy is not by itself upgradeable. It is the role of the implementation to include, alongside the contract’s logic, all the code necessary to update the implementation’s address that is stored at a specific slot in the proxy’s storage space. This is where the [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable) contract comes in. Inheriting from it (and overriding the [`_authorizeUpgrade`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address-) function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation. Note that since both proxies use the same storage slot for the implementation address, using a UUPS compliant implementation with a [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) might allow non-admins to perform upgrade operations. By default, the upgrade functionality included in [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable) contains a security mechanism that will prevent any upgrades to a non UUPS compliant implementation. This prevents upgrades to an implementation contract that wouldn’t contain the necessary upgrade mechanism, as it would lock the upgradeability of the proxy forever. This security mechanism can be bypassed by either of: * Adding a flag mechanism in the implementation that will disable the upgrade function when triggered. * Upgrading to an implementation that features an upgrade mechanism without the additional security check, and then upgrading again to another implementation without the upgrade mechanism. The current implementation of this security mechanism uses [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822) to detect the storage slot used by the implementation. A previous implementation, now deprecated, relied on a rollback check. It is possible to upgrade from a contract using the old mechanism to a new one. The inverse is however not possible, as old implementations (before version 4.5) did not include the ERC-1822 interface. [Core](https://docs.openzeppelin.com/contracts/5.x/api/proxy#core) ------------------------------------------------------------------- [`Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy) [ERC-1967](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc-1967) --------------------------------------------------------------------------- [`IERC1967`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967) [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy) [`ERC1967Utils`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils) [Transparent Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-proxy) --------------------------------------------------------------------------------------------- [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) [Beacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#beacon) ----------------------------------------------------------------------- [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) [`IBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IBeacon) [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) [Minimal Clones](https://docs.openzeppelin.com/contracts/5.x/api/proxy#minimal-clones) --------------------------------------------------------------------------------------- [`Clones`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones) [Utils](https://docs.openzeppelin.com/contracts/5.x/api/proxy#utils) --------------------------------------------------------------------- [`Initializable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable) [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable) [`Clones`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#clones) ------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/Clones.sol) import "@openzeppelin/contracts/proxy/Clones.sol"; [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167) is a standard for deploying minimal proxy contracts, also known as "clones". > To simply and cheaply clone contract functionality in an immutable way, this standard specifies a minimal bytecode implementation that delegates all calls to a known, fixed address. The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the deterministic method. ### Functions * [clone(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-clone-address-) * [clone(implementation, value)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-clone-address-uint256-) * [cloneDeterministic(implementation, salt)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministic-address-bytes32-) * [cloneDeterministic(implementation, salt, value)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministic-address-bytes32-uint256-) * [predictDeterministicAddress(implementation, salt, deployer)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-predictDeterministicAddress-address-bytes32-address-) * [predictDeterministicAddress(implementation, salt)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-predictDeterministicAddress-address-bytes32-) * [cloneWithImmutableArgs(implementation, args)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneWithImmutableArgs-address-bytes-) * [cloneWithImmutableArgs(implementation, args, value)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneWithImmutableArgs-address-bytes-uint256-) * [cloneDeterministicWithImmutableArgs(implementation, args, salt)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-) * [cloneDeterministicWithImmutableArgs(implementation, args, salt, value)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-uint256-) * [predictDeterministicAddressWithImmutableArgs(implementation, args, salt, deployer)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-predictDeterministicAddressWithImmutableArgs-address-bytes-bytes32-address-) * [predictDeterministicAddressWithImmutableArgs(implementation, args, salt)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-predictDeterministicAddressWithImmutableArgs-address-bytes-bytes32-) * [fetchCloneArgs(instance)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-fetchCloneArgs-address-) ### Errors * [CloneArgumentsTooLong()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-CloneArgumentsTooLong--) clone(address implementation) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-clone-address-) Deploys and returns the address of a clone that mimics the behavior of `implementation`. This function uses the create opcode, which should never revert. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. clone(address implementation, uint256 value) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-clone-address-uint256-) Same as [clone](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-clone-address-) , but with a `value` parameter to send native currency to the new contract. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. Using a non-zero value at creation will require the contract using this function (e.g. a factory) to always have enough balance for new deployments. Consider exposing this function under a payable method. cloneDeterministic(address implementation, bytes32 salt) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneDeterministic-address-bytes32-) Deploys and returns the address of a clone that mimics the behavior of `implementation`. This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same `implementation` and `salt` multiple times will revert, since the clones cannot be deployed twice at the same address. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. cloneDeterministic(address implementation, bytes32 salt, uint256 value) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneDeterministic-address-bytes32-uint256-) Same as [cloneDeterministic](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministic-address-bytes32-) , but with a `value` parameter to send native currency to the new contract. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. Using a non-zero value at creation will require the contract using this function (e.g. a factory) to always have enough balance for new deployments. Consider exposing this function under a payable method. predictDeterministicAddress(address implementation, bytes32 salt, address deployer) → address predicted internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-predictDeterministicAddress-address-bytes32-address-) Computes the address of a clone deployed using [`Clones.cloneDeterministic`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministic-address-bytes32-uint256-) . predictDeterministicAddress(address implementation, bytes32 salt) → address predicted internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-predictDeterministicAddress-address-bytes32-) Computes the address of a clone deployed using [`Clones.cloneDeterministic`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministic-address-bytes32-uint256-) . cloneWithImmutableArgs(address implementation, bytes args) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneWithImmutableArgs-address-bytes-) Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom immutable arguments. These are provided through `args` and cannot be changed after deployment. To access the arguments within the implementation, use [`Clones.fetchCloneArgs`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-fetchCloneArgs-address-) . This function uses the create opcode, which should never revert. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. cloneWithImmutableArgs(address implementation, bytes args, uint256 value) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneWithImmutableArgs-address-bytes-uint256-) Same as [cloneWithImmutableArgs](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneWithImmutableArgs-address-bytes-) , but with a `value` parameter to send native currency to the new contract. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. Using a non-zero value at creation will require the contract using this function (e.g. a factory) to always have enough balance for new deployments. Consider exposing this function under a payable method. cloneDeterministicWithImmutableArgs(address implementation, bytes args, bytes32 salt) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-) Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom immutable arguments. These are provided through `args` and cannot be changed after deployment. To access the arguments within the implementation, use [`Clones.fetchCloneArgs`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-fetchCloneArgs-address-) . This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice at the same address. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. cloneDeterministicWithImmutableArgs(address implementation, bytes args, bytes32 salt, uint256 value) → address instance internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-uint256-) Same as [cloneDeterministicWithImmutableArgs](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-) , but with a `value` parameter to send native currency to the new contract. This function does not check if `implementation` has code. A clone that points to an address without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they have no effect and leave the clone uninitialized, allowing a third party to initialize it later. Using a non-zero value at creation will require the contract using this function (e.g. a factory) to always have enough balance for new deployments. Consider exposing this function under a payable method. predictDeterministicAddressWithImmutableArgs(address implementation, bytes args, bytes32 salt, address deployer) → address predicted internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-predictDeterministicAddressWithImmutableArgs-address-bytes-bytes32-address-) Computes the address of a clone deployed using [`Clones.cloneDeterministicWithImmutableArgs`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-uint256-) . predictDeterministicAddressWithImmutableArgs(address implementation, bytes args, bytes32 salt) → address predicted internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-predictDeterministicAddressWithImmutableArgs-address-bytes-bytes32-) Computes the address of a clone deployed using [`Clones.cloneDeterministicWithImmutableArgs`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-uint256-) . fetchCloneArgs(address instance) → bytes internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-fetchCloneArgs-address-) Get the immutable args attached to a clone. * If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this function will return an empty array. * If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or `cloneDeterministicWithImmutableArgs`, this function will return the args array used at creation. * If `instance` is NOT a clone deployed using this library, the behavior is undefined. This function should only be used to check addresses that are known to be clones. CloneArgumentsTooLong() error [#](https://docs.openzeppelin.com/contracts/5.x/api/Clones-CloneArgumentsTooLong--) [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967proxy) ------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/ERC1967/ERC1967Proxy.sol) import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an implementation address that can be changed. This address is stored in storage in the location specified by [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) , so that it doesn't conflict with the storage layout of the implementation behind the proxy. ### Functions * [constructor(implementation, \_data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-constructor-address-bytes-) * [\_implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-_implementation--) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy-toc) * [\_delegate(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_delegate-address-) * [\_fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_fallback--) * [fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-fallback--) constructor(address implementation, bytes \_data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Proxy-constructor-address-bytes-) Initializes the upgradeable proxy with an initial implementation specified by `implementation`. If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: * If `data` is empty, `msg.value` must be zero. \_implementation() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Proxy-_implementation--) Returns the current implementation address. To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using the [`eth_getStorageAt`](https://eth.wiki/json-rpc/API#eth_getstorageat) RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` [`ERC1967Utils`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967utils) ------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/ERC1967/ERC1967Utils.sol) import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; This library provides getters and event emitting update functions for [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) slots. ### Functions * [getImplementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-getImplementation--) * [upgradeToAndCall(newImplementation, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-upgradeToAndCall-address-bytes-) * [getAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-getAdmin--) * [changeAdmin(newAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-changeAdmin-address-) * [getBeacon()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-getBeacon--) * [upgradeBeaconToAndCall(newBeacon, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-upgradeBeaconToAndCall-address-bytes-) ### Errors * [ERC1967InvalidImplementation(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-ERC1967InvalidImplementation-address-) * [ERC1967InvalidAdmin(admin)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-ERC1967InvalidAdmin-address-) * [ERC1967InvalidBeacon(beacon)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-ERC1967InvalidBeacon-address-) * [ERC1967NonPayable()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-ERC1967NonPayable--) getImplementation() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-getImplementation--) Returns the current implementation address. upgradeToAndCall(address newImplementation, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-upgradeToAndCall-address-bytes-) Performs implementation upgrade with additional setup call if data is nonempty. This function is payable only if the setup call is performed, otherwise `msg.value` is rejected to avoid stuck value in the contract. Emits an [`IERC1967.Upgraded`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967-Upgraded-address-) event. getAdmin() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-getAdmin--) Returns the current admin. To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using the [`eth_getStorageAt`](https://eth.wiki/json-rpc/API#eth_getstorageat) RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` changeAdmin(address newAdmin) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-changeAdmin-address-) Changes the admin of the proxy. Emits an [`IERC1967.AdminChanged`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967-AdminChanged-address-address-) event. getBeacon() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-getBeacon--) Returns the current beacon. upgradeBeaconToAndCall(address newBeacon, bytes data) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-upgradeBeaconToAndCall-address-bytes-) Change the beacon and trigger a setup call if data is nonempty. This function is payable only if the setup call is performed, otherwise `msg.value` is rejected to avoid stuck value in the contract. Emits an [`IERC1967.BeaconUpgraded`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967-BeaconUpgraded-address-) event. CAUTION: Invoking this function has no effect on an instance of [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) since v5, since it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for efficiency. ERC1967InvalidImplementation(address implementation) error [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-ERC1967InvalidImplementation-address-) The `implementation` of the proxy is invalid. ERC1967InvalidAdmin(address admin) error [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-ERC1967InvalidAdmin-address-) The `admin` of the proxy is invalid. ERC1967InvalidBeacon(address beacon) error [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-ERC1967InvalidBeacon-address-) The `beacon` of the proxy is invalid. ERC1967NonPayable() error [#](https://docs.openzeppelin.com/contracts/5.x/api/ERC1967Utils-ERC1967NonPayable--) An upgrade function sees `msg.value > 0` that may be lost. [`Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy) ----------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/Proxy.sol) import "@openzeppelin/contracts/proxy/Proxy.sol"; This abstract contract provides a fallback function that delegates all calls to another contract using the EVM instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to be specified by overriding the virtual [`ERC1967Proxy._implementation`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-_implementation--) function. Additionally, delegation to the implementation can be triggered manually through the [`AccountERC7579._fallback`](https://docs.openzeppelin.com/contracts/5.x/api/account#AccountERC7579-_fallback--) function, or to a different contract through the [`Votes._delegate`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Votes-_delegate-address-address-) function. The success and return data of the delegated call will be returned back to the caller of the proxy. ### Functions * [\_delegate(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_delegate-address-) * [\_implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_implementation--) * [\_fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_fallback--) * [fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-fallback--) \_delegate(address implementation) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Proxy-_delegate-address-) Delegates the current call to `implementation`. This function does not return to its internal call site, it will return directly to the external caller. \_implementation() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Proxy-_implementation--) This is a virtual function that should be overridden so it returns the address to which the fallback function and [`AccountERC7579._fallback`](https://docs.openzeppelin.com/contracts/5.x/api/account#AccountERC7579-_fallback--) should delegate. \_fallback() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Proxy-_fallback--) Delegates the current call to the address returned by `_implementation()`. This function does not return to its internal call site, it will return directly to the external caller. fallback() external [#](https://docs.openzeppelin.com/contracts/5.x/api/Proxy-fallback--) Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other function in the contract matches the call data. [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#beaconproxy) ----------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/beacon/BeaconProxy.sol) import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; This contract implements a proxy that gets the implementation address for each call from an [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) . The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) so that it can be accessed externally. CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust the beacon to not upgrade the implementation maliciously. Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in an inconsistent state where the beacon storage slot does not match the beacon address. ### Functions * [constructor(beacon, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy-constructor-address-bytes-) * [\_implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy-_implementation--) * [\_getBeacon()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy-_getBeacon--) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy-toc-1) * [\_delegate(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_delegate-address-) * [\_fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_fallback--) * [fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-fallback--) constructor(address beacon, bytes data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/BeaconProxy-constructor-address-bytes-) Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: * `beacon` must be a contract with the interface [`IBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IBeacon) . * If `data` is empty, `msg.value` must be zero. \_implementation() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/BeaconProxy-_implementation--) Returns the current implementation address of the associated beacon. \_getBeacon() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/BeaconProxy-_getBeacon--) Returns the beacon. [`IBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ibeacon) --------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/beacon/IBeacon.sol) import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; This is the interface that [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) expects of its beacon. ### Functions * [implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IBeacon-implementation--) implementation() → address external [#](https://docs.openzeppelin.com/contracts/5.x/api/IBeacon-implementation--) Must return an address that can be used as a delegate call target. [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon) will check that this address is a contract. [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#upgradeablebeacon) ----------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/beacon/UpgradeableBeacon.sol) import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; This contract is used in conjunction with one or more instances of [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#BeaconProxy) to determine their implementation contract, which is where they will delegate all function calls. An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. ### Functions * [constructor(implementation\_, initialOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon-constructor-address-address-) * [implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon-implementation--) * [upgradeTo(newImplementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon-upgradeTo-address-) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc) * [owner()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-owner--) * [\_checkOwner()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-_checkOwner--) * [renounceOwnership()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-renounceOwnership--) * [transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-transferOwnership-address-) * [\_transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-_transferOwnership-address-) #### [IBeacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ibeacon-toc) ### Events * [Upgraded(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon-Upgraded-address-) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc-1) * [OwnershipTransferred(previousOwner, newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnershipTransferred-address-address-) #### [IBeacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ibeacon-toc-1) ### Errors * [BeaconInvalidImplementation(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UpgradeableBeacon-BeaconInvalidImplementation-address-) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc-2) * [OwnableUnauthorizedAccount(account)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnableUnauthorizedAccount-address-) * [OwnableInvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnableInvalidOwner-address-) #### [IBeacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ibeacon-toc-2) constructor(address implementation\_, address initialOwner) public [#](https://docs.openzeppelin.com/contracts/5.x/api/UpgradeableBeacon-constructor-address-address-) Sets the address of the initial implementation, and the initial owner who can upgrade the beacon. implementation() → address public [#](https://docs.openzeppelin.com/contracts/5.x/api/UpgradeableBeacon-implementation--) Returns the current implementation address. upgradeTo(address newImplementation) public [#](https://docs.openzeppelin.com/contracts/5.x/api/UpgradeableBeacon-upgradeTo-address-) Upgrades the beacon to a new implementation. Emits an [`IERC1967.Upgraded`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967-Upgraded-address-) event. Requirements: * msg.sender must be the owner of the contract. * `newImplementation` must be a contract. Upgraded(address indexed implementation) event [#](https://docs.openzeppelin.com/contracts/5.x/api/UpgradeableBeacon-Upgraded-address-) Emitted when the implementation returned by the beacon is changed. BeaconInvalidImplementation(address implementation) error [#](https://docs.openzeppelin.com/contracts/5.x/api/UpgradeableBeacon-BeaconInvalidImplementation-address-) The `implementation` of the beacon is invalid. [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxyadmin) --------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/transparent/ProxyAdmin.sol) import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; This is an auxiliary contract meant to be assigned as the admin of a [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) . For an explanation of why you would want to use this see the documentation for [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) . ### Functions * [constructor(initialOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin-constructor-address-) * [upgradeAndCall(proxy, implementation, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-) * [UPGRADE\_INTERFACE\_VERSION()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin-UPGRADE_INTERFACE_VERSION-string) #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc-3) * [owner()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-owner--) * [\_checkOwner()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-_checkOwner--) * [renounceOwnership()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-renounceOwnership--) * [transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-transferOwnership-address-) * [\_transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-_transferOwnership-address-) ### Events #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc-4) * [OwnershipTransferred(previousOwner, newOwner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnershipTransferred-address-address-) ### Errors #### [Ownable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ownable-toc-5) * [OwnableUnauthorizedAccount(account)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnableUnauthorizedAccount-address-) * [OwnableInvalidOwner(owner)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Ownable-OwnableInvalidOwner-address-) constructor(address initialOwner) public [#](https://docs.openzeppelin.com/contracts/5.x/api/ProxyAdmin-constructor-address-) Sets the initial owner who can perform upgrades. upgradeAndCall(contract ITransparentUpgradeableProxy proxy, address implementation, bytes data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/ProxyAdmin-upgradeAndCall-contract-ITransparentUpgradeableProxy-address-bytes-) Upgrades `proxy` to `implementation` and calls a function on the new implementation. See [`TransparentUpgradeableProxy._dispatchUpgradeToAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy-_dispatchUpgradeToAndCall--) . Requirements: * This contract must be the admin of `proxy`. * If `data` is empty, `msg.value` must be zero. UPGRADE\_INTERFACE\_VERSION() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/ProxyAdmin-UPGRADE_INTERFACE_VERSION-string) The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address,address)` and `upgradeAndCall(address,address,bytes)` are present, and `upgrade` must be used if no function should be called, while `upgradeAndCall` will invoke the `receive` function if the third argument is the empty byte string. If the getter returns `"5.0.0"`, only `upgradeAndCall(address,address,bytes)` is present, and the third argument must be the empty byte string if no function should be called, making it impossible to invoke the `receive` function during an upgrade. [`ITransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#itransparentupgradeableproxy) --------------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; Interface for [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) . In order to implement transparency, [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch mechanism. The compiler is unaware that these functions are implemented by [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy) and will not include them in the ABI so this interface must be used to interact with it. ### Functions * [upgradeToAndCall(newImplementation, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ITransparentUpgradeableProxy-upgradeToAndCall-address-bytes-) #### [IERC1967](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ierc1967-toc) ### Events #### [IERC1967](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ierc1967-toc-1) * [Upgraded(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IERC1967-Upgraded-address-) * [AdminChanged(previousAdmin, newAdmin)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IERC1967-AdminChanged-address-address-) * [BeaconUpgraded(beacon)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#IERC1967-BeaconUpgraded-address-) upgradeToAndCall(address newImplementation, bytes data) external [#](https://docs.openzeppelin.com/contracts/5.x/api/ITransparentUpgradeableProxy-upgradeToAndCall-address-bytes-) See [`UUPSUpgradeable.upgradeToAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-upgradeToAndCall-address-bytes-) [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparentupgradeableproxy) ------------------------------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; This contract implements a proxy that is upgradeable through an associated [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) instance. To avoid [proxy selector clashing](https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357) , which can potentially be used in an attack, this contract uses the [transparent proxy pattern](https://blog.openzeppelin.com/the-transparent-proxy-pattern/) . This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches the [`ITransparentUpgradeableProxy.upgradeToAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ITransparentUpgradeableProxy-upgradeToAndCall-address-bytes-) function exposed by the proxy itself. 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating the proxy admin cannot fallback to the target implementation. These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. For this reason, the proxy deploys an instance of [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) and allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership. The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to fully implement transparency without decoding reverts caused by selector clashes between the proxy and the implementation. This proxy does not inherit from [`Context`](https://docs.openzeppelin.com/contracts/5.x/api/utils#Context) deliberately. The [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) of this contract won't send a meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract. This contract avoids unnecessary storage reads by setting the admin only during construction as an immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an undesirable state where the admin slot is different from the actual admin. Relying on the value of the admin slot is generally fine if the implementation is trusted. It is not recommended to extend this contract to add additional external functions. If you do so, the compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new function and the functions declared in [`ITransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ITransparentUpgradeableProxy) will be resolved in favor of the new one. This could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency. ### Functions * [constructor(\_logic, initialOwner, \_data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy-constructor-address-address-bytes-) * [\_proxyAdmin()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy-_proxyAdmin--) * [\_fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy-_fallback--) #### [ERC1967Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967proxy-toc) * [\_implementation()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-_implementation--) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy-toc-2) * [\_delegate(implementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-_delegate-address-) * [fallback()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Proxy-fallback--) ### Errors * [ProxyDeniedAdminAccess()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#TransparentUpgradeableProxy-ProxyDeniedAdminAccess--) #### [ERC1967Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967proxy-toc-1) #### [Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy-toc-3) constructor(address \_logic, address initialOwner, bytes \_data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/TransparentUpgradeableProxy-constructor-address-address-bytes-) Initializes an upgradeable proxy managed by an instance of a [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ProxyAdmin) with an `initialOwner`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in [`ERC1967Proxy.constructor`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-constructor-address-bytes-) . \_proxyAdmin() → address internal [#](https://docs.openzeppelin.com/contracts/5.x/api/TransparentUpgradeableProxy-_proxyAdmin--) Returns the admin of this proxy. \_fallback() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/TransparentUpgradeableProxy-_fallback--) If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior. ProxyDeniedAdminAccess() error [#](https://docs.openzeppelin.com/contracts/5.x/api/TransparentUpgradeableProxy-ProxyDeniedAdminAccess--) The proxy caller is the current admin, and can't fallback to the proxy target. [`Initializable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#initializable) --------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/utils/Initializable.sol) import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer function so it can only be called once. The [`Initializable.initializer`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-initializer--) modifier provided by this contract will have this effect. The initialization functions use a version number. Once a version number is used, it is consumed and cannot be reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in case an upgrade adds a module that needs to be initialized. For example: \[.hljs-theme-light.nopadding\] contract MyToken is ERC20Upgradeable { function initialize() initializer public { __ERC20_init("MyToken", "MTK"); } } contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { function initializeV2() reinitializer(2) public { __ERC20Permit_init("MyToken"); } } To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as possible by providing the encoded function call as the `_data` argument to [`ERC1967Proxy.constructor`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy-constructor-address-bytes-) . CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. Avoid leaving a contract uninitialized. An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke the [`Initializable._disableInitializers`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_disableInitializers--) function in the constructor to automatically lock it when it is deployed: \[.hljs-theme-light.nopadding\] /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } ### Modifiers * [initializer()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-initializer--) * [reinitializer(version)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-reinitializer-uint64-) * [onlyInitializing()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-onlyInitializing--) ### Functions * [\_checkInitializing()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_checkInitializing--) * [\_disableInitializers()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_disableInitializers--) * [\_getInitializedVersion()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_getInitializedVersion--) * [\_isInitializing()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_isInitializing--) * [\_initializableStorageSlot()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-_initializableStorageSlot--) ### Events * [Initialized(version)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-Initialized-uint64-) ### Errors * [InvalidInitialization()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-InvalidInitialization--) * [NotInitializing()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-NotInitializing--) initializer() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-initializer--) A modifier that defines a protected initializer function that can be invoked at most once. In its scope, `onlyInitializing` functions can be used to initialize parent contracts. Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any number of times. This behavior in the constructor can be useful during testing and is not expected to be used in production. Emits an [`Initializable.Initialized`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-Initialized-uint64-) event. reinitializer(uint64 version) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-reinitializer-uint64-) A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be used to initialize parent contracts. A reinitializer may be used after the original initialization step. This is essential to configure modules that are added through upgrades and that require initialization. When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` cannot be nested. If one is invoked in the context of another, execution will revert. Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in a contract, executing them in the right order is up to the developer or operator. Setting the version to 2\*\*64 - 1 will prevent any future reinitialization. Emits an [`Initializable.Initialized`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-Initialized-uint64-) event. onlyInitializing() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-onlyInitializing--) Modifier to protect an initialization function so that it can only be invoked by functions with the [`Initializable.initializer`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-initializer--) and [`Initializable.reinitializer`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-reinitializer-uint64-) modifiers, directly or indirectly. \_checkInitializing() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-_checkInitializing--) Reverts if the contract is not in an initializing state. See [`Initializable.onlyInitializing`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-onlyInitializing--) . \_disableInitializers() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-_disableInitializers--) Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized to any version. It is recommended to use this to lock implementation contracts that are designed to be called through proxies. Emits an [`Initializable.Initialized`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-Initialized-uint64-) event the first time it is successfully executed. \_getInitializedVersion() → uint64 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-_getInitializedVersion--) Returns the highest version that has been initialized. See [`Initializable.reinitializer`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-reinitializer-uint64-) . \_isInitializing() → bool internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-_isInitializing--) Returns `true` if the contract is currently initializing. See [`Initializable.onlyInitializing`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#Initializable-onlyInitializing--) . \_initializableStorageSlot() → bytes32 internal [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-_initializableStorageSlot--) Pointer to storage slot. Allows integrators to override it with a custom storage location. Consider following the ERC-7201 formula to derive storage locations. Initialized(uint64 version) event [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-Initialized-uint64-) Triggered when the contract has been initialized or reinitialized. InvalidInitialization() error [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-InvalidInitialization--) The contract is already initialized. NotInitializing() error [#](https://docs.openzeppelin.com/contracts/5.x/api/Initializable-NotInitializing--) The contract is not initializing. [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#uupsupgradeable) ------------------------------------------------------------------------------------------- [](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/proxy/utils/UUPSUpgradeable.sol) import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Proxy) , when this contract is set as the implementation behind such a proxy. A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing `UUPSUpgradeable` with a custom implementation of upgrades. The [`UUPSUpgradeable._authorizeUpgrade`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address-) function must be overridden to include access restriction to the upgrade mechanism. ### Modifiers * [onlyProxy()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-onlyProxy--) * [notDelegated()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-notDelegated--) ### Functions * [proxiableUUID()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-proxiableUUID--) * [upgradeToAndCall(newImplementation, data)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-upgradeToAndCall-address-bytes-) * [\_checkProxy()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_checkProxy--) * [\_checkNotDelegated()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_checkNotDelegated--) * [\_authorizeUpgrade(newImplementation)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address-) * [UPGRADE\_INTERFACE\_VERSION()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-UPGRADE_INTERFACE_VERSION-string) #### [IERC1822Proxiable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ierc1822proxiable-toc) ### Errors * [UUPSUnauthorizedCallContext()](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-UUPSUnauthorizedCallContext--) * [UUPSUnsupportedProxiableUUID(slot)](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-UUPSUnsupportedProxiableUUID-bytes32-) #### [IERC1822Proxiable](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ierc1822proxiable-toc-1) onlyProxy() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-onlyProxy--) Check that the execution is being performed through a delegatecall call and that the execution context is a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to fail. notDelegated() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-notDelegated--) Check that the execution is not being performed through a delegate call. This allows a function to be callable on the implementing contract but not through proxies. proxiableUUID() → bytes32 external [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-proxiableUUID--) Implementation of the ERC-1822 [`IERC1822Proxiable.proxiableUUID`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1822Proxiable-proxiableUUID--) function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. upgradeToAndCall(address newImplementation, bytes data) public [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-upgradeToAndCall-address-bytes-) Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls [`UUPSUpgradeable._authorizeUpgrade`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address-) . Emits an [`IERC1967.Upgraded`](https://docs.openzeppelin.com/contracts/5.x/api/interfaces#IERC1967-Upgraded-address-) event. \_checkProxy() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-_checkProxy--) Reverts if the execution is not performed via delegatecall or the execution context is not of a proxy with an ERC-1967 compliant implementation pointing to self. \_checkNotDelegated() internal [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-_checkNotDelegated--) Reverts if the execution is performed via delegatecall. See [`UUPSUpgradeable.notDelegated`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#UUPSUpgradeable-notDelegated--) . \_authorizeUpgrade(address newImplementation) internal [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-_authorizeUpgrade-address-) Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by [`ERC1967Utils.upgradeToAndCall`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ERC1967Utils-upgradeToAndCall-address-bytes-) . Normally, this function will use an [access control](https://docs.openzeppelin.com/contracts/5.x/api/access) modifier such as [`Ownable.onlyOwner`](https://docs.openzeppelin.com/contracts/5.x/api/access#Ownable-onlyOwner--) . function _authorizeUpgrade(address) internal onlyOwner {} UPGRADE\_INTERFACE\_VERSION() → string public [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-UPGRADE_INTERFACE_VERSION-string) The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must be the empty byte string if no function should be called, making it impossible to invoke the `receive` function during an upgrade. UUPSUnauthorizedCallContext() error [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-UUPSUnauthorizedCallContext--) The call is from an unauthorized context. UUPSUnsupportedProxiableUUID(bytes32 slot) error [#](https://docs.openzeppelin.com/contracts/5.x/api/UUPSUpgradeable-UUPSUnsupportedProxiableUUID-bytes32-) The storage `slot` is unsupported as a UUID. [Meta Transactions\ \ Previous Page](https://docs.openzeppelin.com/contracts/5.x/api/metatx) [Common\ \ Next Page](https://docs.openzeppelin.com/contracts/5.x/api/token/common) ### On this page [Transparent vs UUPS Proxies](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-vs-uups-proxies) [Core](https://docs.openzeppelin.com/contracts/5.x/api/proxy#core) [ERC-1967](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc-1967) [Transparent Proxy](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparent-proxy) [Beacon](https://docs.openzeppelin.com/contracts/5.x/api/proxy#beacon) [Minimal Clones](https://docs.openzeppelin.com/contracts/5.x/api/proxy#minimal-clones) [Utils](https://docs.openzeppelin.com/contracts/5.x/api/proxy#utils) [`Clones`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#clones) [`ERC1967Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967proxy) [`ERC1967Utils`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#erc1967utils) [`Proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxy) [`BeaconProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#beaconproxy) [`IBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#ibeacon) [`UpgradeableBeacon`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#upgradeablebeacon) [`ProxyAdmin`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#proxyadmin) [`ITransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#itransparentupgradeableproxy) [`TransparentUpgradeableProxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#transparentupgradeableproxy) [`Initializable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#initializable) [`UUPSUpgradeable`](https://docs.openzeppelin.com/contracts/5.x/api/proxy#uupsupgradeable) --- # Contribution Guidelines | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Contribution Guidelines ======================= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) Welcome to the OpenZeppelin Monitor project! We appreciate your interest in contributing. This guide outlines the requirements and processes for contributing to the project. [Getting Started](https://docs.openzeppelin.com/monitor/contribution#getting-started) -------------------------------------------------------------------------------------- The OpenZeppelin Monitor project has comprehensive contribution guidelines documented in the [`CONTRIBUTING.md`](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file. This documentation provides a summary of key requirements, but for complete details including GitHub workflow, labeling guidelines, and advanced topics, please refer to the full CONTRIBUTING.md file. For the most up-to-date and comprehensive contribution guidelines, always refer to the [CONTRIBUTING.md](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) file in the repository. [Key Requirements](https://docs.openzeppelin.com/monitor/contribution#key-requirements) ---------------------------------------------------------------------------------------- ### [Contributor License Agreement (CLA)](https://docs.openzeppelin.com/monitor/contribution#contributor-license-agreement-cla) _**You must sign the CLA before contributing.**_ The CLA process is automated through GitHub workflows that check and label PRs accordingly. * All contributors must complete the CLA process * The CLA bot will automatically check your PR status * PRs cannot be merged without a signed CLA ### [Signed Commits](https://docs.openzeppelin.com/monitor/contribution#signed-commits) _**All commits must be GPG-signed**_ as a security requirement. * Configure GPG signing for your commits * Unsigned commits will not be accepted * This helps ensure code integrity and authenticity [Development Environment Setup](https://docs.openzeppelin.com/monitor/contribution#development-environment-setup) ------------------------------------------------------------------------------------------------------------------ ### [Prerequisites](https://docs.openzeppelin.com/monitor/contribution#prerequisites) Before contributing, ensure you have: * _**Rust 2021 edition**_ - Required for development * _**Git**_ - For version control * _**Python/pip**_ - For pre-commit hooks ### [Initial Setup](https://docs.openzeppelin.com/monitor/contribution#initial-setup) # Clone and set up the repository git clone https://github.com/openzeppelin/openzeppelin-monitor cd openzeppelin-monitor # Build the project cargo build # Set up environment variables cp .env.example .env ### [Running Tests](https://docs.openzeppelin.com/monitor/contribution#running-tests) # All tests RUST_TEST_THREADS=1 cargo test # Integration tests RUST_TEST_THREADS=1 cargo test integration # Property-based tests RUST_TEST_THREADS=1 cargo test properties [Development Workflow](https://docs.openzeppelin.com/monitor/contribution#development-workflow) ------------------------------------------------------------------------------------------------ ### [1\. Pre-commit Hooks](https://docs.openzeppelin.com/monitor/contribution#1-pre-commit-hooks) _**Required for code quality checks**_ including `rustfmt`, `clippy`, and commit message validation. * Install and configure pre-commit hooks * Automatic formatting and linting checks * Commit message format validation #### [Installing Pre-commit Hooks](https://docs.openzeppelin.com/monitor/contribution#installing-pre-commit-hooks) Install and configure pre-commit hooks to ensure code quality: # Install pre-commit (use pipx for global installation if preferred) pip install pre-commit # Install and configure hooks for commit-msg, pre-commit, and pre-push pre-commit install --install-hooks -t commit-msg -t pre-commit -t pre-push If you encounter issues with pip install, you may need to install [pipx](https://github.com/pypa/pipx) for global installation. Use `pipx install pre-commit` instead. The pre-commit hooks will automatically run on every commit and push, checking for: * Code formatting with `rustfmt` * Linting with `clippy` * Commit message format validation * Other code quality checks ### [2\. GitHub Workflow](https://docs.openzeppelin.com/monitor/contribution#2-github-workflow) #### [Fork and Clone](https://docs.openzeppelin.com/monitor/contribution#fork-and-clone) 1. _**Fork the repository**_ on GitHub 2. _**Clone your fork**_ locally: # Set up your working directory export working_dir="$HOME/repos" export user= # Clone your fork mkdir -p $working_dir cd $working_dir git clone https://github.com/$user/openzeppelin-monitor.git # Add upstream remote cd openzeppelin-monitor git remote add upstream https://github.com/openzeppelin/openzeppelin-monitor.git git remote set-url --push upstream no_push #### [Branch Management](https://docs.openzeppelin.com/monitor/contribution#branch-management) * Create feature branches from an up-to-date main branch * Regularly sync with upstream * Use descriptive branch names # Keep main updated git fetch upstream git checkout main git rebase upstream/main # Create feature branch git checkout -b feature/your-feature-name # Keep branch updated git fetch upstream git rebase upstream/main Use `git rebase` instead of `git pull` to avoid merge commits and maintain a clean history. ### [3\. Pull Request Process](https://docs.openzeppelin.com/monitor/contribution#3-pull-request-process) #### [Creating a Pull Request](https://docs.openzeppelin.com/monitor/contribution#creating-a-pull-request) 1. _**Push your changes**_ to your fork: git push -f origin feature/your-feature-name 2. _**Create a Pull Request**_ on GitHub 3. _**Add appropriate labels**_ (see Labeling Guidelines below) 4. _**Include a clear description**_ of your changes #### [Best Practices for PRs](https://docs.openzeppelin.com/monitor/contribution#best-practices-for-prs) * Write clear and meaningful commit messages * Include `fixes #123` in PR body (not commit messages) to auto-close issues * Break large changes into smaller, logical commits * Ensure all tests pass * Include sufficient information for reviewers [Code Standards](https://docs.openzeppelin.com/monitor/contribution#code-standards) ------------------------------------------------------------------------------------ ### [Rust Standards](https://docs.openzeppelin.com/monitor/contribution#rust-standards) Rust API Guidelines: * Format code with `rustfmt` * Pass all `clippy` linting checks * Follow Rust naming conventions # Format code cargo fmt # Check linting cargo clippy --all-targets --all-features # Run tests RUST_TEST_THREADS=1 cargo test ### [Testing Requirements](https://docs.openzeppelin.com/monitor/contribution#testing-requirements) _**All contributions must pass existing tests**_ and include new tests when applicable: * Write unit tests for new functionality * Add integration tests for complex features * Ensure all tests pass before submitting * Maintain or improve code coverage For detailed testing information, see the [Testing Guide](https://docs.openzeppelin.com/monitor/testing) . ### [Commit Message Format](https://docs.openzeppelin.com/monitor/contribution#commit-message-format) _**Follow conventional commit format**_ with types like: * `feat:` - New features * `fix:` - Bug fixes * `docs:` - Documentation changes * `test:` - Test additions or modifications * `refactor:` - Code refactoring * `chore:` - Maintenance tasks [Issue and Pull Request Labeling](https://docs.openzeppelin.com/monitor/contribution#issue-and-pull-request-labeling) ---------------------------------------------------------------------------------------------------------------------- The project uses a structured labeling system to organize issues and PRs. Key label categories include: ### [Area Labels (`A-`)](https://docs.openzeppelin.com/monitor/contribution#area-labels-a-) * `A-arch` - Architectural concerns * `A-blocks` - Block processing * `A-clients` - Blockchain clients * `A-configs` - Configuration issues * `A-docs` - Documentation * `A-tests` - Testing ### [Type Labels (`T-`)](https://docs.openzeppelin.com/monitor/contribution#type-labels-t-) * `T-bug` - Bug reports * `T-feature` - New features * `T-task` - General tasks * `T-documentation` - Documentation updates ### [Priority Labels (`P-`)](https://docs.openzeppelin.com/monitor/contribution#priority-labels-p-) * `P-high` - Critical tasks * `P-medium` - Important tasks * `P-low` - Low priority ### [Difficulty Labels (`D-`)](https://docs.openzeppelin.com/monitor/contribution#difficulty-labels-d-) * `D-easy` - Beginner-friendly * `D-medium` - Intermediate * `D-hard` - Complex issues For complete labeling guidelines and all available labels, see the [labeling section](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md#issue-and-pull-request-labeling-guidelines) in CONTRIBUTING.md. [Code Review Process](https://docs.openzeppelin.com/monitor/contribution#code-review-process) ---------------------------------------------------------------------------------------------- ### [Review Requirements](https://docs.openzeppelin.com/monitor/contribution#review-requirements) * All PRs require review and approval * At least one Reviewer and one Approver must approve * Address all review comments before merging * Commits are automatically squashed when merging ### [Review Guidelines](https://docs.openzeppelin.com/monitor/contribution#review-guidelines) Reviewers should focus on: 1. _**Soundness**_ - Is the idea behind the contribution sound? 2. _**Architecture**_ - Is the contribution architected correctly? 3. _**Polish**_ - Is the contribution polished and ready? ### [Getting Reviews](https://docs.openzeppelin.com/monitor/contribution#getting-reviews) If your PR isn’t getting attention: * Contact the team on [Telegram](https://t.me/openzeppelin_tg/4) * Ensure your PR has appropriate labels * Keep PRs focused and reasonably sized [Security](https://docs.openzeppelin.com/monitor/contribution#security) ------------------------------------------------------------------------ * Follow the [Security Policy](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/SECURITY.md) * Report security vulnerabilities through the proper channels * Never commit sensitive information or credentials [Community Guidelines](https://docs.openzeppelin.com/monitor/contribution#community-guidelines) ------------------------------------------------------------------------------------------------ ### [Code of Conduct](https://docs.openzeppelin.com/monitor/contribution#code-of-conduct) Contributors must follow the [Code of Conduct](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CODE_OF_CONDUCT.md) , which: * Establishes standards for respectful collaboration * Outlines enforcement procedures * Promotes an inclusive environment [Getting Help](https://docs.openzeppelin.com/monitor/contribution#getting-help) -------------------------------------------------------------------------------- ### [Community Support](https://docs.openzeppelin.com/monitor/contribution#community-support) * _**GitHub Discussions**_: For questions and community interaction * _**Issues**_: For bug reports and feature requests * _**Telegram**_: [Join our community chat](https://t.me/openzeppelin_tg/4) * _**Good First Issues**_: [Find beginner-friendly issues](https://github.com/openzeppelin/openzeppelin-monitor/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) ### [Additional Resources](https://docs.openzeppelin.com/monitor/contribution#additional-resources) * _**Full CONTRIBUTING.md**_: [Complete contribution guidelines](https://github.com/OpenZeppelin/openzeppelin-monitor/blob/main/CONTRIBUTING.md) * _**User Documentation**_: [Monitor documentation](https://docs.openzeppelin.com/monitor) * _**OpenZeppelin Website**_: [Main website](https://openzeppelin.com/) [Testing\ \ Previous Page](https://docs.openzeppelin.com/monitor/testing) [Changelog\ \ Next Page](https://docs.openzeppelin.com/monitor/changelog) ### On this page [Getting Started](https://docs.openzeppelin.com/monitor/contribution#getting-started) [Key Requirements](https://docs.openzeppelin.com/monitor/contribution#key-requirements) [Contributor License Agreement (CLA)](https://docs.openzeppelin.com/monitor/contribution#contributor-license-agreement-cla) [Signed Commits](https://docs.openzeppelin.com/monitor/contribution#signed-commits) [Development Environment Setup](https://docs.openzeppelin.com/monitor/contribution#development-environment-setup) [Prerequisites](https://docs.openzeppelin.com/monitor/contribution#prerequisites) [Initial Setup](https://docs.openzeppelin.com/monitor/contribution#initial-setup) [Running Tests](https://docs.openzeppelin.com/monitor/contribution#running-tests) [Development Workflow](https://docs.openzeppelin.com/monitor/contribution#development-workflow) [1\. Pre-commit Hooks](https://docs.openzeppelin.com/monitor/contribution#1-pre-commit-hooks) [Installing Pre-commit Hooks](https://docs.openzeppelin.com/monitor/contribution#installing-pre-commit-hooks) [2\. GitHub Workflow](https://docs.openzeppelin.com/monitor/contribution#2-github-workflow) [Fork and Clone](https://docs.openzeppelin.com/monitor/contribution#fork-and-clone) [Branch Management](https://docs.openzeppelin.com/monitor/contribution#branch-management) [3\. Pull Request Process](https://docs.openzeppelin.com/monitor/contribution#3-pull-request-process) [Creating a Pull Request](https://docs.openzeppelin.com/monitor/contribution#creating-a-pull-request) [Best Practices for PRs](https://docs.openzeppelin.com/monitor/contribution#best-practices-for-prs) [Code Standards](https://docs.openzeppelin.com/monitor/contribution#code-standards) [Rust Standards](https://docs.openzeppelin.com/monitor/contribution#rust-standards) [Testing Requirements](https://docs.openzeppelin.com/monitor/contribution#testing-requirements) [Commit Message Format](https://docs.openzeppelin.com/monitor/contribution#commit-message-format) [Issue and Pull Request Labeling](https://docs.openzeppelin.com/monitor/contribution#issue-and-pull-request-labeling) [Area Labels (`A-`)](https://docs.openzeppelin.com/monitor/contribution#area-labels-a-) [Type Labels (`T-`)](https://docs.openzeppelin.com/monitor/contribution#type-labels-t-) [Priority Labels (`P-`)](https://docs.openzeppelin.com/monitor/contribution#priority-labels-p-) [Difficulty Labels (`D-`)](https://docs.openzeppelin.com/monitor/contribution#difficulty-labels-d-) [Code Review Process](https://docs.openzeppelin.com/monitor/contribution#code-review-process) [Review Requirements](https://docs.openzeppelin.com/monitor/contribution#review-requirements) [Review Guidelines](https://docs.openzeppelin.com/monitor/contribution#review-guidelines) [Getting Reviews](https://docs.openzeppelin.com/monitor/contribution#getting-reviews) [Security](https://docs.openzeppelin.com/monitor/contribution#security) [Community Guidelines](https://docs.openzeppelin.com/monitor/contribution#community-guidelines) [Code of Conduct](https://docs.openzeppelin.com/monitor/contribution#code-of-conduct) [Getting Help](https://docs.openzeppelin.com/monitor/contribution#getting-help) [Community Support](https://docs.openzeppelin.com/monitor/contribution#community-support) [Additional Resources](https://docs.openzeppelin.com/monitor/contribution#additional-resources) --- # Changelog | OpenZeppelin Docs [Monitor](https://docs.openzeppelin.com/monitor) Changelog ========= Copy Markdown [AnthropicOpen in Claude](https://claude.ai/new?q=Read+loading%2C+I+want+to+ask+questions+about+it.) [](https://docs.openzeppelin.com/monitor/changelog#v100---2025-06-30) [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.0.0) - 2025-06-30 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/monitor/changelog#100-2025-06-30) [1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0) (2025-06-30) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features) * add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11) ) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10) ) * Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107) ) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0) ) * Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75) ) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1) ) * add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7) ) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd) ) * Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69) ) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d) ) * Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199) ) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06) ) * Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77) ) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474) ) * Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156) ) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0) ) * Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65) ) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9) ) * Enhance filter expression parsing and evaluation ([#222](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/222) ) ([3cb0849](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3cb084919b3d477f329a85fbafce1ce6d696b16d) ) * Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187) ) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731) ) * Handle Stellar JSON-RPC outside of retention window error for `getTransactions` and `getEvents` ([#270](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/270) ) ([ae116ff](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ae116ff10f393a04c19d3b845df656027c6be4b9) ) * Implement client pooling for Webhook-based notifiers ([#281](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/281) ) ([4f480c6](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4f480c6a05aeb949cfd8e227c5c08f19a5e60180) ) * Introduce `TransportError` ([#259](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/259) ) ([0e04cfb](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0e04cfb57109251095ef8ee526fb5e05f5792792) ) * Introduce centralized retryable HTTP client creation ([#273](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/273) ) ([5f6edaf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5f6edaf5deb77a5d9dfead52a162e923aad6a2ab) ) * Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208) ) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8) ) * Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197) ) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33) ) * Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95) ) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7) ) * PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58) ) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4) ) * PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79) ) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877) ) * PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117) ) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93) ) * Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84) ) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd) ) * spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4) ) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946) ) * Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133) ) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes) * Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41) ) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af) ) * Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223) ) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f) ) * Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47) ) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835) ) * CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176) ) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a) ) * Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106) ) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832) ) * Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167) ) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b) ) * Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105) ) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37) ) * Duplicate name in triggers config ([#274](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/274) ) ([00f58f4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/00f58f4be3f9452792f9fdcf5dd8696947a274cb) ) * Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219) ) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096) ) * Event and function signatures from matched\_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198) ) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0) ) * Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110) ) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e) ) * Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116) ) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c) ) * Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97) ) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe) ) * fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2) ) * Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5) ) * Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203) ) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45) ) * Pagination logic in stellar getEvents relies only on cursor data ([#265](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/265) ) ([fca4057](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fca4057ff5847e04981e5903eebe6ccf3931726c) ) * PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90) ) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b) ) * Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62) ) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5) ) * remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174) ) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3) ) * rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2) ) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574) ) * rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6) ) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e) ) * Replace automatic minor version bumps ([#285](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/285) ) ([0c9e14a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/0c9e14a542cae2d2c7ff580ff7de28b0d9aab22a) ) * Risk of key collision for monitor custom scripts ([#258](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/258) ) ([2aa4cd7](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2aa4cd730dbcbbd1cf0892394cedc4ea06332375) ) * Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181) ) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86) ) * Stellar ledgers are deterministic ([#257](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/257) ) ([56a9f9e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/56a9f9e10e533ea96c01cb1f0f67024600ad89df) ) * trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24) ) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64) ) * Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49) ) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0) [](https://docs.openzeppelin.com/monitor/changelog#v020---2025-05-14) [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.2.0) - 2025-05-14 ====================================================================================================================================================================== [](https://docs.openzeppelin.com/monitor/changelog#020-2025-05-14) [0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0) (2025-05-14) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- [⚠️ ⚠️ Breaking Changes in v0.2.0](https://docs.openzeppelin.com/monitor/changelog#%EF%B8%8F-%EF%B8%8F-breaking-changes-in-v020) --------------------------------------------------------------------------------------------------------------------------------- * Renamed abi to contract\_spec in monitor configurations. * Stellar function expressions now use named parameters instead of positional indexes, for example; (Transfer(address,address,amount)): 2 > 1000 → amount > 1000 * Template variables now follow dot notation rather than underscores, for example: * monitor\_name → monitor.name * transaction\_hash → transaction.hash * function\_0\_amount → functions.0.args.amount * event\_0\_signature → events.0.signature * Sensitive configuration values (e.g., URLs, usernames, passwords, tokens) must now be defined using the SecretValue object structure, for example: * RPC URLs: "rpc_urls": [\ {\ "type_": "rpc",\ "url": {\ "type": "plain",\ "value": "https://eth.drpc.org"\ },\ "weight": 100\ }\ ] * Webhook URLs: "discord_url": { "type": "plain", "value": "https://discord.com/api/webhooks/123-456-789" } ### [🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features-1) * Add environment vars and Hashicorp cloud vault support (breaking) ([#199](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/199) ) ([558304f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/558304f335a645c1de2d348a041337ccba2c2a06) ) * Extend support for EVM transaction properties ([#187](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/187) ) ([f20086b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f20086b0431a787dd55aa8928a09aece80b9a731) ) * Leverage contract spec (SEP-48) for Stellar functions (breaking) ([#208](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/208) ) ([5ebc2a4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5ebc2a441b9ac6ed66a0807cac2795af2ae5b1c8) ) * Markdown for telegram, discord, slack and email ([#197](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/197) ) ([791bf4b](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/791bf4b347d8cfe03ccd53e9797f179c15629a33) ) * Test execute the monitor against specific block ([#133](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/133) ) ([563c34f](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/563c34fde3c0f334a7c5884de5510bf27e4fca48) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes-1) * Adding validation for unknown field names ([#223](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/223) ) ([cadf4da](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cadf4dac293e2c24a02a2eb188540e1eb312b75f) ) * CLA labels and assistant ([#176](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/176) ) ([b14f060](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b14f0600dc4cac5a5f00d3772328abe123114b2a) ) * Docs pipeline ([#167](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/167) ) ([1e78ec4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1e78ec4f98f70ac12dea353c1605ac4ac2c5734b) ) * Environment adjustments and cargo lock file improvements ([#219](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/219) ) ([1b4d5d8](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1b4d5d8dbe8cba26fbb84a8f847fc22b1a1dc096) ) * Event and function signatures from matched\_on ([#198](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/198) ) ([cdd9f1d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/cdd9f1d7333ee2f3ef9c476a08e918388b3c35f0) ) * Monitor match template var signature collission (breaking) ([#203](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/203) ) ([283b724](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/283b724a88f45f82c3c5fc81742a564b70909d45) ) * remove the create-github-app-token action from the scorecard workflow ([#174](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/174) ) ([48ca0b1](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/48ca0b106dbee225b5d4824013c2a28b773b23b3) ) * Running duplicate tests ([#181](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/181) ) ([ad0f741](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ad0f741608b2719a1db16dd22bf8c457e5814f86) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0) [](https://docs.openzeppelin.com/monitor/changelog#v010---2025-04-07) [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.1.0) - 2025-04-07 ====================================================================================================================================================================== [0.1.0 (2025-04-07)](https://docs.openzeppelin.com/monitor/changelog#010-2025-04-07) ------------------------------------------------------------------------------------- ### [🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features-2) * add block tracker ([#11](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/11) ) ([1d4d117](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d4d117aab56e2c31c0747d6bf681fe60b2d8b10) ) * Add CLA assistant bot ([#107](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/107) ) ([47e490e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/47e490e4a5657a48bc60f85c38d72aca16334ac0) ) * Add client rpc pool ([#75](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/75) ) ([28cd940](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/28cd940a8aea5c97fb15a4ca0d415debaa2864b1) ) * add email support ([#7](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/7) ) ([decb56d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/decb56d45d3f1000346c24e137d1a5d952c4a9dd) ) * Add endpoint rotation manager ([#69](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/69) ) ([454a630](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/454a630cf92c305ea5d9254b211a7b60abf8804d) ) * Add new error context ([#77](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/77) ) ([612bb76](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/612bb76b9c8e9a470fc68685c2f06481663a9474) ) * Add rc workflow file ([#156](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/156) ) ([8907591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/890759186570a64a9d0b0ef4dc9e512d0110d7a0) ) * Add support for webhook, telegram, discord notifications ([#65](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/65) ) ([829967d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/829967da45062dc22ffb0cb3376e68101a46b3e9) ) * Plat 6187 write metrics to prometheus ([#95](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/95) ) ([2dc08d5](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2dc08d51670834f453498299937debfca67fa1b7) ) * PLAT-6148 Adding post filter to monitor model ([#58](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/58) ) ([920a0bf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/920a0bf27953b67eb722d17d5ebf50b51237d4d4) ) * PLAT-6151 Integrate custom script execution with notification service ([#79](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/79) ) ([bd5f218](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/bd5f218507dfc30bd4b2182077e2997cf04b8877) ) * PLAT-6477 Adding rust toolchain file ([#117](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/117) ) ([ea6fb1e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ea6fb1ee6bba46cfa66a0c81665e17930bbbed93) ) * Separate code test coverage into different categories of tests ([#84](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/84) ) ([a3ad89c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/a3ad89cdcf0bab5883af7ec36b854fedc2f060cd) ) * spawn block-watcher per network ([#4](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/4) ) ([d7a19ec](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d7a19ec57344e4fb28dffc6f2025e809d0f5d946) ) ### [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes-2) * Add thread flag when running tests in CI ([#41](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/41) ) ([4312669](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/4312669d8da84f5cf7e7817b10c377fe3a6992af) ) * Adjust netlify toml settings ([#47](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/47) ) ([af9fe55](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/af9fe553a92cfc47a306a7dcfc43be0b2257f835) ) * Docs link ([#106](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/106) ) ([f12d95d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f12d95d85ad9230bece0342c39cb5c3c1cd62832) ) * Documentation name for antora ([#105](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/105) ) ([5a8c4bd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5a8c4bd8315e62bb2dedb066f6b6bfcaa09c2d37) ) * Fix cargo lock ([#110](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/110) ) ([c440ca4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/c440ca43542e919cd473a7d533b0820cf5474d3e) ) * Fix cargo lock file ([#116](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/116) ) ([1bd3658](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1bd3658ab507c2dde90a2132b6eaec6d849e0e3c) ) * Fix the codecov yaml syntax ([#97](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/97) ) ([fcafcbf](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/fcafcbf5765014a65c3f2c8718ee0f24a4531ebe) ) * fixed check ([1d36aaa](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/1d36aaa63ca12b4a660ec7e7bfcb18f722d8adf2) ) * Linter ([b0e27ca](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b0e27ca21f8e39b3a3c16d356df00dfcd0a868e5) ) * Netlify integration & Release workflow doc ([#162](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/162) ) ([3b77025](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3b7702569e7c5828ca55fb67f7eec2672bf768b2) ) * PLAT-6301 Remove logic for checking file descriptors open and fixing readme ([#90](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/90) ) ([71dbd24](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/71dbd24a9ba5ab4c37cf4be432a4614c2e68166b) ) * Reduce USDC ABI and fix trailing comma ([#62](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/62) ) ([92e343c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/92e343c09dc2da565912b6cd5bc83fbdc591cdb5) ) * rename docker binaries ([#2](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/2) ) ([78d438a](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/78d438a1ca4931651d3ca106c5dbda1ea1357574) ) * rename import ([#6](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/6) ) ([745e591](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/745e591faba06f557b2f6a091434250ed559df6e) ) * trigger execution order ([#24](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/24) ) ([26581fe](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/26581fec9ec1078ea4284fd6b43509616c66ad64) ) * Variable resolving ([#49](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/49) ) ([e26d173](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e26d17314e9b2e78c0772a46f3139da70c6ca144) ) ### [📚 Documentation](https://docs.openzeppelin.com/monitor/changelog#-documentation) * Add Antora documentation ([#48](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/48) ) ([2f737c4](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2f737c4c040090bd3acd0af90d3f24045b8ff173) ) * add link to contributing in README ([#33](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/33) ) ([5abb548](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5abb548c199f3a033860b027461e5fb3cd60e565) ) * Add list of RPC calls ([#67](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/67) ) ([aae9577](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/aae9577f4e011eaca12adb7997bf5fd28a558f83) ) * Add quickstart guide ([#56](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/56) ) ([e422353](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/e422353873335540afce5a9a5702c786c71eea75) ) * add readme documentation ([#8](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/8) ) ([357006d](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/357006d98f6cc8d160920e702dc78662008d39a3) ) * add rust documentation ([#5](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/5) ) ([3832570](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/3832570adf4854279fcda215fbbba5eb0d5396a1) ) * Adding node to docker images - custom scripts ([#76](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/76) ) ([da6516c](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/da6516c6f3afccb297cb1c1251f673e02ceaeaa5) ) * Custom scripts documentation to antora and readme ([#91](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/91) ) ([2b81058](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/2b81058f810e6b4d18a2c79e96002fb77890e9e0) ) * Fix quickstart closing tag ([#118](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/118) ) ([d360379](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/d3603796f39c15ed5247efab90ab95c5537c76d2) ) * Fix telegram channel ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db) ) * Implement README feedback ([#50](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/50) ) ([5b6ba64](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/5b6ba6419a06b9abd60412fa02b09da2a416e38c) ) * Improve docs ([#100](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/100) ) ([9586a25](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/9586a253f2a76993bbf82d4834b37863edabab60) ) * improve readme section and examples ([#9](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/9) ) ([009db37](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/009db3719e1be03120733755ade3c1c45e13f8a5) ) * Improvements to custom scripts ([#98](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/98) ) ([69047d9](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/69047d90a2fe057446f7c1b3f3526ab31bc6afcb) ) * Re-order example and fix test flag ([#52](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/52) ) ([f90b6df](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/f90b6df73ef7a6040eab59d71402b34877c88fc5) ) * Readability improvements ([#109](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/109) ) ([8e23389](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/8e23389ea0dcb3b221227a6cddd17de39603acbb) ) * Update project structure ([#101](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/101) ) ([207edd2](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/207edd28f3fb0a805d40d6ba9109abe9e6553d23) ) * Update README and antora docs ([#57](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/57) ) ([6a2299e](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/6a2299e0c41052ef9523aec1aa6f5852990e9179) ) * Update RPC documentation after client pool feature ([#96](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/96) ) ([ade2811](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/ade2811431c07c6b46730cbce5e357934df14cd5) ) * Update telegram channel in docs ([#99](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/99) ) ([9899259](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/98992599ab8998113b6202781787a48ce0aab3db) ) * Updated Quickstart guide ([#108](https://github.com/OpenZeppelin/openzeppelin-monitor/issues/108) ) ([b81c7cd](https://github.com/OpenZeppelin/openzeppelin-monitor/commit/b81c7cd22143a7d2854ef496ab59e114d70c360f) ) [Changes](https://github.com/OpenZeppelin/openzeppelin-monitor/tree/v0.1.0) ### On this page [](https://docs.openzeppelin.com/monitor/changelog#v100---2025-06-30) [v1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v1.0.0) - 2025-06-30[](https://docs.openzeppelin.com/monitor/changelog#100-2025-06-30) [1.0.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.2.0...v1.0.0) (2025-06-30)[🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features) [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes) [](https://docs.openzeppelin.com/monitor/changelog#v020---2025-05-14) [v0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.2.0) - 2025-05-14[](https://docs.openzeppelin.com/monitor/changelog#020-2025-05-14) [0.2.0](https://github.com/OpenZeppelin/openzeppelin-monitor/compare/v0.1.0...v0.2.0) (2025-05-14)[⚠️ ⚠️ Breaking Changes in v0.2.0](https://docs.openzeppelin.com/monitor/changelog#%EF%B8%8F-%EF%B8%8F-breaking-changes-in-v020) [🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features-1) [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes-1) [](https://docs.openzeppelin.com/monitor/changelog#v010---2025-04-07) [v0.1.0](https://github.com/OpenZeppelin/openzeppelin-monitor/releases/tag/v0.1.0) - 2025-04-07[0.1.0 (2025-04-07)](https://docs.openzeppelin.com/monitor/changelog#010-2025-04-07) [🚀 Features](https://docs.openzeppelin.com/monitor/changelog#-features-2) [🐛 Bug Fixes](https://docs.openzeppelin.com/monitor/changelog#-bug-fixes-2) [📚 Documentation](https://docs.openzeppelin.com/monitor/changelog#-documentation) ---