ERC20Bridgable (ERC-7802) (#5735)

Co-authored-by: ernestognw <ernestognw@gmail.com>
Co-authored-by: Arr00 <13561405+arr00@users.noreply.github.com>
This commit is contained in:
Hadrien Croubois
2025-06-12 02:19:56 +02:00
committed by GitHub
parent bbc4d7ae67
commit 5c79432e40
7 changed files with 206 additions and 0 deletions

View File

@ -45,6 +45,7 @@ are useful to interact with third party contracts that implement them.
- {IERC6909Metadata}
- {IERC6909TokenSupply}
- {IERC7674}
- {IERC7802}
== Detailed ABI
@ -97,3 +98,5 @@ are useful to interact with third party contracts that implement them.
{{IERC6909TokenSupply}}
{{IERC7674}}
{{IERC7802}}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import {IERC165} from "./IERC165.sol";
/// @title IERC7802
/// @notice Defines the interface for crosschain ERC20 transfers.
interface IERC7802 is IERC165 {
/// @notice Emitted when a crosschain transfer mints tokens.
/// @param to Address of the account tokens are being minted for.
/// @param amount Amount of tokens minted.
/// @param sender Address of the caller (msg.sender) who invoked crosschainMint.
event CrosschainMint(address indexed to, uint256 amount, address indexed sender);
/// @notice Emitted when a crosschain transfer burns tokens.
/// @param from Address of the account tokens are being burned from.
/// @param amount Amount of tokens burned.
/// @param sender Address of the caller (msg.sender) who invoked crosschainBurn.
event CrosschainBurn(address indexed from, uint256 amount, address indexed sender);
/// @notice Mint tokens through a crosschain transfer.
/// @param _to Address to mint tokens to.
/// @param _amount Amount of tokens to mint.
function crosschainMint(address _to, uint256 _amount) external;
/// @notice Burn tokens through a crosschain transfer.
/// @param _from Address to burn tokens from.
/// @param _amount Amount of tokens to burn.
function crosschainBurn(address _from, uint256 _amount) external;
}

View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC20, ERC20Bridgeable} from "../../token/ERC20/extensions/draft-ERC20Bridgeable.sol";
abstract contract ERC20BridgeableMock is ERC20Bridgeable {
address private _bridge;
error OnlyTokenBridge();
event OnlyTokenBridgeFnCalled(address caller);
constructor(address bridge) {
_bridge = bridge;
}
function onlyTokenBridgeFn() external onlyTokenBridge {
emit OnlyTokenBridgeFnCalled(msg.sender);
}
function _checkTokenBridge(address sender) internal view override {
if (sender != _bridge) {
revert OnlyTokenBridge();
}
}
}

View File

@ -16,6 +16,7 @@ There are a few core contracts that implement the behavior specified in the ERC-
Additionally there are multiple custom extensions, including:
* {ERC20Permit}: gasless approval of tokens (standardized as ERC-2612).
* {ERC20Bridgeable}: compatibility with crosschain bridges through ERC-7802.
* {ERC20Burnable}: destruction of own tokens.
* {ERC20Capped}: enforcement of a cap to the total supply when minting tokens.
* {ERC20Pausable}: ability to pause token transfers.
@ -50,6 +51,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
{{ERC20Permit}}
{{ERC20Bridgeable}}
{{ERC20Burnable}}
{{ERC20Capped}}

View File

@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC20} from "../ERC20.sol";
import {ERC165, IERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC7802} from "../../../interfaces/draft-IERC7802.sol";
/**
* @dev ERC20 extension that implements the standard token interface according to
* https://eips.ethereum.org/EIPS/eip-7802[ERC-7802].
*/
abstract contract ERC20Bridgeable is ERC20, ERC165, IERC7802 {
/// @dev Modifier to restrict access to the token bridge.
modifier onlyTokenBridge() {
// Token bridge should never be impersonated using a relayer/forwarder. Using msg.sender is preferable to
// _msgSender() for security reasons.
_checkTokenBridge(msg.sender);
_;
}
/// @inheritdoc ERC165
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC7802).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC7802-crosschainMint}. Emits a {IERC7802-CrosschainMint} event.
*/
function crosschainMint(address to, uint256 value) public virtual override onlyTokenBridge {
_mint(to, value);
emit CrosschainMint(to, value, _msgSender());
}
/**
* @dev See {IERC7802-crosschainBurn}. Emits a {IERC7802-CrosschainBurn} event.
*/
function crosschainBurn(address from, uint256 value) public virtual override onlyTokenBridge {
_burn(from, value);
emit CrosschainBurn(from, value, _msgSender());
}
/**
* @dev 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} or {AccessManaged}.
*/
function _checkTokenBridge(address caller) internal virtual;
}