# Jake's Audit Notes: GMO Adam NFT Client: GMO Adam Repo: https://github.com/ADAM-byGMO/contracts Commit: `9a1777596639fc07e9de349ee478fa224e1a09c9` ## Whitepaper & specification about the protocol No whitepaper on https://adam.jp/ or Jira. Background on the project at https://www.gmo.jp/en/news/article/811/ "GMO Internet Group (https://www.gmo.jp/en/ ) will realize an authentic, safe, and secure digital content payment and distribution, and support the online content distribution revolution utilizing a non-fungible token (NFT) by working on the development of Adam byGMO (https://adam.jp ), a new NFT marketplace for sellers and buyers to be launched in August 2021." Project is an NFT marketplace. ## Review of the protocol/implementation ### Adam721.sol [1] **Incorrect access control implementation** [`burn()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721.sol#L29) has no access modifier to control who may call the function. The check for the callers role is completed in a `require()` statement, but this is not best practice. Same applies in [`safeMint()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721.sol#L46), [`setBaseURI()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721.sol#L51), and [`setTokenURI()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721.sol#L56). Recommendations: [a] Use an access modifier to control who may call this function and limit `require()` checks for argument checking/external call validation. [2] **Misleading event emission on burn** [`burn()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721.sol#L29) emits an event `ChangeTokenURI()` once the token has been burnt. This is the same event that gets emitted on changes of the Token URI. Recommendations: [a] Consider emitting an event specific to burning operations. ### Adam721Factory.sol [1] **Incorrect access control implementation** [`createToken()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L22) has no access modifier to control who may call the function. The check for the callers role is completed in a `require()` statement, but this is not best practice. Same applies in [`grantRoleTokenBatch()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L32), [`revokeRoleTokenBatch()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L47), and [`setBaseURITokenBatch()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L62). Recommendations: [a] Use an access modifier to control who may call these functions and limit `require()` checks for argument checking/external call validation. [2] **Batch grant/revoke functions missing input validation** [`grantRoleTokenBatch()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L32) and [`revokeRoleTokenBatch()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Adam721Factory.sol#L47) have `grantRole()` and `revokeRole()` respectively. No checks are performed to validate if the roles being added are present or can be removed. Recommendations: [a] Confirm the roles granted and revoked to accounts are valid roles. ### AdamCustodianAdam721.sol [1] **Gas inefficient functions** [`callAdam721Burn()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianAdam721.sol#L25) and [`callAdam721SafeMintOrTransferFrom()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianAdam721.sol#L32) have `public` views. Recommendations: [a] Change function to views to be`external` for lower gas usage. [2] **Incorrect access control implementation** [`callAdam721Burn()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianAdam721.sol#L25) has no access modifier to control who may call the function. The check for the callers role is completed in a `require()` statement, but this is not best practice. Same applies in [`callAdam721SafeMintOrTransferFrom()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianAdam721.sol#L32). Recommendations: [a] Use an access modifier to control who may call these functions and limit `require()` checks for argument checking/external call validation. ### AdamCustodianERC721.sol [1] **Gas inefficient function** [`callERC721SafeTransferFrom()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianERC721.sol#L23) has a `public` view. Recommendations: [a] Change the function view to be external for lower gas usage. [2] **Incorrect access control implementation** [`callERC721SafeTransferFrom()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamCustodianERC721.sol#L23) has no access modifier to control who may call the function. The check for the callers role is completed in a `require()` statement, but this is not best practice. [a] Use an access modifier to control who may call these functions and limit require() checks for argument checking/external call validation. ### AdamEthSettlement.sol [1] **Unclear `settle()` function** [`settle()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamEthSettlement.sol#L27) is not well documented so it is hard to determine the intended implementation. It's not clear if `_sellerPrice` is actually the seller price as it's an argument passed into the function and does not have an external call to validate the price. Recommendations: [a] Document the intended implementation and usage. [2] **Access modifier inconsistency** The rest of the project uses `AccessControl` from OpenZeppelin to manage access control to external functions. `Ownable` has been used in this file which is an inconsistency. Moreover, the owner is not set in the constructor so the `onlyOwner` address is not defined. Affects [`withdrawERC20()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamEthSettlement.sol#L66), [`changeOperator()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamEthSettlement.sol#L73), and [`changeAdamWallet()`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/AdamEthSettlement.sol#L79). Recommendations: [a] Move to using `AccessControl` for function access. [b] Consider using a multi-sig wallet for protected functions instead of making admin changes using a single EOA account in the contracts. ### Migrations.sol [1] Unset Pragama version [`pragma`](https://github.com/ADAM-byGMO/contracts/blob/main/contracts/Migrations.sol#L2) compiler version is not set. This may lead to an unintended version used during deployment, with unexpected behaviour of the desired vs actual implementation. Recommendations: [a] Set to `pragma solidity 0.8.4;` as is consistent with the rest of the project. ## General Comments - Lack of doctrings on functions describing intented behaviour. Instructions in `README.md` are useful but should be docstrings instead. This helps to keep documentation consistent in the event of change to the code during development, or upgrades via proxy patterns later. - The documentation states there's a single EOA address for `DEFAULT_ADMIN_ROLE`. This should be a multi-sig account with multiple key holders.