Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/happy-pants-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---

Rename `BridgeERC20Core` to `BridgeFungible`
2 changes: 1 addition & 1 deletion contracts/crosschain/CrosschainLinked.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {ERC7786Recipient} from "./ERC7786Recipient.sol";
*
* This contract contains the logic to register and send messages to counterparts on remote chains using ERC-7786
* gateways. It ensure received messages originate from a counterpart. This is the base of token bridges such as
* {BridgeERC20Core}.
* {BridgeFungible}.
*
* Contracts that inherit from this contract can use the internal {_sendMessageToCounterpart} to send messages to their
* counterpart on a foreign chain. They must override the {_processMessage} function to handle messages that have
Expand Down
4 changes: 2 additions & 2 deletions contracts/crosschain/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This directory contains contracts for sending and receiving cross chain messages

Additionally there are multiple bridge constructions:

* {BridgeERC20Core}: Core bridging logic for crosschain ERC-20 transfer. Used by {BridgeERC20}, {BridgeERC7802} and {ERC20Crosschain},
* {BridgeFungible}: Core bridging logic for crosschain ERC-20 transfer. Used by {BridgeERC20}, {BridgeERC7802} and {ERC20Crosschain},
* {BridgeERC20}: Standalone bridge contract to connect an ERC-20 token contract with counterparts on remote chains,
* {BridgeERC7802}: Standalone bridge contract to connect an ERC-7802 token contract with counterparts on remote chains.

Expand All @@ -22,7 +22,7 @@ Additionally there are multiple bridge constructions:

== Bridges

{{BridgeERC20Core}}
{{BridgeFungible}}

{{BridgeERC20}}

Expand Down
6 changes: 3 additions & 3 deletions contracts/crosschain/bridges/BridgeERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
pragma solidity ^0.8.26;

import {IERC20, SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol";
import {BridgeERC20Core} from "./BridgeERC20Core.sol";
import {BridgeFungible} from "./abstract/BridgeFungible.sol";

/**
* @dev This is a variant of {BridgeERC20Core} that implements the bridge logic for ERC-20 tokens that do not expose a
* @dev This is a variant of {BridgeFungible} that implements the bridge logic for ERC-20 tokens that do not expose a
* crosschain mint and burn mechanism. Instead, it takes custody of bridged assets.
*/
// slither-disable-next-line locked-ether
abstract contract BridgeERC20 is BridgeERC20Core {
abstract contract BridgeERC20 is BridgeFungible {
using SafeERC20 for IERC20;

IERC20 private immutable _token;
Expand Down
6 changes: 3 additions & 3 deletions contracts/crosschain/bridges/BridgeERC7802.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
pragma solidity ^0.8.26;

import {IERC7802} from "../../interfaces/draft-IERC7802.sol";
import {BridgeERC20Core} from "./BridgeERC20Core.sol";
import {BridgeFungible} from "./abstract/BridgeFungible.sol";

/**
* @dev This is a variant of {BridgeERC20Core} that implements the bridge logic for ERC-7802 compliant tokens.
* @dev This is a variant of {BridgeFungible} that implements the bridge logic for ERC-7802 compliant tokens.
*/
// slither-disable-next-line locked-ether
abstract contract BridgeERC7802 is BridgeERC20Core {
abstract contract BridgeERC7802 is BridgeFungible {
IERC7802 private immutable _token;

constructor(IERC7802 token_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

pragma solidity ^0.8.26;

import {InteroperableAddress} from "../../utils/draft-InteroperableAddress.sol";
import {Context} from "../../utils/Context.sol";
import {ERC7786Recipient} from "../ERC7786Recipient.sol";
import {CrosschainLinked} from "../CrosschainLinked.sol";
import {InteroperableAddress} from "../../../utils/draft-InteroperableAddress.sol";
import {Context} from "../../../utils/Context.sol";
import {ERC7786Recipient} from "../../ERC7786Recipient.sol";
import {CrosschainLinked} from "../../CrosschainLinked.sol";

/**
* @dev Base contract for bridging ERC-20 between chains using an ERC-7786 gateway.
Expand All @@ -18,11 +18,11 @@ import {CrosschainLinked} from "../CrosschainLinked.sol";
* which interface with ERC-7802 to provide an approve-free user experience. It is also used by the {ERC20Crosschain}
* extension, which embeds the bridge logic directly in the token contract.
*/
abstract contract BridgeERC20Core is Context, CrosschainLinked {
abstract contract BridgeFungible is Context, CrosschainLinked {
using InteroperableAddress for bytes;

event CrosschainERC20TransferSent(bytes32 indexed sendId, address indexed from, bytes to, uint256 amount);
event CrosschainERC20TransferReceived(bytes32 indexed receiveId, bytes from, address indexed to, uint256 amount);
event CrosschainFungibleTransferSent(bytes32 indexed sendId, address indexed from, bytes to, uint256 amount);
event CrosschainFungibleTransferReceived(bytes32 indexed receiveId, bytes from, address indexed to, uint256 amount);

/**
* @dev Transfer `amount` tokens to a crosschain receiver.
Expand Down Expand Up @@ -50,7 +50,7 @@ abstract contract BridgeERC20Core is Context, CrosschainLinked {
new bytes[](0)
);

emit CrosschainERC20TransferSent(sendId, from, to, amount);
emit CrosschainFungibleTransferSent(sendId, from, to, amount);

return sendId;
}
Expand All @@ -68,7 +68,7 @@ abstract contract BridgeERC20Core is Context, CrosschainLinked {

_onReceive(to, amount);

emit CrosschainERC20TransferReceived(receiveId, from, to, amount);
emit CrosschainFungibleTransferReceived(receiveId, from, to, amount);
}

/// @dev Virtual function: implementation is required to handle token being burnt or locked on the source chain.
Expand Down
2 changes: 1 addition & 1 deletion contracts/token/ERC20/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Additionally there are multiple custom extensions, including:
* {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.
* {ERC20Crosschain}: embedded {BridgeERC20Core} bridge, making the token crosschain through the use of ERC-7786 gateways.
* {ERC20Crosschain}: embedded {BridgeFungible} bridge, making the token crosschain through the use of ERC-7786 gateways.
* {ERC20Pausable}: ability to pause token transfers.
* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC-3156).
* {ERC20Votes}: support for voting and vote delegation. xref:governance.adoc#token[See the governance guide for a minimal example (with the required overrides when combining ERC20 + ERC20Permit + ERC20Votes)].
Expand Down
6 changes: 3 additions & 3 deletions contracts/token/ERC20/extensions/ERC20Crosschain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
pragma solidity ^0.8.26;

import {ERC20} from "../ERC20.sol";
import {BridgeERC20Core} from "../../../crosschain/bridges/BridgeERC20Core.sol";
import {BridgeFungible} from "../../../crosschain/bridges/abstract/BridgeFungible.sol";

/**
* @dev Extension of {ERC20} that makes it natively cross-chain using the ERC-7786 based {BridgeERC20Core}.
* @dev Extension of {ERC20} that makes it natively cross-chain using the ERC-7786 based {BridgeFungible}.
*
* This extension makes the token compatible with counterparts on other chains, which can be:
* * {ERC20Crosschain} instances,
Expand All @@ -19,7 +19,7 @@ import {BridgeERC20Core} from "../../../crosschain/bridges/BridgeERC20Core.sol";
* * `_checkTokenBridge` (on the {ERC20Bridgeable} side) is implemented such that it only accepts self-calls.
*/
// slither-disable-next-line locked-ether
abstract contract ERC20Crosschain is ERC20, BridgeERC20Core {
abstract contract ERC20Crosschain is ERC20, BridgeFungible {
/// @dev Variant of {crosschainTransfer} that allows an authorized account (using ERC20 allowance) to operate on `from`'s assets.
function crosschainTransferFrom(address from, bytes memory to, uint256 amount) public virtual returns (bytes32) {
_spendAllowance(from, _msgSender(), amount);
Expand Down
10 changes: 5 additions & 5 deletions test/crosschain/BridgeERC20.behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ function shouldBehaveLikeBridgeERC20({ chainAIsCustodial = false, chainBIsCustod
.to.emit(this.tokenA, 'Transfer')
.withArgs(alice, chainAIsCustodial ? this.bridgeA : ethers.ZeroAddress, amount)
// crosschain transfer sent
.to.emit(this.bridgeA, 'CrosschainERC20TransferSent')
.to.emit(this.bridgeA, 'CrosschainFungibleTransferSent')
.withArgs(anyValue, alice, this.chain.toErc7930(bruce), amount)
// ERC-7786 event
.to.emit(this.gateway, 'MessageSent')
// crosschain transfer received
.to.emit(this.bridgeB, 'CrosschainERC20TransferReceived')
.to.emit(this.bridgeB, 'CrosschainFungibleTransferReceived')
.withArgs(anyValue, this.chain.toErc7930(alice), bruce, amount)
// crosschain mint event
.to.emit(this.tokenB, 'CrosschainMint')
Expand All @@ -60,12 +60,12 @@ function shouldBehaveLikeBridgeERC20({ chainAIsCustodial = false, chainBIsCustod
.to.emit(this.tokenB, 'CrosschainBurn')
.withArgs(bruce, amount, this.bridgeB)
// crosschain transfer sent
.to.emit(this.bridgeB, 'CrosschainERC20TransferSent')
.to.emit(this.bridgeB, 'CrosschainFungibleTransferSent')
.withArgs(anyValue, bruce, this.chain.toErc7930(chris), amount)
// ERC-7786 event
.to.emit(this.gateway, 'MessageSent')
// crosschain transfer received
.to.emit(this.bridgeA, 'CrosschainERC20TransferReceived')
.to.emit(this.bridgeA, 'CrosschainFungibleTransferReceived')
.withArgs(anyValue, this.chain.toErc7930(bruce), chris, amount)
// bridge on chain A releases custody of the funds
.to.emit(this.tokenA, 'Transfer')
Expand Down Expand Up @@ -114,7 +114,7 @@ function shouldBehaveLikeBridgeERC20({ chainAIsCustodial = false, chainBIsCustod
// first time works
await expect(
this.bridgeA.connect(this.gatewayAsEOA).receiveMessage(id, this.chain.toErc7930(this.bridgeB), payload),
).to.emit(this.bridgeA, 'CrosschainERC20TransferReceived');
).to.emit(this.bridgeA, 'CrosschainFungibleTransferReceived');

// second time fails
await expect(
Expand Down
4 changes: 2 additions & 2 deletions test/token/ERC20/extensions/ERC20Crosschain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ describe('ERC20Crosschain', function () {
.to.emit(this.tokenA, 'Transfer')
.withArgs(alice, ethers.ZeroAddress, amount)
// crosschain transfer sent
.to.emit(this.tokenA, 'CrosschainERC20TransferSent')
.to.emit(this.tokenA, 'CrosschainFungibleTransferSent')
.withArgs(anyValue, alice, this.chain.toErc7930(bruce), amount)
// ERC-7786 event
.to.emit(this.gateway, 'MessageSent')
// crosschain transfer received
.to.emit(this.bridgeB, 'CrosschainERC20TransferReceived')
.to.emit(this.bridgeB, 'CrosschainFungibleTransferReceived')
.withArgs(anyValue, this.chain.toErc7930(alice), bruce, amount)
// crosschain mint event
.to.emit(this.tokenB, 'CrosschainMint')
Expand Down