Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: added extra security measure for ERC20/ERC721 contracts #31

Open
wants to merge 1 commit into
base: tokens
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions contracts/ERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,68 +5,82 @@ import "./IERC20.sol";

contract ERC20 is IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner, address indexed spender, uint256 value
);
event Approval(address indexed owner, address indexed spender, uint256 value);

uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
string public name;
string public symbol;
uint8 public decimals;

address private _owner;

modifier onlyOwner() {
require(msg.sender == _owner, "caller is not the owner");
_;
}

constructor(string memory _name, string memory _symbol, uint8 _decimals) {
name = _name;
symbol = _symbol;
decimals = _decimals;
_owner = msg.sender;
}

function transfer(address recipient, uint256 amount)
external
returns (bool)
{
function transfer(address recipient, uint256 amount) external returns (bool) {
require(recipient != address(0), "transfer to zero address");
require(balanceOf[msg.sender] >= amount, "transfer amount exceeds balance");
require(balanceOf[msg.sender] > 0, "transfer amount must be greater than 0");

balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);

return true;
}

function approve(address spender, uint256 amount) external returns (bool) {
require(spender != address(0), "approve to 0 address");

allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}

function transferFrom(address sender, address recipient, uint256 amount)
external
returns (bool)
{
require(msg.sender != recipient, "cannot transfer to self");
allowance[sender][msg.sender] -= amount;
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
require(sender != address(0), "transfer to correct address");
require(recipient != address(0), "transfer to correct address");
require(balanceOf[sender] >= amount, "transfer amount exceeds balance");

balanceOf[sender] -= amount;
balanceOf[recipient] += amount;
allowance[sender][msg.sender] -= amount;
emit Transfer(sender, recipient, amount);
return true;
}

function _mint(address to, uint256 amount) internal {
require(to != address(0), "mint to zero address");

balanceOf[to] += amount;
totalSupply += amount;
emit Transfer(address(0), to, amount);
}

function _burn(address from, uint256 amount) internal {
require(from != address(0), "burn from the zero address");
require(balanceOf[from] >= amount, "ERC20: burn amount exceeds balance");

balanceOf[from] -= amount;
totalSupply -= amount;
emit Transfer(from, address(0), amount);
}

function mint(address to, uint256 amount) external {
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}

function burn(address from, uint256 amount) external {
function burn(address from, uint256 amount) external onlyOwner {
_burn(from, amount);
}
}
115 changes: 78 additions & 37 deletions contracts/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,42 @@
pragma solidity ^0.8.24;

interface IERC165 {
function supportsInterface(bytes4 interfaceID)
external
view
returns (bool);
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

interface IERC721 is IERC165 {
function balanceOf(address owner) external view returns (uint256 balance);

function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId)
external;

function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;

function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function transferFrom(address from, address to, uint256 tokenId) external;

function transferFrom(
address from,
address to,
uint256 tokenId
) external;

function approve(address to, uint256 tokenId) external;

function getApproved(uint256 tokenId)
external
view
returns (address operator);

function setApprovalForAll(address operator, bool _approved) external;

function isApprovedForAll(address owner, address operator)
external
view
Expand All @@ -43,13 +55,19 @@ interface IERC721Receiver {

contract ERC721 is IERC721 {
event Transfer(
address indexed from, address indexed to, uint256 indexed id
address indexed from,
address indexed to,
uint256 indexed id
);
event Approval(
address indexed owner, address indexed spender, uint256 indexed id
address indexed owner,
address indexed spender,
uint256 indexed id
);
event ApprovalForAll(
address indexed owner, address indexed operator, bool approved
address indexed owner,
address indexed operator,
bool approved
);

// Mapping from token ID to owner address
Expand All @@ -69,8 +87,9 @@ contract ERC721 is IERC721 {
pure
returns (bool)
{
return interfaceId == type(IERC721).interfaceId
|| interfaceId == type(IERC165).interfaceId;
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}

function ownerOf(uint256 id) external view returns (address owner) {
Expand All @@ -96,7 +115,6 @@ contract ERC721 is IERC721 {
);

_approvals[id] = spender;

emit Approval(owner, spender, id);
}

Expand All @@ -105,39 +123,49 @@ contract ERC721 is IERC721 {
return _approvals[id];
}

function _isApprovedOrOwner(address owner, address spender, uint256 id)
internal
view
returns (bool)
{
return (
spender == owner || isApprovedForAll[owner][spender]
|| spender == _approvals[id]
);
function _isApprovedOrOwner(
address owner,
address spender,
uint256 id
) internal view returns (bool) {
return (spender == owner ||
isApprovedForAll[owner][spender] ||
spender == _approvals[id]);
}

function transferFrom(address from, address to, uint256 id) public {
function transferFrom(
address from,
address to,
uint256 id
) public {
require(from == _ownerOf[id], "from != owner");
require(to != address(0), "transfer to zero address");

require(_isApprovedOrOwner(from, msg.sender, id), "not authorized");

_balanceOf[from]--;
_balanceOf[to]++;
_ownerOf[id] = to;

delete _approvals[id];

emit Transfer(from, to, id);
}

function safeTransferFrom(address from, address to, uint256 id) external {
function safeTransferFrom(
address from,
address to,
uint256 id
) external {
transferFrom(from, to, id);

require(
to.code.length == 0
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, "")
== IERC721Receiver.onERC721Received.selector,
to.code.length == 0 ||
IERC721Receiver(to).onERC721Received(
msg.sender,
from,
id,
""
) ==
IERC721Receiver.onERC721Received.selector,
"unsafe recipient"
);
}
Expand All @@ -151,9 +179,14 @@ contract ERC721 is IERC721 {
transferFrom(from, to, id);

require(
to.code.length == 0
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, data)
== IERC721Receiver.onERC721Received.selector,
to.code.length == 0 ||
IERC721Receiver(to).onERC721Received(
msg.sender,
from,
id,
data
) ==
IERC721Receiver.onERC721Received.selector,
"unsafe recipient"
);
}
Expand All @@ -164,25 +197,33 @@ contract ERC721 is IERC721 {

_balanceOf[to]++;
_ownerOf[id] = to;

emit Transfer(address(0), to, id);
}

function _burn(uint256 id) internal {
address owner = _ownerOf[id];
require(owner != address(0), "not minted");

_balanceOf[owner] -= 1;

_balanceOf[owner]--;
delete _ownerOf[id];
delete _approvals[id];

emit Transfer(owner, address(0), id);
}
}

contract MyNFT is ERC721 {
function mint(address to, uint256 id) external {
address private _admin;

constructor() {
_admin = msg.sender;
}

modifier onlyAdmin() {
require(msg.sender == _admin, "not authorized");
_;
}

function mint(address to, uint256 id) external onlyAdmin {
_mint(to, id);
}

Expand Down