So, let's analyze this a little...
There are many functions in the XENFT contract, but as far as I can tell, only this one seems to be impacted by the number of XENFTs person owns.:
_afterTokenTransfer
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
_ownedTokens[from].removeItem(tokenId);
_ownedTokens[to].addItem(tokenId);
}
It seems, that when someone transfers a XENFT, the system checks the list of all XENFTs the sender owns, in order to find and remove the specific XENFT that is being transferred. If the sender has many XENFTs, it takes longer for the system to find and remove the specific one that is being transferred, which has a direct implication on the cost of gas.
This is because _ownedTokens[from].removeItem(tokenId) searches for the tokenId of the XENFT in the array of tokens owned by from in order to be able to remove it. It appears that the worst-case scenario for this operation is when the tokenId is the last item in the array, which would require iterating through the entire array. Therefore, we can say, that the gas consumption for this operation is proportional to the number of tokens owned by from.
So, why does this happen? Well, think of it like searching for a specific book in a large library versus a small one. The larger the library (or the more XENFTs the sender has), the longer it takes to find that XENFT (or book). And that means, that more tokens the sender has, the more it might cost them in terms of the overall transaction fees because the system has to search through a longer list. Now, this won't be an issue for the receiver, because adding the token to their list is straightforward (like placing a book on an empty shelf), so it shouldn't matter how many XENFTs they already have (this action is quick).
Anyways, if I understand this correctly (DON'T QUOTE ME ON THIS ONE) this may also mean that there could be a limit on each chain, for how many XENFTs someone can hold, before being unable to transfer them.
Someone can do the math on this, but it'd likely be gas dependent...
--
For those that worry about claiming XEN from existing XENFT. As far as I can tell, the total number of XENFTs shouldn't impact claiming XENFT cost, which is handled by this function:
bulkClaimMintReward
function bulkClaimMintReward(uint256 tokenId, address to) external notBeforeStart nonReentrant {
require(ownerOf(tokenId) == _msgSender(), "XENFT: Incorrect owner");
require(to != address(0), "XENFT: Illegal address");
require(!mintInfo[tokenId].getRedeemed(), "XENFT: Already redeemed");
bytes memory bytecode = bytes.concat(
bytes20(0x3D602d80600A3D3981F3363d3d373d3D3D363d73),
bytes20(address(this)),
bytes15(0x5af43d82803e903d91602b57fd5bf3)
);
uint256 end = vmuCount[tokenId] + 1;
bytes memory callData = abi.encodeWithSignature("callClaimMintReward(address)", to);
bytes memory callData1 = abi.encodeWithSignature("powerDown()");
for (uint256 i = 1; i < end; i++) {
bytes32 salt = keccak256(abi.encodePacked(i, tokenId));
bool succeeded;
bytes32 hash = keccak256(abi.encodePacked(hex"ff", address(this), salt, keccak256(bytecode)));
address proxy = address(uint160(uint256(hash)));
assembly {
succeeded := call(gas(), proxy, 0, add(callData, 0x20), mload(callData), 0, 0)
}
require(succeeded, "XENFT: Error while claiming rewards");
assembly {
succeeded := call(gas(), proxy, 0, add(callData1, 0x20), mload(callData1), 0, 0)
}
require(succeeded, "XENFT: Error while powering down");
}
_setRedeemed(tokenId);
emit EndTorrent(_msgSender(), tokenId, to);
}
The Bulk Claim Mint Reward function shouldn't be impacted by the number of XENFTs held in someone's wallet, because bulkClaimMintReward function's gas consumption is influenced by the number of VMUs being claimed and not by the total number of XENFTs held in the wallet. Also the functions such as bulkClaimRank and bulkClaimRankLimited (for APEX) that initiate a creation of new XENFTs do not seem to be directly impacted by the number of XENFTs already held in the wallet.