-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🗞️ Add MintBurnOFTAdapter.sol to oft-evm package (#1116)
- Loading branch information
Showing
8 changed files
with
389 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@layerzerolabs/oft-evm": minor | ||
--- | ||
|
||
Added MintBurnOFTAdapter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.22; | ||
|
||
// External imports | ||
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; | ||
|
||
// Local imports | ||
import { IMintableBurnable } from "./interfaces/IMintableBurnable.sol"; | ||
import { OFTCore } from "./OFTCore.sol"; | ||
|
||
/** | ||
* @title MintBurnOFTAdapter | ||
* @notice A variant of the standard OFT Adapter that uses an existing ERC20's mint and burn mechanisms for cross-chain transfers. | ||
* | ||
* @dev Inherits from OFTCore and provides implementations for _debit and _credit functions using a mintable and burnable token. | ||
*/ | ||
abstract contract MintBurnOFTAdapter is OFTCore { | ||
/// @dev The underlying ERC20 token. | ||
IERC20 internal immutable innerToken; | ||
|
||
/// @notice The contract responsible for minting and burning tokens. | ||
IMintableBurnable public immutable minterBurner; | ||
|
||
/** | ||
* @notice Initializes the MintBurnOFTAdapter contract. | ||
* | ||
* @param _token The address of the underlying ERC20 token. | ||
* @param _minterBurner The contract responsible for minting and burning tokens. | ||
* @param _lzEndpoint The LayerZero endpoint address. | ||
* @param _delegate The address of the delegate. | ||
* | ||
* @dev Calls the OFTCore constructor with the token's decimals, the endpoint, and the delegate. | ||
*/ | ||
constructor( | ||
address _token, | ||
IMintableBurnable _minterBurner, | ||
address _lzEndpoint, | ||
address _delegate | ||
) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _delegate) { | ||
innerToken = IERC20(_token); | ||
minterBurner = _minterBurner; | ||
} | ||
|
||
/** | ||
* @notice Retrieves the address of the underlying ERC20 token. | ||
* | ||
* @return The address of the adapted ERC20 token. | ||
* | ||
* @dev In the case of MintBurnOFTAdapter, address(this) and erc20 are NOT the same contract. | ||
*/ | ||
function token() public view returns (address) { | ||
return address(innerToken); | ||
} | ||
|
||
/** | ||
* @notice Indicates whether the OFT contract requires approval of the underlying token to send. | ||
* | ||
* @return requiresApproval True if approval is required, false otherwise. | ||
* | ||
* @dev In this MintBurnOFTAdapter, approval is NOT required because it uses mint and burn privileges. | ||
*/ | ||
function approvalRequired() external pure virtual returns (bool) { | ||
return false; | ||
} | ||
|
||
/** | ||
* @notice Burns tokens from the sender's balance to prepare for sending. | ||
* | ||
* @param _from The address to debit the tokens from. | ||
* @param _amountLD The amount of tokens to send in local decimals. | ||
* @param _minAmountLD The minimum amount to send in local decimals. | ||
* @param _dstEid The destination chain ID. | ||
* | ||
* @return amountSentLD The amount sent in local decimals. | ||
* @return amountReceivedLD The amount received in local decimals on the remote. | ||
* | ||
* @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, i.e., 1 token in, 1 token out. | ||
* If the 'innerToken' applies something like a transfer fee, the default will NOT work. | ||
* A pre/post balance check will need to be done to calculate the amountReceivedLD. | ||
*/ | ||
function _debit( | ||
address _from, | ||
uint256 _amountLD, | ||
uint256 _minAmountLD, | ||
uint32 _dstEid | ||
) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) { | ||
(amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid); | ||
// Burns tokens from the caller. | ||
minterBurner.burn(_from, amountSentLD); | ||
} | ||
|
||
/** | ||
* @notice Mints tokens to the specified address upon receiving them. | ||
* | ||
* @param _to The address to credit the tokens to. | ||
* @param _amountLD The amount of tokens to credit in local decimals. | ||
* | ||
* @return amountReceivedLD The amount of tokens actually received in local decimals. | ||
* | ||
* @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, i.e., 1 token in, 1 token out. | ||
* If the 'innerToken' applies something like a transfer fee, the default will NOT work. | ||
* A pre/post balance check will need to be done to calculate the amountReceivedLD. | ||
*/ | ||
function _credit( | ||
address _to, | ||
uint256 _amountLD, | ||
uint32 /* _srcEid */ | ||
) internal virtual override returns (uint256 amountReceivedLD) { | ||
if (_to == address(0x0)) _to = address(0xdead); // _mint(...) does not support address(0x0) | ||
// Mints the tokens and transfers to the recipient. | ||
minterBurner.mint(_to, _amountLD); | ||
// In the case of NON-default OFTAdapter, the amountLD MIGHT not be equal to amountReceivedLD. | ||
return _amountLD; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/oft-evm/contracts/interfaces/IMintableBurnable.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.22; | ||
|
||
/// @title Interface for mintable and burnable tokens | ||
interface IMintableBurnable { | ||
|
||
/** | ||
* @notice Burns tokens from a specified account | ||
* @param _from Address from which tokens will be burned | ||
* @param _amount Amount of tokens to be burned | ||
* @return success Indicates whether the operation was successful | ||
*/ | ||
function burn(address _from, uint256 _amount) external returns (bool success); | ||
|
||
/** | ||
* @notice Mints tokens to a specified account | ||
* @param _to Address to which tokens will be minted | ||
* @param _amount Amount of tokens to be minted | ||
* @return success Indicates whether the operation was successful | ||
*/ | ||
function mint(address _to, uint256 _amount) external returns (bool success); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-LICENSE-Identifier: UNLICENSED | ||
|
||
pragma solidity ^0.8.22; | ||
|
||
import { MintBurnOFTAdapterMock } from "../mocks/MintBurnOFTAdapterMock.sol"; | ||
import { MintBurnOFTAdapter } from "../../contracts/MintBurnOFTAdapter.sol"; | ||
|
||
// @title MintBurnOFTAdapterMockCodec | ||
// @notice Codec to convert MintBurnOFTAdapter to MintBurnOFTAdapterMock in a consistent, readable manner. | ||
// @dev For testing purposes only. | ||
library MintBurnOFTAdapterMockCodec { | ||
function asMintBurnOFTAdapterMock(MintBurnOFTAdapter _oft) internal pure returns (MintBurnOFTAdapterMock) { | ||
return MintBurnOFTAdapterMock(address(_oft)); | ||
} | ||
} |
Oops, something went wrong.