I am creating a simple crypto trading card program on remix/solidity. Currently, I am storing each trading card as a uint256 in an array of length 99,999,999 indexes.
Each card has its own rarity, which is calculated using its uint256 ID. I want to make my program as gas-efficient as possible. When finding the rarity of a card, would it be cheaper to repeatedly calculate the cards' rarity like this:
uint[99999999] private cards;
// card id calculation etc. //
function findCardRarity(uint _randNum) internal returns (string memory) {
uint cardRemainder = findCardRemainder(_randNum);
if (cardRemainder < 10) {
return "unique";
} else if (10 <= cardRemainder < 10010) {
return "legendary";
} else if (10010 <= cardRemainder < 1010010) {
return "rare";
} else if (1010010 <= cardRemainder < 11010010) {
return "uncommon";
} else {
return "common";
}
or to store it once as an attribute of a struct like this:
struct Card{
uint cardNumber;
string rarity;
}
Card[] public cards;
function assignRarity(_cardId) internal {
uint cardRemainder = findCardRemainder(_randNum);
if (cardRemainder < 10) {
cards[_cardId].rarity = "unique";
} else if (10 <= cardRemainder < 10010) {
cards[_cardId].rarity = "legendary";
} else if (10010 <= cardRemainder < 1010010) {
cards[_cardId].rarity = "rare";
} else if (1010010 <= cardRemainder < 11010010) {
cards[_cardId].rarity = "uncommon";
} else {
cards[_cardId].rarity = "common";
}
}
// then create cards and assign rarity //
I ask this as I'm not sure if it's cheaper to store data on the blockchain as part of a struct or to execute calculations on the blockchain repeatedly, on each instance of a function call. This is my first smart contract.
Generally speaking, storage is much more expensive than computational costs. So my gut feel answer is that your set of if-else statements would be more gas efficient than switching from using
uint256[]toCard[]where eachCardis auint256and astring.Details:
SLOADopcodes, which cost 100 or 2,100 gas unitsSSTOREopcodes, which cost 2,100 to 20,000 gas units (and the calculation is complex)But I'll end with a disclaimer:
It is super hard to work out what the actual EVM opcodes your solidity code will actually generate, so the best way top know for sure is to write both variants, compile, deploy, run tests, and measure the before and after balances to work out the aggregate gas costs.
Another thing worth considering is that you should consider smart contract deployment gas fees separately from smart contract function invocation gas fees. For deployment, the length of the bytecode generated is what matters. So in your example, the variant with many if-else statements is likely to generate more verbose bytecode, and therefore cost more gas to deploy. Whereas the variant with the structs is likely to cost less gas to deploy. Which is, in effect, the reverse of the function invocation gas costs.