[G-06] Using private rather than public for constants, saves gas
The values can still be inspected on the source code if necessary
There are 11 instances of this issue.
File: script/deploy/DeployRinkeby.s.sol
13: string public constant gobblerBaseUri = "https://testnet.ag.xyz/api/nfts/gobblers/";
14: string public constant gobblerUnrevealedUri = "https://testnet.ag.xyz/api/nfts/unrevealed";
15: string public constant pagesBaseUri = "https://testnet.ag.xyz/api/nfts/pages/";
File: src/ArtGobblers.sol
112: uint256 public constant MAX_SUPPLY = 10000;
115: uint256 public constant MINTLIST_SUPPLY = 2000;
118: uint256 public constant LEGENDARY_SUPPLY = 10;
122: uint256 public constant RESERVED_SUPPLY = (MAX_SUPPLY - MINTLIST_SUPPLY - LEGENDARY_SUPPLY) / 5;
126: uint256 public constant MAX_MINTABLE = MAX_SUPPLY
177: uint256 public constant LEGENDARY_GOBBLER_INITIAL_START_PRICE = 69;
180: uint256 public constant FIRST_LEGENDARY_GOBBLER_ID = MAX_SUPPLY - LEGENDARY_SUPPLY + 1;
184: uint256 public constant LEGENDARY_AUCTION_INTERVAL = MAX_MINTABLE / (LEGENDARY_SUPPLY + 1);
[G-07] x += y costs more gas than x = x + y for state variables
There's 1 instance with this issue.
File: src/ArtGobblers.sol
464: legendaryGobblerAuctionData.numSold += 1; // Increment the # of legendaries sold.
[G-08] Repeated validation logic can be refactored into a single function modifier to save gas
The logic for if (gobblerRevealsData.waitingForSeed) revert SeedPending() is used across upgradeRandProvider() and revealGobblers().
function upgradeRandProvider(RandProvider newRandProvider) external onlyOwner {
// Revert if waiting for seed, so we don't interrupt requests in flight.
if (gobblerRevealsData.waitingForSeed) revert SeedPending();
function revealGobblers(uint256 numGobblers) external {
uint256 randomSeed = gobblerRevealsData.randomSeed;
uint256 lastRevealedId = gobblerRevealsData.lastRevealedId;
uint256 totalRemainingToBeRevealed = gobblerRevealsData.toBeRevealed;
// Can't reveal if we're still waiting for a new seed.
if (gobblerRevealsData.waitingForSeed) revert SeedPending();
It can be converted into a single modifier to save gas and improve code reusability.
diff --git a/ArtGobblers.sol.orig b/ArtGobblers.sol
index 7a5925a..7700255 100644
--- a/ArtGobblers.sol.orig
+++ b/ArtGobblers.sol
@@ -271,6 +271,12 @@ contract ArtGobblers is GobblersERC721, LogisticVRGDA, Owned, ERC1155TokenReceiv
error UnauthorizedCaller(address caller);
+
+ modifier notPending(bool isWaitingForSeed) {
+ // Revert if waiting for seed, so we don't interrupt requests in flight.
+ if (isWaitingForSeed) revert SeedPending();
+ }
+
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
@@ -557,10 +563,7 @@ contract ArtGobblers is GobblersERC721, LogisticVRGDA, Owned, ERC1155TokenReceiver
/// @notice Upgrade the rand provider contract. Useful if current VRF is sunset.
/// @param newRandProvider The new randomness provider contract address.
- function upgradeRandProvider(RandProvider newRandProvider) external onlyOwner {
- // Revert if waiting for seed, so we don't interrupt requests in flight.
- if (gobblerRevealsData.waitingForSeed) revert SeedPending();
-
+ function upgradeRandProvider(RandProvider newRandProvider) external onlyOwner notPending(gobblerRevealsData.waitingForSeed) {
randProvider = newRandProvider; // Update the randomness provider.
emit RandProviderUpgraded(msg.sender, newRandProvider);
@@ -573,16 +576,13 @@ contract ArtGobblers is GobblersERC721, LogisticVRGDA, Owned, ERC1155TokenReceiver
/// @notice Knuth shuffle to progressively reveal
/// new gobblers using entropy from a random seed.
/// @param numGobblers The number of gobblers to reveal.
- function revealGobblers(uint256 numGobblers) external {
+ function revealGobblers(uint256 numGobblers) external notPending(gobblerRevealsData.waitingForSeed) {
uint256 randomSeed = gobblerRevealsData.randomSeed;
uint256 lastRevealedId = gobblerRevealsData.lastRevealedId;
uint256 totalRemainingToBeRevealed = gobblerRevealsData.toBeRevealed;
- // Can't reveal if we're still waiting for a new seed.
- if (gobblerRevealsData.waitingForSeed) revert SeedPending();
-
// Can't reveal more gobblers than are currently remaining to be revealed with the seed.
if (numGobblers > totalRemainingToBeRevealed) revert NotEnoughRemainingToBeRevealed(totalRemainingToBeRevealed);
[G-01] Prefix increment costs less gas than postfix increment
There are 2 instances of this issue.
[G-02] Cache the length of the array before the loop
There are 2 instances of this issue.
[G-03] Initializing a variable with the default value wastes gas
There are 7 instances of this issue.
[G-04] Use custom errors rather than require/revert strings to save gas
There are 28 instances of this issue.
[G-05] Use right/left shift instead of division/multiplication to save gas
There are 2 instances of this issue.
[G-06] Using private rather than public for constants, saves gas
The values can still be inspected on the source code if necessary
There are 11 instances of this issue.
[G-07] x += y costs more gas than x = x + y for state variables
There's 1 instance with this issue.
[G-08] Repeated validation logic can be refactored into a single function modifier to save gas
The logic for
if (gobblerRevealsData.waitingForSeed) revert SeedPending()
is used acrossupgradeRandProvider()
andrevealGobblers()
.https://github.com/code-423n4/2022-09-artgobblers/blob/main/src/ArtGobblers.sol#L560-L562
https://github.com/code-423n4/2022-09-artgobblers/blob/main/src/ArtGobblers.sol#L576-L584
It can be converted into a single modifier to save gas and improve code reusability.