// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; // Without paying gas, token holders will be able to allow third parties to transfer from their account. (EIP2612) import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import "erc-payable-token/contracts/token/ERC1363/IERC1363.sol"; import "erc-payable-token/contracts/token/ERC1363/IERC1363Spender.sol"; import "erc-payable-token/contracts/token/ERC1363/IERC1363Receiver.sol"; abstract contract AbstractToken is IERC1363, ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint { using Address for address; constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) ERC20Permit(_name) {} function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165) returns (bool) { return interfaceId == type(IERC1363).interfaceId; } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override whenNotPaused { super._beforeTokenTransfer(from, to, amount); } // The following functions are overrides required by Solidity. function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._afterTokenTransfer(from, to, amount); } function _mint(address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._mint(to, amount); } function _burn(address account, uint256 amount) internal override(ERC20, ERC20Votes) { super._burn(account, amount); } function balanceOf(address account) public view virtual override(ERC20, IERC20) returns (uint256) { return ERC20.balanceOf(account); } function transferFrom(address sender, address recipient, uint256 amount) public virtual override(ERC20, IERC20) returns (bool) { return ERC20.transferFrom(sender, recipient, amount); } /** * @dev Transfer tokens to a specified address and then execute a callback on `to`. * @param to The address to transfer to. * @param amount The amount to be transferred. * @return A boolean that indicates if the operation was successful. */ function transferAndCall(address to, uint256 amount) public virtual override returns (bool) { return transferAndCall(to, amount, ""); } /** * @dev Transfer tokens to a specified address and then execute a callback on `to`. * @param to The address to transfer to * @param amount The amount to be transferred * @param data Additional data with no specified format * @return A boolean that indicates if the operation was successful. */ function transferAndCall(address to, uint256 amount, bytes memory data) public virtual override returns (bool) { transfer(to, amount); require(_checkOnTransferReceived(_msgSender(), to, amount, data), "ERC1363: receiver returned wrong data"); return true; } /** * @dev Transfer tokens from one address to another and then execute a callback on `to`. * @param from The address which you want to send tokens from * @param to The address which you want to transfer to * @param amount The amount of tokens to be transferred * @return A boolean that indicates if the operation was successful. */ function transferFromAndCall(address from, address to, uint256 amount) public virtual override returns (bool) { return transferFromAndCall(from, to, amount, ""); } /** * @dev Transfer tokens from one address to another and then execute a callback on `to`. * @param from The address which you want to send tokens from * @param to The address which you want to transfer to * @param amount The amount of tokens to be transferred * @param data Additional data with no specified format * @return A boolean that indicates if the operation was successful. */ function transferFromAndCall( address from, address to, uint256 amount, bytes memory data ) public virtual override returns (bool) { transferFrom(from, to, amount); require(_checkOnTransferReceived(from, to, amount, data), "ERC1363: receiver returned wrong data"); return true; } /** * @dev Approve spender to transfer tokens and then execute a callback on `spender`. * @param spender The address allowed to transfer to * @param amount The amount allowed to be transferred * @return A boolean that indicates if the operation was successful. */ function approveAndCall(address spender, uint256 amount) public virtual override returns (bool) { return approveAndCall(spender, amount, ""); } /** * @dev Approve spender to transfer tokens and then execute a callback on `spender`. * @param spender The address allowed to transfer to. * @param amount The amount allowed to be transferred. * @param data Additional data with no specified format. * @return A boolean that indicates if the operation was successful. */ function approveAndCall(address spender, uint256 amount, bytes memory data) public virtual override returns (bool) { approve(spender, amount); require(_checkOnApprovalReceived(spender, amount, data), "ERC1363: spender returned wrong data"); return true; } /** * @dev Internal function to invoke {IERC1363Receiver-onTransferReceived} on a target address. * The call is not executed if the target address is not a contract. * @param sender address Representing the previous owner of the given token amount * @param recipient address Target address that will receive the tokens * @param amount uint256 The amount mount of tokens to be transferred * @param data bytes Optional data to send along with the call * @return whether the call correctly returned the expected magic value */ function _checkOnTransferReceived( address sender, address recipient, uint256 amount, bytes memory data ) internal virtual returns (bool) { if (!recipient.isContract()) { revert("ERC1363: transfer to non contract address"); } try IERC1363Receiver(recipient).onTransferReceived(_msgSender(), sender, amount, data) returns (bytes4 retval) { return retval == IERC1363Receiver.onTransferReceived.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC1363: transfer to non ERC1363Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } /** * @dev Internal function to invoke {IERC1363Receiver-onApprovalReceived} on a target address. * The call is not executed if the target address is not a contract. * @param spender address The address which will spend the funds * @param amount uint256 The amount of tokens to be spent * @param data bytes Optional data to send along with the call * @return whether the call correctly returned the expected magic value */ function _checkOnApprovalReceived( address spender, uint256 amount, bytes memory data ) internal virtual returns (bool) { if (!spender.isContract()) { revert("ERC1363: approve a non contract address"); } try IERC1363Spender(spender).onApprovalReceived(_msgSender(), amount, data) returns (bytes4 retval) { return retval == IERC1363Spender.onApprovalReceived.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC1363: approve a non ERC1363Spender implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } }