Omniscia AllianceBlock Audit

AllianceBlockToken Code Style Findings

AllianceBlockToken Code Style Findings

ABT-01C: Enhancement of State Validation

TypeSeverityLocation
Gas OptimizationAllianceBlockToken.sol:L65-L68

Description:

The snapshot function is meant to create a snapshot of the token balances of each account. In the current implementation, a snapshot is always created when the protocol is paused, hence rendering snapshot invocations during the token's paused state to be ineffectual.

Example:

contracts/AllianceBlockToken.sol
57/**
58 * @dev Creates a new snapshot and returns its snapshot id.
59 *
60 * Emits a {Snapshot} event that contains the same id.
61 *
62 * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a
63 * set of accounts, for example using {AccessControl}, or it may be open to the public.
64 */
65function snapshot() public returns (uint256) {
66 require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "NXRA: Snapshot invalid role");
67 return _snapshot();
68}
69
70/**
71 * @dev Returns the cap on the token's total supply.
72 */
73function cap() external view virtual returns (uint256) {
74 return _cap;
75}
76
77/**
78 * @dev Pauses all token transfers.
79 *
80 * See {ERC20Pausable} and {Pausable-_pause}.
81 *
82 * Requirements:
83 *
84 * - the caller must have the `PAUSER_ROLE`.
85 */
86function pause() public override {
87 super.pause();
88 _snapshot();
89}

Recommendation:

We advise a require check to be introduced that ensures the token is not paused when snapshot is invoked, preventing incorrect and gas-burdening snapshots from being created.

Alleviation (5bde836b591caa6c3dfd47b79f323317a26c8a0d):

The snapshot mechanism now adequately evaluates that the protocol is not paused, ensuring snapshots are solely created once when the protocol is in a paused state.

ABT-02C: Loop Iterator Optimization

TypeSeverityLocation
Gas OptimizationAllianceBlockToken.sol:L106

Description:

The linked for loop increments / decrements the iterator "safely" due to Solidity's built-in safe arithmetics(post - 0.8.X).

Example:

contracts/AllianceBlockToken.sol
106for (uint256 i = 0; i < recipientsLength; i++) {

Recommendation:

We advise the increment / decrement operation to be performed in an unchecked code block as the last statement within the for loop to optimize its execution cost.

Alleviation (5bde836b591caa6c3dfd47b79f323317a26c8a0d):

The loop iterator has been optimized by being relocated to the end of the for loop and wrapped in an unchecked code block as advised.

ABT-03C: Potential Batch Mint Optimization

TypeSeverityLocation
Gas OptimizationAllianceBlockToken.sol:L107, L122-L125

Description:

Given that the token implementation's batchMint operation is expected to be invoked multiple times, we advise it to be made as optimal as possible. It currently invokes the _mint function overridden in the AllianceBlockToken that imposes a _cap on the total supply, however, this is inefficient as the cap can be evaluated at the end of the function.

Example:

contracts/AllianceBlockToken.sol
96/**
97 * @dev Mints multiple values for multiple receivers
98 */
99function batchMint(address[] memory recipients, uint256[] memory values) public returns (bool) {
100 require(hasRole(MINTER_ROLE, _msgSender()), "NXRA: Batch mint invalid role");
101
102 uint256 recipientsLength = recipients.length;
103 require(recipientsLength == values.length, "NXRA: Batch mint not same legth");
104
105 uint256 totalValue = 0;
106 for (uint256 i = 0; i < recipientsLength; i++) {
107 _mint(recipients[i], values[i]);
108 unchecked {
109 // Overflow not possible: totalValue + amount is at most totalSupply + amount, which is checked above.
110 totalValue += values[i];
111 }
112 }
113
114 emit BatchMint(_msgSender(), recipientsLength, totalValue);
115 return true;
116}
117
118/**
119 * @dev See {ERC20-_mint}.
120 * @dev Checks if cap is reached and calls normal _mint.
121 */
122function _mint(address account, uint256 amount) internal override {
123 require(ERC20Upgradeable.totalSupply() + amount <= _cap, "NXRA: cap exceeded");
124 super._mint(account, amount);
125}

Recommendation:

We advise it to invoke super._mint instead and the _cap check to occur after the for loop by evaluating that the ERC20Upgradeable.totalSupply() is less-than-or-equal-to (<=) the value of _cap, significantly reducing the gas cost of the function.

Alleviation (5bde836b591caa6c3dfd47b79f323317a26c8a0d):

The batchMint function has been significantly optimized by evaluating the total supply cap at the end of its execution as per our recommendation.

ABT-04C: Potentially Incorrect Error Messages

TypeSeverityLocation
Code StyleAllianceBlockToken.sol:L30, L46, L66, L100, L103, L123

Description:

The referenced error messages make mention of the NXRA acronym whilst the token itself is meant to represent AllianceBlock.

Example:

contracts/AllianceBlockToken.sol
100require(hasRole(MINTER_ROLE, _msgSender()), "NXRA: Batch mint invalid role");

Recommendation:

We advise them to be evaluated and aptly renamed if deemed incorrect.

Alleviation (5bde836b591caa6c3dfd47b79f323317a26c8a0d):

The AllianceBlock team stated that NXRA is the intended symbol / ticker of the token rendering this exhibit nullified as the error messages are correctly defined.