---
# System prepended metadata

title: Security Audit of `Demotapers`

---

# Security Audit of `Demotapers`

![](https://i.imgur.com/DreWe7g.png)


## Conclusion

This audit was made by [Web3Go](https://web3go.tech) 
Auditor: Vladimir Smelov <vsmelov.job@gmail.com>.
Date: 2022-10-14

In the final contract were **NOT FOUND**:
- Backdoors for investor funds withdrawal by anyone.
- Bugs allow stealing money from the contract.
- Any severe security problems.

There were **FOUND**:
- Places for beautification (typos, refactoring).
- Places for gas optimization.

The client was acknowledged about all notes below.
All required fixes were done.

**The code is ready for use.**

## Scope

#### Pre-audit

- DemotapersMarket.sol, md5 hash: 15087969b0afbb82ca857566c92b7dad  
- DemotapersNFT.sol, md5 hash: 8e4f1ab4455ece7321412a6417cfc06e  
- DemotapersNFTTest.sol, md5 hash: d7fe1a1b2387f27c515eb2137ff27ad4  
- ERC165.sol, md5 hash: d336cb34366e7303e3f82b2beba86921 

#### Final audit

TO BE DONE

## Methodology

1. Blind audit. Understand the structure of the code without reading any docs.
2. Ask questions to developers.
3. Draw the scheme of cross-contracts interactions.
4. Write user stories and usage cases.
5. Run static analyzers.
6. Find problems with:
- backdoors;
- bugs;
- math;
- potential leaking of funds;
- potential locking of the contract;
- validate arguments and events;
- others.

## Result

### Critical

Not found.

___


### Major

Not found.

___

### Warning


#### WARNING-1. Centralization power - The owner may change metadata.

- src/contracts/DemotapersNFT.sol:123

At any moment, the owner may turn all tokens into something completely unusable just by changing the baseURI value.

##### Recommendation

Use Gnosis Multisig. Consider the usage of individual tokenURI with immutable decentralized storage (like IPFS).

##### Status
ACKNOWLEDGED


___

### Comment.


#### COMMENT-1. Consider the usage of off-chain sales.

At:
- src/contracts/DemotapersNFT.sol
- src/contracts/DemotapersMarket.sol

To sell NFT to someone for a specific price, there should be 

1. Mint NFT by owner
2. listItems by owner
3. buyItem by user

Every operation costs gas and takes time.

You can publish to your website (covered by the frontend) ECDSA signatures for not-minted-yet NFT with signing (tokenId, price, deadline).

Then if someone wants to get NFT, he calls:

```solidity
function buyAndMint(tokenId, price, deadline, ownerSignature) external payable {
    _verifySignature(tokenId, price, deadline, ownerSignature);
    require(msg.value == price);
    require(block.timestamp < deadline);
    _mint(tokenId, msg.sender);
}
```

In that way, the owner pays no gas for minting and listing.

Similar mechanics are used in well-known OpenSea and Rarible.

##### Recommendation

Consider the usage of listing via off-chain signatures.

##### Status
ACKNOWLEDGED

The client wants to first mint and then sell NFTs.

---

#### COMMENT-2. Calculate signatures at compilation time rather than have them hard-coded.

At:
- src/contracts/ERC165.sol:9
- src/contracts/DemotapersNFT.sol:32-38


You have hard-coded constants like

```solidity
_INTERFACE_ID_ERC165 = 0x01ffc9a7;
```

Any typo in any symbol will lead to an untrackable mistake, which will be impossible to find.

##### Recommendation

Consider rewriting to human-readable form:

```solidity
_INTERFACE_ID_ERC165 = bytes4(keccak256('supportsInterface(bytes4)')); // 0x01ffc9a7 
```
##### Status
FIXED

The double check of "magic" hashes was added.


---



#### COMMENT-3. ERC165 implementation is gas-costly.

At:
- src/contracts/ERC165.sol:17


You read storage to check if the contract supports the interface or not.

```solidity
function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
    return _supportedInterfaces[interfaceId];
}
```

It costs 2100 gas - https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a6-sload

##### Recommendation

Consider rewriting to OpenZeppelin style with inheritance and OR operators.

##### Status
ACKNOWLEDGED

Not a big issue since, interface registry is done only once and view methods are not to be used intensevily.


--- 


#### COMMENT-4. Emit events on important state changes.

At:
- src/contracts/DemotapersNFT.sol:124
- src/contracts/DemotapersMarket.sol:155

Some important state variable is changed, but you cannot track them since you don't emit an event.

##### Recommendation

Emit event on essential state changes.

##### Status
ACKNOWLEDGED

These actions are done by the contract Owner, so no monitoring is needed.


--- 



#### COMMENT-5. Useless structure.

At:
- src/contracts/DemotapersMarket.sol:35

The structure has only one attribute, so it's useless.

##### Recommendation

Remove the structure.

##### Status
FIXED

---


#### COMMENT-6. Use `immutable` declarations.

At:
- src/contracts/DemotapersMarket.sol:39

Declare the variable as `immutable`; it saves gas.

##### Recommendation

Use `immutable` declarations.

##### Status
FIXED


---


#### COMMENT-7. Explicitly state the interface of the variable.

At:
- src/contracts/DemotapersMarket.sol:39

Declare the variable as `IERC721` for clarity.

##### Recommendation

Consider refactoring.

##### Status
FIXED

---

#### COMMENT-8. Use the `unchecked` declaration for index increment.

At:
- src/contracts/DemotapersMarket.sol:47
- src/contracts/DemotapersMarket.sol:66
- src/contracts/DemotapersMarket.sol:98
- src/contracts/DemotapersMarket.sol:110
- src/contracts/DemotapersNFT.sol:158

You have default solidity 0.8.x safeMath enabled for an increment:

```solidity=
for (uint i=0; i < tokenIds.length; i++) {
    ...
}
```

But you know for sure that `i` will never overflow.

##### Recommendation

Consider explicitly unchecking the increment to save gas:

```solidity=
for (uint i=0; i < tokenIds.length;) {
    unchecked{i++;}
    ...
}
```
##### Status
ACKNOWLEDGED

Skipped for the code clarity.

---

#### COMMENT-9. Avoid double SLOAD.

Whenever you call 
- `cancelListing`
- `updateListing
- `buyItem`

You first read the storage in the modifier; then, you SLOAD the same storage slot in the function itself.

##### Recommendation

Consider the removal of modifiers and do all checks in one for-loop with one SLOAD to save gas.

##### Status
ACKNOWLEDGED

Skipped to avoid the logic duplication.

---


#### COMMENT-10. Prevent sending extensive ether.

At:
- src/contracts/DemotapersMarket.sol:139

It's better to require strictly.

```
if (msg.value != listedItem.price) {
    revert PriceNotMet(tokenId, listedItem.price);
}
```

To prevent user mistakes.

##### Recommendation

Consider using a strict check.

##### Status
FIXED


---


#### COMMENT-11. Never use `payable(...).transfer`.

At:
- src/contracts/DemotapersMarket.sol:154

You use the old-fashion style of sending the ethers.
See - https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/

##### Recommendation

Use `payable{value: value}.call("");`

##### Status
FIXED


---


#### COMMENT-12. Add recoverERC20 and recoverERC721 to prevent user mistakes.

Users often make mistakes, occasionally directly sending wETH to the contract or sending NFT to the contract.

##### Recommendation

Consider adding 
`recoverERC20`, `recoverERC721` to recover tokens sent to the contract by mistake.
##### Status
FIXED


---


#### COMMENT-13. Don't use `uint256(x) <= 0`

- src/contracts/DemotapersMarket.sol:59
- src/contracts/DemotapersMarket.sol:69
- src/contracts/DemotapersMarket.sol:91
- src/contracts/DemotapersMarket.sol:123

uint256 may never be under `0`; it's confusing to check `<= 0`.

##### Recommendation

Consider replacing with `== 0`.
##### Status
FIXED

---


#### COMMENT-14. Remove useless stack variables.

- src/contracts/DemotapersMarket.sol:94

You don't need a separate stack variable.

##### Recommendation

Consider rewriting:


```solidity
if (!IERC721(nft).isApprovedForAll(msg.sender, address(this))) {
```

##### Status
FIXED


---


#### COMMENT-15. Import OpenZeppelin code.

- src/contracts/DemotapersNFT.sol:16-24

you can import 
- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/extensions/IERC721Metadata.sol
- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Receiver.sol

Also, you can inherit 80% of the code of DemotapersNFT from 
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol

##### Recommendation

Consider importing OpenZeppelin code.

##### Status
ACKNOWLEDGED



---



#### COMMENT-16. Rename symbol "DMT".

- src/contracts/DemotapersNFT.sol:42

"DMT" is a well-known drug (type "DMT" in Google).


##### Recommendation

Consider renaming.

##### Status
FIXED

---



#### COMMENT-17. Unused `_marketAddress` variable.

- src/contracts/DemotapersNFT.sol

you never use `_marketAddress`, `setMarketAddress`, `getMarketAddress` for any business logic.

##### Recommendation

Consider removing.

##### Status
FIXED

---



#### COMMENT-18. Use `tokenId` rather than `tokenIndex`.

- src/contracts/DemotapersNFT.sol

You use variables named `tokenIndex`; however, the standard EIP-721 defines them as `tokenId`.

See - https://eips.ethereum.org/EIPS/eip-721

##### Recommendation

Consider renaming.

##### Status
FIXED


---



#### COMMENT-19. Fix typo in `tokenOowner`.

- src/contracts/DemotapersNFT.sol

##### Recommendation

Consider renaming it to `tokenOwner`.

##### Status
FIXED




---



#### COMMENT-20. Avoid calling `totalSupply` in a loop.

- src/contracts/DemotapersNFT.sol:159

`totalSupply()` is a costly operation.

##### Recommendation

Consider replacing with `first+i`

##### Status
FIXED


---



#### COMMENT-21. Remove the Context usage.

- src/contracts/DemotapersNFT.sol

You never switch the context, so you don't need to use `_msgSender()`

##### Recommendation

Consider replacing it with `msg.sender` to save gas.

##### Status
FIXED



---



#### COMMENT-22. Optimize `_approve`.

- src/contracts/DemotapersNFT.sol:399

You load `owner()`, but you already loaded it when you called the function.

##### Recommendation

Avoid double SLOAD.

##### Status
ACKNOWLEDGED


---



#### COMMENT-23. Move test and mock contracts to a separate folder.

- src/contracts/DemotapersNFTTest.sol

##### Recommendation

Consider moving this contract to a separate folder, "mocks" or "tests."

##### Status
FIXED



