Platform: Code4rena
Start Date: 08/03/2023
End Date: 15/03/2023
Period: 7 days
Status: Completed
Pot Size: $60,500 USDC
Participants: 123
Reporter: liveactionllama
Judge: hansfriese
Id: 220
League: ETH
adriro | 1/123 | $3,665.60 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
rbserver | 2/123 | $3,209.67 | 3 | 2 | 0 | 0 | 0 | Grade A | 0 | 0 |
Haipls | 3/123 | $3,209.67 | 3 | 2 | 0 | 0 | 0 | Grade A | 0 | 0 |
minhquanym | 4/123 | $3,004.10 | 3 | 2 | 0 | 0 | 0 | Grade B | 0 | 0 |
ABA | 5/123 | $3,004.10 | 3 | 2 | 0 | 0 | 0 | Grade B | 0 | 0 |
auditor0517 | 6/123 | $2,974.43 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
J4de | 7/123 | $2,974.43 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Madalad | 8/123 | $2,868.66 | 3 | 1 | 0 | 0 | 0 | Grade B | Grade B | 0 |
joestakey | 9/123 | $2,849.36 | 2 | 1 | 0 | 0 | 0 | Grade B | 0 | 0 |
Dug | 10/123 | $2,849.36 | 2 | 1 | 0 | 0 | 0 | Grade B | 0 | 0 |
Auditor per page
Automated findings output for the contest can be found here within an hour of contest opening.
Note for C4 wardens: Anything included in the automated findings output is considered a publicly known issue and is ineligible for awards.
The Neo Tokyo ecosystem can be complicated to explain. To request any additional clarification, please contact Tim Clancy. Any answered questions will be added to an FAQ section.
Neo Tokyo is an NFT ecosystem consisting of:
beckLoot.sol
.vaultBox.sol
.NTItems.sol
.NTLandDeploy.sol
.BYTESContract.sol
.NTCitizenDeploy.sol
. Neo Tokyo S1 Citizens are currently created by burning BYTES 1.0 tokens and combining an S1 Identity, S1 Item, S1 Land, and optionally an S1 Vault. As part of these contracts, this S1 Citizen creation process will begin using the new BYTES 2.0 contract.Similarly to the Neo Tokyo S1 Citizens, there exists an ecosystem of Neo Tokyo S2 Citizens:
NTOuterIdentity.sol
.NTS2Items.sol
.NTS2LandDeploy.sol
.NTOuterCitizenDeploy.sol
. The Neo Tokyo S2 Citizen is created by combining the other component pieces, though that fact is irrelevant to the specifics of this staking system.The Neo Tokyo staking program operates as follows:
?
-tier Vault.VAULT_CAP
value.NO_VAULT_CAP
value.We are aware that a staker will continue earning their timelocked bonus after fulfilling their entire timelock duration. This is expected.
The only contracts that are in scope for this contest are the two listed below, excluding any concerns regarding centralization or malicious administrator risk.
Contract | SLOC | Purpose | Libraries used |
---|---|---|---|
BYTES2.sol (partial, see below) | 88 | the new Neo Tokyo ERC-20 | @openzeppelin/* |
NeoTokyoStaker.sol (partial, see below) | 881 | the new Neo Tokyo staker | @openzeppelin/* |
We are already aware of some gas optimizations that we have opted not to make for the sake of clarity and simplicity, which we believe ultimately improves security. For each in-scope function we will note gas optimizations that we do not consider to be in-scope.
We are aware that specific assumptions about the Neo Tokyo ecosystem mean that structs can likely be packed more efficiently. Therefore we consider any gas optimization based on more efficiently aligning structs to be trivial and out of scope.
The BYTES2
contract is the implementation of the new Neo Tokyo BYTES 2.0 smart contract, which will be configured across the entire ecosystem using existing Neo Tokyo administrative calls such as NTCitizenDeploy.setBytesAddress
.
Within this contract, the only functions in scope are:
BYTES2.upgradeBytes
, which is intended to be called by any holder of the existing Neo Tokyo BYTES 1.0 ERC-20 token to let them convert some amount of their BYTES 1.0 tokens into BYTES 2.0 tokens.BYTE2.getReward
, which is intended to be the primary entry-point for a staking caller to claim earned BYTES 2.0 tokens.
-- There may exist a more optimal way to perform this mint of BYTES than calculating the mintable BYTES totals through performing the cross-contract call to NeoTokyoStaker.claimReward
. We don't care about this optimization if it should exist.BYTES2.burn
, which is intended to use the PermitControl
role system to allow configured administrative callers in the Neo Tokyo ecosystem to burn BYTES 2.0 tokens on behalf of users with no approval required. A finding related to a potential token holder's inability to directly burn their own ERC-20 tokens is out of scope. Any finding related to the centralized risk of an administrator maliciously burning all of a holder's tokens is out of scope. Any finding related to not being in perfect compliance with the ERC-20 standard is out of scope.BYTES2.updateReward
, which is a no-op intended to let the BYTES 2.0 contract prevent functionality in the NTCitizenDeploy
contract from breaking (namely getReward
, transferFrom
, and safeTransferFrom
).BYTES2.updateRewardOnMint
, which is a no-op intended to let the BYTES 2.0 contract prevent functionality in the NTCitizenDeploy
contract from breaking (namely createCitizen
).The NeoTokyoStaker
contract implements the new staking methodology in the Neo Tokyo ecosystem by which holders of Neo Tokyo Citizens (both S1 and S2) and holders of a future BYTES 2.0 LP token may earn BYTES 2.0 tokens. Excluding the initial migration by holders from BYTES 1.0 tokens to BYTES 2.0 tokens using BYTES2.upgradeBytes
, the logic implemented in this contract is intended to be the only means by which new BYTES 2.0 tokens may be earned.
Within this contract, the only functions in scope are:
NeoTokyoStaker.getCreditYield
, which is intended to accurately deduce the otherwise-unavailable string "Credit Yield" trait of a Neo Tokyo S1 Citizen given its token ID and potential Vault ID.NeoTokyoStaker.getConfiguredVaultMultiplier
, which is intended to accurately retrieve the administrator-configured values of Neo Tokyo vault configuration.NeoTokyoStaker.getStakerPosition
and NeoTokyoStaker.getStakerPositions
, which are intended to give accurate observability into the state of a particular staker's position across various staked assets.NeoTokyoStaker._assetTransferFrom
and NeoTokyoStaker._assetTransfer
, which are intended to support transfer of the Neo Tokyo S1 Citizens, S2 Citizens, BYTES 2.0 ERC-20 tokens, and future BYTES 2.0 LP tokens to and from the Neo Tokyo escrow-based staker contract. The only assets these functions operate on should be configurable by an administrator. Any findings related to any problems caused by malicious assets configured by administrators are therefore not valid.NeoTokyoStaker._stakeS1Citizen
/NeoTokyoStaker._stakeS2Citizen
/NeoTokyoStaker._stakeBytes
/NeoTokyoStaker._stakeLP
/NeoTokyoStaker.stake
, which are intended to support staking various assets for being held in escrow by the Neo Tokyo staker contract. Ensuring the safety of these functions are a primary focus of this audit; staking logic should behave correctly and barring malicious administrator activity staker assets should always be recoverable.NeoTokyoStaker.getPoolReward
and NeoTokyoStaker.claimReward
, which are respectively intended to accurately calculate the pending rewards of a staker and permit the claiming of rewards through the BYTES2.getReward
entry-point. Ensuring the safety and accuracy of these functions are a primary focus of this audit; barring malicious administrator activity stakers should receive the BYTES 2.0 tokens that they are entitled to without earning excessive tokens.NeoTokyoStaker._withdrawS1Citizen
/NeoTokyoStaker._withdrawS2Citizen
/NeoTokyoStaker._withdrawLP
/NeoTokyoStaker.withdraw
, which are intended to support withdrawing various assets that have been previously staked. Ensuring the safety and accuracy of these functions are a primary focus of this audit; withdrawing logic should behave correctly and barring malicious administrator activity withdrawing staker assets should always function correctly.Every file and contract function not explicitly listed above is considered out of scope for this contest in terms of both security and gas optimization. Any changes to the smart contracts which are stylistic in nature are also out of scope.
This includes the entire existing Neo Tokyo ecosystem consisting of the deployed mainnet versions of beckLoot
(Neo Tokyo S1 Identities), vaultBox
(Neo Tokyo S1 Vaults), NTItems
(Neo Tokyo S1 Items), NTLandDeploy
(Neo Tokyo S1 Land), BYTESContract
(Neo Tokyo BYTES 1.0), NTBytesBridge
(Neo Tokyo BYTES 1.0 Bridge), NTCitizenDeploy
(Neo Tokyo S1 Citizen), NTOuterIdentity
(Neo Tokyo S2 Identities), NTS2Items
(Neo Tokyo S2 Items), NTS2LandDeploy
(Neo Tokyo S2 Land), NTOuterCitizenDeploy
(Neo Tokyo S2 Citizens).
This also includes the specific testing mock contracts IdentityMint
, VaultMint
, CitizenMint
, and LPToken
. These testing contracts are used to prepare mock data for their relevant Neo Tokyo ecosystem assets; in the production Neo Tokyo ecosystem this data was prepared using different administrative mechanisms assumed to be correct.
This also includes the IByteContract
, IGenericGetter
and IStaker
interface contracts.
This also includes any OpenZeppelin dependencies being imported. Specifically ReentrancyGuard
, ERC20
, and IERC20
are used in our two in-scope contracts. We assume these contracts to be safe. We know there may exist more gas-optimized alternatives to these contracts but that consideration remains out of scope.
This also includes the PermitControl
dependency used for administrative access control. This is a well-tested contract that we consider completely out of scope.
This also includes any concerns about centralization or administrative functions in the smart contracts. We are aware of the damage that could be caused by both a malicious administrator or administrative misconfiguration. We will negate these concerns via other mechanisms (timelocks, future DAO caller, etc.) assuming the underlying safety of the relevant staking mechanisms. Specifically, these functions are completely out of scope in terms of both administrative functionality and gas optimization:
BYTES2.changeStakingContractAddress
, which is intended to let an administrator change the potential NeoTokyoStaker
contract address.BYTES2.changeTreasuryContractAddress
, which is intended to let an administrator change the address of the Neo Tokyo DAO treasury.NeoTokyoStaker.configureLP
, which is intended to let an administrator change the address of the LP token.NeoTokyoStaker.lockLP
, which is intended to let an administrator lock the LP token address against future changes.NeoTokyoStaker.configureTimelockOptions
, which is intended to let an administrator configure available timelock staking options.NeoTokyoStaker.configureIdentityCreditYields
, which is intended to let an administrator configure the available Neo Tokyo S1 Identity "Credit Yield" strings corresponding to S1 Citizen reward rate and Vault reward rate pairs.NeoTokyoStaker.configureIdentityCreditPoints
, which is intended to let an administrator configure the points weight earned by each configured Neo Tokyo S1 Identity "Credit Yield" trait.NeoTokyoStaker.configureVaultCreditMultipliers
, which is intended to let an administrator configure the point multipliers earned by each Citizen's component Vault.NeoTokyoStaker.configurePools
, which is intended to let an administrator configure the reward points accrued by a particular asset type across a particular time window.NeoTokyoStaker.configureCaps
, which is intended to let an administrator configure the respective Neo Tokyo S1 and S2 Citizen staking caps.One exception that we consider out of scope for gas optimization but in scope for any security issues unrelated to a malicious administrator is the legacy reward-claiming flow of calling NTCitizenDeploy.getReward
, which ultimately calls BYTES2.getReward
. We support this legacy flow for historic UI reasons and would consider a security finding to be relevant.
The most novel feature of this smart contract is perhaps the ability to boost the point weight of a staked S1 or S2 Citizen by depositing BYTES 2.0 tokens into the Citizen. Otherwise, this staking system is a rather straightforward timelocked staker where callers compete for a fixed emissions rate, similar to many previous implementations such as Chef Nomi's MasterChef
staker for Sushi.
- If you have a public code repo, please share it here: This contest repo is the only public code repo at this time. - How many contracts are in scope?: 2 - Total SLoC for these contracts?: 969 - How many external imports are there?: 8 - How many separate interfaces and struct definitions are there for the contracts within scope?: 11 - Does most of your code generally use composition or inheritance?: Inheritance - How many external calls?: 10 - What is the overall line coverage percentage provided by your tests?: 80 - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: True - Please describe required context: The Neo Tokyo ecosystem consists of several NFT drops that were performed over time. These NFTs may ultimately be combined together to form a new type of NFT which is involved in this staking contract. Several of the details for staking logic are dictated by the independent component NFTs that were used in combining. - Does it use an oracle?: No - Does the token conform to the ERC20 standard?: True - Are there any novel or unique curve logic or mathematical models?: There is nothing particularly novel here. The staking logic is essentially a Chef Nomi MasterChef-style competitive staker for fixed ERC-20 token emissions. - Does it use a timelock function?: True - Is it an NFT?: True - Does it have an AMM?: False - Is it a fork of a popular project?: False - Does it use rollups?: False - Is it multi-chain?: False - Does it use a side-chain?: False - Describe any specific areas you would like addressed: We are most particularly concerned about ensuring that there is no way for a user to lose access to their staked NFTs or ERC-20 tokens. We are secondarily concerned about ensuring that there is no way for an attacker to earn excessive token emissions for their staking.
To build the project from a fresh git clone
, perform the following.
npm install
.npx hardhat test
.hardhat.config.js
and should provide automatic gas reporting for the relevant contracts used in testing.In the scripts folder, you will find a determine-citizen-yields.js
file along with an output.txt
file that it generated. You should not need this information for testing, but it is included here to illustrate the method of deducing a Neo Tokyo S1 Citizen's component Identity "Credit Yield" trait as provided to the staker via NeoTokyoStaker.configureIdentityCreditPoints
.