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

Assignment: Tokens security vulnerabilities checks #35

Open
wants to merge 2 commits 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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"solidity.compileUsingRemoteVersion": "v0.8.14+commit.80d49f37"
"solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# BlockHeaderWeb3 Cohort 5
Introduction to the fundamentals of EVM-based smart contract development
Introduction to the fundamentals of EVM-based smart contract development
87 changes: 87 additions & 0 deletions contracts/ERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./IERC20.sol";
import "./Ownable.sol";
import "./ReentrancyGuard.sol";

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

// Proper Events for burn and mint functions
event Mint(address indexed to, uint256 value);
event Burn(address indexed from, uint256 value);

uint256 public totalSupply;
string public name;
string public symbol;

// decimal state was missing
uint8 public decimals;

mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;

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

function transfer(address recipient, uint256 amount)
external
nonReentrant // Added Reentrancy Guard modifier
returns (bool)
{
require(balanceOf[msg.sender] >= amount, "Insufficient balance"); // Check if there is enough balance to go through
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);

return true;
}

function approve(address spender, uint256 amount) external onlyOwner returns (bool) { // Only owner can approve spender
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}

function transferFrom(address sender, address recipient, uint256 amount)
external
nonReentrant
returns (bool)
{
require(balanceOf[sender] >= amount, "Insufficient balance"); // Check if sender has enough balance to go through
require(allowance[sender][msg.sender] >= amount, "Allowance exceeded"); // Check if address has enough allocation

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

function _mint(address to, uint256 amount) internal onlyOwner { // Only owner can mint tokens
balanceOf[to] += amount;
totalSupply += amount;
emit Mint(to, amount); // proper log mint action
}

function _burn(address from, uint256 amount) internal onlyOwner { // Only owner can burn tokens
balanceOf[from] -= amount;
totalSupply -= amount;
emit Burn(from, amount); // proper log burn action
}

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

function burn(address from, uint256 amount) external {
_burn(from, amount);
}
}
205 changes: 205 additions & 0 deletions contracts/ERC721.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./Ownable.sol";
import "./ReentrancyGuard.sol";

interface IERC165 {
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,
bytes calldata data
) 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
returns (bool);
}

interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}

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

// Proper event for MINT/BURN
event Mint(
address indexed to, uint256 indexed id
);

event Burn(
address indexed owner, uint256 indexed id
);

// Mapping from token ID to owner address
mapping(uint256 => address) internal _ownerOf;

// Mapping owner address to token count
mapping(address => uint256) internal _balanceOf;

// Mapping from token ID to approved address
mapping(uint256 => address) internal _approvals;

// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) public isApprovedForAll;

function supportsInterface(bytes4 interfaceId)
external
pure
returns (bool)
{
return interfaceId == type(IERC721).interfaceId
|| interfaceId == type(IERC165).interfaceId;
}

function ownerOf(uint256 id) external view returns (address owner) {
owner = _ownerOf[id];
require(owner != address(0), "token doesn't exist");
}

function balanceOf(address owner) external view returns (uint256) {
require(owner != address(0), "owner = zero address");
return _balanceOf[owner];
}

function setApprovalForAll(address operator, bool approved) external {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}

function approve(address spender, uint256 id) external onlyOwner {
address owner = _ownerOf[id];
require(
msg.sender == owner || isApprovedForAll[owner][msg.sender],
"not authorized"
);

_approvals[id] = spender;

emit Approval(owner, spender, id);
}

function getApproved(uint256 id) external view returns (address) {
require(_ownerOf[id] != address(0), "token doesn't exist");
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 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 nonReentrant { // Reentrancy Guard added
transferFrom(from, to, id);

require(
to.code.length == 0
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, "")
== IERC721Receiver.onERC721Received.selector,
"unsafe recipient"
);
}

function safeTransferFrom(
address from,
address to,
uint256 id,
bytes calldata data
) external nonReentrant { // Reentrancy Guard added
transferFrom(from, to, id);

require(
to.code.length == 0
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, data)
== IERC721Receiver.onERC721Received.selector,
"unsafe recipient"
);
}

function _mint(address to, uint256 id) internal nonReentrant { // Reentrancy Guard added
require(to != address(0), "mint to zero address");
require(_ownerOf[id] == address(0), "already minted");

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

emit Mint(to, id); // Proper event for Mint
}

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

_balanceOf[owner] -= 1;

delete _ownerOf[id];
delete _approvals[id];

emit Burn(owner, id);
}
}

contract MyNFT is ERC721 {
function mint(address to, uint256 id) external onlyOwner { // Can only be called by contract owner
_mint(to, id);
}

function burn(uint256 id) external onlyOwner { // Can only be called by contract owner
require(msg.sender == _ownerOf[id], "not owner");
_burn(id);
}
}
18 changes: 18 additions & 0 deletions contracts/IERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount)
external
returns (bool);
}
17 changes: 0 additions & 17 deletions contracts/IStudentRegistry.sol

This file was deleted.

31 changes: 0 additions & 31 deletions contracts/MyStudentRegistry.sol

This file was deleted.

Loading