|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/ERC1363Utils.sol)
|
|
|
|
|
|
|
|
pragma solidity ^0.8.20;
|
|
|
|
|
|
|
|
import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
|
|
|
|
import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Library that provides common ERC-1363 utility functions.
|
|
|
|
*
|
|
|
|
* See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
|
|
|
|
*/
|
|
|
|
library ERC1363Utils {
|
|
|
|
/**
|
|
|
|
* @dev Indicates a failure with the token `receiver`. Used in transfers.
|
|
|
|
* @param receiver Address to which tokens are being transferred.
|
|
|
|
*/
|
|
|
|
error ERC1363InvalidReceiver(address receiver);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Indicates a failure with the token `spender`. Used in approvals.
|
|
|
|
* @param spender Address that may be allowed to operate on tokens without being their owner.
|
|
|
|
*/
|
|
|
|
error ERC1363InvalidSpender(address spender);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
|
|
|
|
*
|
|
|
|
* Requirements:
|
|
|
|
*
|
|
|
|
* - The target has code (i.e. is a contract).
|
|
|
|
* - The target `to` must implement the {IERC1363Receiver} interface.
|
|
|
|
* - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
|
|
|
|
*/
|
|
|
|
function checkOnERC1363TransferReceived(
|
|
|
|
address operator,
|
|
|
|
address from,
|
|
|
|
address to,
|
|
|
|
uint256 value,
|
|
|
|
bytes memory data
|
|
|
|
) internal {
|
|
|
|
if (to.code.length == 0) {
|
|
|
|
revert ERC1363InvalidReceiver(to);
|
|
|
|
}
|
|
|
|
|
|
|
|
try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) {
|
|
|
|
if (retval != IERC1363Receiver.onTransferReceived.selector) {
|
|
|
|
revert ERC1363InvalidReceiver(to);
|
|
|
|
}
|
|
|
|
} catch (bytes memory reason) {
|
|
|
|
if (reason.length == 0) {
|
|
|
|
revert ERC1363InvalidReceiver(to);
|
|
|
|
} else {
|
|
|
|
assembly ("memory-safe") {
|
|
|
|
revert(add(32, reason), mload(reason))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
|
|
|
|
*
|
|
|
|
* Requirements:
|
|
|
|
*
|
|
|
|
* - The target has code (i.e. is a contract).
|
|
|
|
* - The target `spender` must implement the {IERC1363Spender} interface.
|
|
|
|
* - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
|
|
|
|
*/
|
|
|
|
function checkOnERC1363ApprovalReceived(
|
|
|
|
address operator,
|
|
|
|
address spender,
|
|
|
|
uint256 value,
|
|
|
|
bytes memory data
|
|
|
|
) internal {
|
|
|
|
if (spender.code.length == 0) {
|
|
|
|
revert ERC1363InvalidSpender(spender);
|
|
|
|
}
|
|
|
|
|
|
|
|
try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) {
|
|
|
|
if (retval != IERC1363Spender.onApprovalReceived.selector) {
|
|
|
|
revert ERC1363InvalidSpender(spender);
|
|
|
|
}
|
|
|
|
} catch (bytes memory reason) {
|
|
|
|
if (reason.length == 0) {
|
|
|
|
revert ERC1363InvalidSpender(spender);
|
|
|
|
} else {
|
|
|
|
assembly ("memory-safe") {
|
|
|
|
revert(add(32, reason), mload(reason))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|