10grans-ng/contracts/AbstractToken.sol

204 lines
8.5 KiB
Solidity

// 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))
}
}
}
}
}