## 4 Implementation
### Smart Contract
\begin{table}
\begin{tabular}{l c c} \hline \hline  & **ERC-721 (Gas)** & **ERC-1155 (Gas)** \\ \hline Contract initialization & 1,965,192 & 2,320,645 \\ Minting of a token & 93,723 & 52,486 \\ Transfer of token & 58,496 & 41,776 \\ \hline \hline \end{tabular}
\end{table} 
Table 1: Comparison of gas costs for ERC-721 and ERC-1155 baseline implementations. * The data contained within the QR code is hashed together with constant data for the contract, such as ID of the chain it is deployed at and the contracts address. * Using the hash and public key of the administrator for the game, the signature is verified. * The remaining cards from the pack are verified to be from the same game to prevent abuse. * The proof of ownership for cards that the user chose to secure are minted. The code of card redemption process followed by the in depth explanation is presented in Listing 2. ```
functionclaimBooster(  BoosterPackcalldataboosterPack,  bool[]memorywantPrinted )publicpayable{ uint32 gameId=_getGameId(boosterPack.ids[0]); uint80 collectionId=_getCollectionId(boosterPack.ids[0]); require(!mintedNonces[gameId][collectionId][boosterPack.nonce], \"TCGProt:mintingalreadyusednonce\" ); bytes32 hash=keccak256(  abi.encodePacked(  boosterPack.ids,  boosterPack.nonce,  block.chainid,  address(this) ); hash=keccak256(  abi.encodePacked(\"\x19 EthereumSignedMessage:\
32\",hash) ); addresssigner=ECDSA.recover(hash,boosterPack.signature); bytes32 role=keccak256(abi.encodePacked(\"MINTER_ROLE\",gameId)); require(  hasRole(role,signer),  \"TCGProt:Somecardswerenotsignedbyvalidminterforthis );
```  
Listing 2: Card Booster redemption process. To redeem the pack, the first nonce is checked if it was used to prevent unnecessary calculations. If the nonce is valid, the hash of the provided data is calculated. It contains cards included in the pack, as well as additional information, such as nonce, address of the contract, and chain id. The last two will prevent double-use attacks, where the system could be deployed on multiple chains or under multiple addresses. In this way, a booster is designated to be used in the exact system and cannot be abused. Using this hash, it is possible to verify that the user-provided signature matches the data and then recover the signer from it. Then, from the first card of the booster, the game id is derived. Finally, the recovered signer is compared to the signer registered in the game. If it matches,that means the authority responsible for this game signed the booster, and we are safe to proceed. The first part of the function only verified if the booster pack was indeed created by the game developer (Listing 3). As signature derivation and role comparison can be costly operations, they are done once. Still, other cards need to be checked to prevent valid game developers from providing consumers with access to cards from games they do not control. This is done by comparing the game id from each following card against the original one for which role authorization was performed (Listing 4). If there is a mismatch, that means that cards inside the booster are inconsistent with their game identity and will not be minted. ```
for(uint8i=1;i<boosterPack.ids.length;i++){ require( gameId==_getGameId(boosterPack.ids[i]), \"TGGProt:Cardidsarefromdifferentgames\" ); } }
```  
Listing 3: Verification of cards. ```
uint256[]memoryamounts=newuint256[](wantPrinted.length); for(uint8i=0;i<wantPrinted.length;i++){ amounts[i]=wantPrinted[i]?1:0; } require( boosterPack.ids.length==wantPrinted.length, \"TGGProt:idsandwishlistlength mismatch\" ); }
```  
Listing 4: Minting the tokens. Finally cards requested to be minted by the user are verified. For each card contained in the booster, marked to be minted, the token is created for the redeeming entity. This operation is batched to reduce the cost. The nonce will be marked as used for the current collection and game. Additionally, the information about tokens is extracted using supplementary functions.