2023-08-13 15:15:29 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2023-08-20 01:06:10 +00:00
|
|
|
pragma solidity ^0.8.19;
|
2023-08-13 15:15:29 +00:00
|
|
|
|
|
|
|
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";
|
2023-08-20 02:27:18 +00:00
|
|
|
// Without paying gas, token holders will be able to allow third parties to transfer from their account. (EIP2612)
|
2023-08-13 15:15:29 +00:00
|
|
|
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
|
2023-08-13 23:52:11 +00:00
|
|
|
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";
|
|
|
|
|
2023-08-20 13:46:39 +00:00
|
|
|
abstract contract AbstractToken is IERC1363, ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint {
|
2023-08-13 23:52:11 +00:00
|
|
|
using Address for address;
|
|
|
|
|
2023-08-20 13:46:39 +00:00
|
|
|
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) ERC20Permit(_name) {}
|
2023-08-13 15:15:29 +00:00
|
|
|
|
|
|
|
function pause() public onlyOwner {
|
|
|
|
_pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
function unpause() public onlyOwner {
|
|
|
|
_unpause();
|
|
|
|
}
|
|
|
|
|
2023-08-13 23:52:11 +00:00
|
|
|
/**
|
|
|
|
* @dev See {IERC165-supportsInterface}.
|
|
|
|
*/
|
|
|
|
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165) returns (bool) {
|
|
|
|
return interfaceId == type(IERC1363).interfaceId;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-13 15:15:29 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-08-13 23:52:11 +00:00
|
|
|
function balanceOf(address account) public view virtual override(ERC20, IERC20) returns (uint256) {
|
2023-08-13 15:15:29 +00:00
|
|
|
return ERC20.balanceOf(account);
|
|
|
|
}
|
|
|
|
|
2023-08-13 23:52:11 +00:00
|
|
|
function transferFrom(address sender, address recipient, uint256 amount) public virtual override(ERC20, IERC20) returns (bool) {
|
2023-08-13 15:15:29 +00:00
|
|
|
return ERC20.transferFrom(sender, recipient, amount);
|
|
|
|
}
|
2023-08-13 23:52:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-13 15:15:29 +00:00
|
|
|
}
|