Neo Tokyo contest - 0x1f8b's results

A staking contract for the crypto gaming illuminati.

General Information

Platform: Code4rena

Start Date: 08/03/2023

Pot Size: $60,500 USDC

Total HM: 2

Participants: 123

Period: 7 days

Judge: hansfriese

Id: 220

League: ETH

Neo Tokyo

Findings Distribution

Researcher Performance

Rank: 57/123

Findings: 2

Award: $48.97

QA:
grade-b
Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Low

1. Lack of checks address(0)

The following methods have a lack of checks if the received argument is an address, it's good practice in order to reduce human error to check that the address specified in the constructor or initialize is different than address(0).

Affected source code:

2. Lack of event emit

The changeStakingContractAddress and changeTreasuryContractAddress methods do not emit an event when the state changes, something that it's very important for dApps and users.

Affected source code:

3. Unsafe transfer

It does not check the return returned in the case of ERC-20, so a token that returns false could incur economic losses for the user or the project.

It is necessary to check that if data is a boolean, it is positive, just like Open Zeppelin's SafeTransfer does.

Affected source code:


Non critical

4. Typo

Tab was used instead of a space:

S2) and BYTES for time-locked emission rewards. The staker operates on a

Affected source code:

5. Avoid hardcoded values

It is not good practice to hardcode values, but if you are dealing with addresses much less, these can change between implementations, networks or projects, so it is convenient to remove these values from the source code.

Affected source code:

Use the selector instead of the raw value:

#0 - c4-judge

2023-03-17T02:36:58Z

hansfriese marked the issue as grade-b

#1 - TimTinkers

2023-03-21T01:11:07Z

Acknowledging the typo, thanks.

#2 - c4-sponsor

2023-03-21T01:11:11Z

TimTinkers marked the issue as sponsor acknowledged

Gas

1. Optimize stringEquals

It is possible to optimize the comparison of 2 string using a hash function.

Sample:

pragma solidity ^0.8.19;

contract testA
{
	function stringEquals (
		string memory _a,
		string memory _b
	) public pure returns (bool) {
		bytes memory a = bytes(_a);
		bytes memory b = bytes(_b);
		
		// Check equivalence of the two strings by comparing their contents.
		bool equal = true;
		assembly {
			let length := mload(a)
			switch eq(length, mload(b))

			// Proceed to compare string contents if lengths are equal. 
			case 1 {
				let cb := 1

				// Iterate through the strings and compare contents.
				let mc := add(a, 0x20)
				let end := add(mc, length)
				for {
					let cc := add(b, 0x20)
				} eq(add(lt(mc, end), cb), 2) {
					mc := add(mc, 0x20)
					cc := add(cc, 0x20)
				} {

					// If any of these checks fails then arrays are not equal.
					if iszero(eq(mload(mc), mload(cc))) {
						equal := 0
						cb := 0
					}
				}
			}

			// By default the array length is not equal so the strings are not equal.
			default {
				equal := 0
			}
		}
		return equal;
	}
}

contract testB
{
	function stringEquals (
		string memory _a,
		string memory _b
	) public pure returns (bool) {
        bytes memory a = bytes(_a);
		bytes memory b = bytes(_b);
		if (a.length != b.length) return false;
		return keccak256(a) == keccak256(b);
	}
}

With my result it's cheaper using keccak256:

+ With one character ("a") or 32 characters ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"): 1251 before, 1173 after
+ With 64 characters ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"): 1356 before, 1197 after

Because is only used for if (_stringEquals(class, "Hand of Citadel")) { that is less than 32 bytes, it will be cheaper using keccak256

Affected source code:

2. Optimize stake

The following logic is redundant an can be removed because it's not possible to send a different type and also it's checked that the rewardCount has a value with _pools[_assetType].rewardCount == 0.

	function stake (
		AssetType _assetType,
		uint256 _timelockId,
		uint256,
		uint256,
		uint256
	) external nonReentrant {

-		// Validate that the asset being staked is of a valid type.
-		if (uint8(_assetType) > 4) {
-			revert InvalidAssetType(uint256(_assetType));
-		}

		// Validate that the asset being staked matches a configured pool.
		if (_pools[_assetType].rewardCount == 0) {
			revert UnconfiguredPool(uint256(_assetType));
		}

Affected source code:

#0 - c4-judge

2023-03-17T03:42:57Z

hansfriese marked the issue as grade-b

#1 - c4-sponsor

2023-03-21T01:12:23Z

TimTinkers marked the issue as sponsor confirmed

#2 - TimTinkers

2023-03-21T01:12:37Z

Thanks, good catch.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter