Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas fees very high on safeTransfer Method #145

Closed
dilukangelosl opened this issue Mar 1, 2022 · 7 comments
Closed

Gas fees very high on safeTransfer Method #145

dilukangelosl opened this issue Mar 1, 2022 · 7 comments

Comments

@dilukangelosl
Copy link

I minted 310 tokens at a single transaction.
Eg: 0 to 310

Safetransfering Token ID is around $8
Safetransfering Token ID 300 is around $300

Wonder whats caused the price change for high index tokens.

This only happens for higher transactions

@ahbanavi
Copy link
Contributor

ahbanavi commented Mar 1, 2022

When you are transferring a token, contract checks the owner of the token using ownershipOf function.
This function may run a loop and that's cost SLOAD for each iteration, and when batch size is high (like 310) and you want to transfer 300th token, the loop iterate from 300 to 0 and that cost 300 SLOADs.

while (true) {
curr--;
ownership = _ownerships[curr];
if (ownership.addr != address(0)) {
return ownership;
}
}

You could use small batch size like 5 or 10.
Also see #83 and this tweet.

@EmanuelCampos
Copy link

ERC721A/contracts/ERC721A.sol

Could

When you are transferring a token, contract checks the owner of the token using ownershipOf function. This function may run a loop and that's cost SLOAD for each iteration, and when batch size is high (like 310) and you want to transfer 300th token, the loop iterate from 300 to 0 and that cost 300 SLOADs.

while (true) {
curr--;
ownership = _ownerships[curr];
if (ownership.addr != address(0)) {
return ownership;
}
}

You could use small batch size like 5 or 10. Also see #83 and this tweet.

Could you explain better about use small batch size? it's abbout small batch in mint? so the transfer will be more cheaper?

@ahbanavi
Copy link
Contributor

ahbanavi commented Mar 1, 2022

Could you explain better about use small batch size? it's abbout small batch in mint? so the transfer will be more cheaper?

Yes, you are right in both questions.
Contracts can implement a maxBatchSize variable and limit the quantity that a minter can mint in a single transaction.

uint256 private constant maxBatchSize = 5;

function mint(quantity) external payable {
    require(quantity <= maxBatchSize, "quantity to mint too high");
    .
    .
    .
   _safeMint(msg.sender, quantity);
}

By setting a small maxBatchSize, you are also limiting the maximum iteration of the loop inside ownershipOf.
Therefore, the maximum gas that this function costs would be lower.
In other words, the ownershipOf function became O(maxBatchSize).

@Vectorized
Copy link
Collaborator

Vectorized commented Mar 1, 2022

Just transfer from lowest id to highest id. The fees will be as low as possible.

Some suggestions if you want to circumvent this:

  • Look into ERC721AOwnersExplicit.
  • Mint in mini batches of size 8 internally if someone mints a big batch (8 is chosen as a good balance between _mint and _transfer costs).
  • Simply restricting the max batch size for public mints to a reasonable number.

We didn’t include those by default to give projects the flexibility to balance between _mint and _transfer costs. For example, power users or teams can do a _mint for hundreds of tokens at a very low cost and choose to slowly release their tokens in ascending order.

@Vectorized
Copy link
Collaborator

Closing this, as users have several options to reduce the first-time transfer gas usage to reasonable levels.

Please refer to the documentation for tips.

@basememara
Copy link

I minted 5000 NFTs at once, which doesn't seem like the intended use of this contract.. I'm supposed to batch them in groups of 8? Since I batch minted them all, transferring token 1 is about $10 while transferring token 4000 is $700-800. Any ideas or insights on how to fix my scenario?

@Vectorized
Copy link
Collaborator

Vectorized commented Jul 29, 2022

@basememara What you can do now is to batch transfer every 10th NFT to some wallet you own. (1,11,21,…4991)

Do that when the gwei is like less than 10.

You can use some tool like https://nft.life/batch-transfer. Do call setApprovalForAll on Etherscan first to approve the batch transfer contract to transfer your NFTs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants