EIP ERC721 Implementation
Published: 2024-02-16 12:37:30

ERC 721 is different from ERC 20 token standard because it allows us to create a group of tokens that are uniquely different from each other. This feature allows NFTs to represent assets such as digital collectibles, physical properties, etc. 

The ERC 721 standard has nine (9) functions, three (3) events, and one (1) interface.

First we create our state variables, mappings, and constructor.

## State Variables

```Javascript

 // Token name
 string private _name;

 // Token symbol
 string private _symbol;

```

## Mappings

```Javascript

// To track the NFT (tokenId) and get the owner's address  
mapping(uint256 tokenId => address) private _ownersOf;

// To track the address to get the NFTs owned
mapping(address owner => uint256) private _balancesOf;

// To track approval of a particular NFT that other addresses can interact with.
mapping(uint256 tokenId => address) private _approvals;

// To grant approval for all the NFT in the address to another
mapping(address owner => mapping(address operator => bool)) private _IsApprovedForAll;

```

## Constructor 

```javascript
// Here we are setting the name and symbol for our collection
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}

```

## Functions

**1. Balance Of:**
This returns the number of NFTs owned by an address passed into `_owner`

**Specification:**

```python
function balanceOf(address _owner) external view returns (uint256);
```
**Implementation:**

```Javascript
function balanceOf(address owner) public view virtual returns (uint256) {

return _balancesOf[owner];

}
```
**2. Owner Of:**
This returns the owner to an NFT

**Specification:**

```python
function ownerOf(uint256 _tokenId) external view returns (address);
```
**Implementation:**

```Javascript
function ownerOf(uint256 tokenId) public view virtual returns (address) {

return  owner = _ownerOf[tokenId];

}
```

**3. Set Approval For All:**
Enable or disable approval for a third party ("operator") to manage all of `msg.sender`'s assets

**Specification:**

```python
function setApprovalForAll(address _operator, bool _approved) external;

```
**Implementation:**

```Javascript
function setApprovalForAll(address operator, bool approved) external {

isApprovedForAll[msg.sender][operator] = approved;

emit ApprovalForAll(msg.sender, operator, approved);
}
```

**4. Approval:**
Change or reaffirm the approved address for an NFT

**Specification:**

```python
function approve(address _approved, uint256 _tokenId) external payable;

```
**Implementation:**

```Javascript
function approve(address spender, uint id) external {

address owner = _ownerOf[id];

require(
msg.sender == owner || isApprovedForAll[owner][msg.sender],
"not authorized" );

_approvals[id] = spender;

emit Approval(owner, spender, id);

}

```
**5.Get Approval:**
Get the approval on an address for a single NFT

**Specification:**

```python
function getApproved(uint256 _tokenId) external view returns (address);

```
**Implementation:**

```Javascript
function getApproved(uint id) external view returns (address) {

require(_ownerOf[id] != address(0), "token doesn't exist");

return _approvals[id];

}

```
**6. Approved or Owner:**
if an address is an authorized operator owner and checks if _owner The address that owns the NFTs

**Specification:**

```python
function isApprovedForAll(address _owner, address _operator) external view returns (bool);

```
**Implementation:**

```Javascript
function isApprovedOrOwner(
address owner,
address spender,
uint id
) internal view returns (bool) {

return (spender == owner ||
isApprovedForAll[owner][spender] ||
spender == _approvals[id]);

}

```
**7. Transfer From:**
Transfer ownership of an NFT 

**Specification:**

```python
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

```
**Implementation:**

```Javascript
function transferFrom(address from, address to, uint 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);

 }

```



**8. Safe Tranfer From Address to Address:**
Transfers the ownership of an NFT from one address to another address
**Specification:**

```python
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

```
**Implementation:**

```Javascript
function safeTransferFrom(address from, address to, uint id) external {

transferFrom(from, to, id);

require(

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

```

**9. Safe Transfer From Address to Contract:**
Transfers the ownership of an NFT from one address to contract address.

**Specification:**

```python
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
```
**Implementation:**

```Javascript
function safeTransferFrom(
address from,
address to,
uint id,
bytes calldata data
) external {

transferFrom(from, to, id);

require(

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

);
}
```