ERC1363 support

This commit is contained in:
Moon Man 2023-08-13 19:52:11 -04:00
parent e77f44b3c1
commit 77a0cf4461
4 changed files with 293 additions and 11 deletions

View File

@ -8,11 +8,15 @@ import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.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 AbstractGrans is ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint { abstract contract AbstractGrans is IERC1363, ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint {
constructor() ERC20("10Grans", "GRANS") ERC20Permit("10Grans") { using Address for address;
} constructor() ERC20("10Grans", "GRANS") ERC20Permit("10Grans") {}
function pause() public onlyOwner { function pause() public onlyOwner {
_pause(); _pause();
@ -22,6 +26,14 @@ abstract contract AbstractGrans is ERC20, ERC20Burnable, Pausable, Ownable, ERC2
_unpause(); _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 { function _beforeTokenTransfer(address from, address to, uint256 amount) internal override whenNotPaused {
super._beforeTokenTransfer(from, to, amount); super._beforeTokenTransfer(from, to, amount);
} }
@ -40,11 +52,151 @@ abstract contract AbstractGrans is ERC20, ERC20Burnable, Pausable, Ownable, ERC2
super._burn(account, amount); super._burn(account, amount);
} }
function balanceOf(address account) public view virtual override(ERC20) returns (uint256) { function balanceOf(address account) public view virtual override(ERC20, IERC20) returns (uint256) {
return ERC20.balanceOf(account); return ERC20.balanceOf(account);
} }
function transferFrom(address sender, address recipient, uint256 amount) public virtual override(ERC20) returns (bool) { function transferFrom(address sender, address recipient, uint256 amount) public virtual override(ERC20, IERC20) returns (bool) {
return ERC20.transferFrom(sender, recipient, amount); 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))
}
}
}
}
} }

View File

@ -1,8 +1,17 @@
import { HardhatUserConfig } from "hardhat/config"; import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox"; import "@nomicfoundation/hardhat-toolbox";
import "hardhat-contract-sizer";
const config: HardhatUserConfig = { const config: HardhatUserConfig = {
solidity: "0.8.19", solidity: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
}
}; };
export default config; export default config;

123
package-lock.json generated
View File

@ -7,14 +7,16 @@
"": { "": {
"name": "10grans-ng", "name": "10grans-ng",
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "MIT",
"dependencies": { "dependencies": {
"@arbitrum/token-bridge-contracts": "^1.0.0-beta.0", "@arbitrum/token-bridge-contracts": "^1.0.0-beta.0",
"@openzeppelin/contracts": "^4.9.3" "@openzeppelin/contracts": "^4.9.3",
"erc-payable-token": "^4.9.3"
}, },
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^3.0.0", "@nomicfoundation/hardhat-toolbox": "^3.0.0",
"hardhat": "^2.17.1", "hardhat": "^2.17.1",
"hardhat-contract-sizer": "^2.10.0",
"prettier": "^3.0.1", "prettier": "^3.0.1",
"prettier-plugin-solidity": "^1.1.3" "prettier-plugin-solidity": "^1.1.3"
} }
@ -100,6 +102,16 @@
"case": "^1.6.3" "case": "^1.6.3"
} }
}, },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.1.90"
}
},
"node_modules/@cspotcode/source-map-support": { "node_modules/@cspotcode/source-map-support": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -4150,6 +4162,14 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/erc-payable-token": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/erc-payable-token/-/erc-payable-token-4.9.3.tgz",
"integrity": "sha512-hAkSyH+TfXvbTyrlcOpGhzQkSTgrRWkAktOhRUL2vY2sztYr3twjxhPydaK6CI4uf9+nk6SpujiRrPqxoDOd/w==",
"dependencies": {
"@openzeppelin/contracts": "4.9.3"
}
},
"node_modules/es-abstract": { "node_modules/es-abstract": {
"version": "1.22.1", "version": "1.22.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz",
@ -5814,6 +5834,105 @@
} }
} }
}, },
"node_modules/hardhat-contract-sizer": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz",
"integrity": "sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
"cli-table3": "^0.6.0",
"strip-ansi": "^6.0.0"
},
"peerDependencies": {
"hardhat": "^2.0.0"
}
},
"node_modules/hardhat-contract-sizer/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/hardhat-contract-sizer/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/hardhat-contract-sizer/node_modules/cli-table3": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
"integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0"
},
"engines": {
"node": "10.* || >= 12.*"
},
"optionalDependencies": {
"@colors/colors": "1.5.0"
}
},
"node_modules/hardhat-contract-sizer/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/hardhat-contract-sizer/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/hardhat-contract-sizer/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/hardhat-contract-sizer/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/hardhat-gas-reporter": { "node_modules/hardhat-gas-reporter": {
"version": "1.0.9", "version": "1.0.9",
"resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz",

View File

@ -21,11 +21,13 @@
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^3.0.0", "@nomicfoundation/hardhat-toolbox": "^3.0.0",
"hardhat": "^2.17.1", "hardhat": "^2.17.1",
"hardhat-contract-sizer": "^2.10.0",
"prettier": "^3.0.1", "prettier": "^3.0.1",
"prettier-plugin-solidity": "^1.1.3" "prettier-plugin-solidity": "^1.1.3"
}, },
"dependencies": { "dependencies": {
"@arbitrum/token-bridge-contracts": "^1.0.0-beta.0", "@arbitrum/token-bridge-contracts": "^1.0.0-beta.0",
"@openzeppelin/contracts": "^4.9.3" "@openzeppelin/contracts": "^4.9.3",
"erc-payable-token": "^4.9.3"
} }
} }