{"id":20974228,"url":"https://github.com/thirdweb-example/play-to-earn-game","last_synced_at":"2025-06-16T02:36:05.637Z","repository":{"id":37765840,"uuid":"506216558","full_name":"thirdweb-example/play-to-earn-game","owner":"thirdweb-example","description":"Use thirdweb's token, edition drop, and a custom contract using thirdweb deploy to build a Play-to-Earn game!","archived":false,"fork":false,"pushed_at":"2024-04-12T00:33:03.000Z","size":204,"stargazers_count":76,"open_issues_count":4,"forks_count":77,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-14T12:37:01.491Z","etag":null,"topics":["contract-kit","erc1155","erc20","erc721","extensions","thirdweb-deploy"],"latest_commit_sha":null,"homepage":"https://play-to-earn.thirdweb-example.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thirdweb-example.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-22T11:24:30.000Z","updated_at":"2025-03-07T16:09:59.000Z","dependencies_parsed_at":"2024-04-12T01:45:45.271Z","dependency_job_id":null,"html_url":"https://github.com/thirdweb-example/play-to-earn-game","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thirdweb-example/play-to-earn-game","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fplay-to-earn-game","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fplay-to-earn-game/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fplay-to-earn-game/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fplay-to-earn-game/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thirdweb-example","download_url":"https://codeload.github.com/thirdweb-example/play-to-earn-game/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fplay-to-earn-game/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260086740,"owners_count":22956856,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contract-kit","erc1155","erc20","erc721","extensions","thirdweb-deploy"],"created_at":"2024-11-19T04:27:19.024Z","updated_at":"2025-06-16T02:36:05.608Z","avatar_url":"https://github.com/thirdweb-example.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!Important]  \r\n\u003e This repository is referencing the `mumbai` chain.\r\n\u003e \r\n\u003e `Mumbai` [is deprecated since 08/04/2024](https://blog.thirdweb.com/deprecation-of-mumbai-testnet/), meaning the code in this repository will no longer work out of the box.\r\n\u003e\r\n\u003e You can still use this repository, however you will have to switch any references to `mumbai` to another chain.\r\n\r\n# thirdweb Play-to-Earn Example\r\n\r\nThis example project is a simple Play-to-Earn (P2E) game!\r\n\r\n## The Idea\r\n\r\nThe game is a \"mining\" game, where your character mines for gold gems!\r\n\r\nIn the beginning, you start out with nothing! In order to play the game, you need to:\r\n\r\n1. Mint your character NFT (ERC-1155 using the [Edition Drop](https://portal.thirdweb.com/pre-built-contracts/edition-drop) contract)\r\n2. Purchase a pickaxe NFT from the \"Shop\" (Another ERC-1155 using an [Edition Drop](https://portal.thirdweb.com/pre-built-contracts/edition-drop) contract)\r\n3. \"Equip\" (stake) the pickaxe NFT in the [Mining](./contracts/contracts/Mining.sol) contract (built with [thirdweb deploy](https://portal.thirdweb.com/thirdweb-deploy))\r\n4. Start earning \"Gold Gems\"; ERC-20 tokens (using the [Token](https://portal.thirdweb.com/pre-built-contracts/token) contract)\r\n\r\n\u003c!-- Image of miner --\u003e\r\n\u003cimg src='./application/public/mine.gif' height='48'\u003e\r\n\u003cimg src='./application/public/pickaxe.png'  height='48'\u003e\r\n\u003cimg src='./application/public/gold-gem.png' height='48'\u003e\r\n\r\nYou can use the GEMs you earn to purchase higher tier pickaxes, which will increase your rewards per block.\r\n\r\n```js\r\n( 0 + 1 ) * 10_000_000_000_000 / 100_000_000_000_000_000  gold gems per block.\r\n```\r\n\r\nOnce you have earned enough GEM tokens, you can use them to purchase higher tier pickaxes.\r\n\r\nFor example, when you buy the \"Stone Hammer\" (token ID `1`) for 10 GEMs, you will earn:\r\n\r\n```js\r\n// 1 (Token ID of stone hammer) + 1 = Rewards Multiplier\r\n// 10_000_000_000_000 / 100_000_000_000_000_000 = The number of GEMs rewarded per block (since the token has 18 decimals)\r\n( 1 + 1 ) * 10_000_000_000_000 / 100_000_000_000_000_000 gold gems per block.\r\n```\r\n\r\n**Check out the Demo here**: https://play-to-earn.thirdweb-example.com/\r\n\r\n## Using this Example\r\n\r\nYou can create your own copy of this project by running the following command:\r\n\r\n```bash\r\nnpx thirdweb create --template play-to-earn\r\n```\r\n\r\nInside the [contractAddresses](./application/const/contractAddresses.ts) file, you can change the contract addresses to your own contracts.\r\n\r\nThis project uses 4 contracts built with thirdweb:\r\n\r\n| Name      | Contract Type            | Description                    | Link                                                                                                                        |\r\n| --------- | ------------------------ | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |\r\n| Gold Gems | Token (ERC-20)           | Gold Gems Rewards Token        | [View on thirdweb dashboard](https://thirdweb.com/dashboard/mumbai/token/0x18B18e5D2375c592997e1eaFf6C77A6bd24F5c44)        |\r\n| Pickaxes  | Edition Drop (ERC-1155)  | Pickaxe NFTs                   | [View on thirdweb dashboard](https://thirdweb.com/dashboard/mumbai/edition-drop/0x9d33597aD43bE6295Fe7626baDBF72B862F71bB2) |\r\n| Miners    | Edition Drop (ERC-1155)  | Character NFTs                 | [View on thirdweb dashboard](https://thirdweb.com/dashboard/mumbai/edition-drop/0x16A131b7e5a62E8fe83f0993aAF2ECCaBF519382) |\r\n| Mining    | Custom (thirdweb deploy) | Staking and rewarding contract | [View on thirdweb dashboard](https://thirdweb.com/dashboard/mumbai/0x90E438ba4Bf62573FEC13F792F051E8c96C41636/)             |\r\n\r\nLearn how to deploy and configure these contracts using the thirdweb portal documentation:\r\n\r\n- [Edition Drop](https://portal.thirdweb.com/pre-built-contracts/edition-drop)\r\n- [Token](https://portal.thirdweb.com/pre-built-contracts/token)\r\n- [thirdweb deploy](https://portal.thirdweb.com/thirdweb-deploy)\r\n\r\n## Guide\r\n\r\nBelow, you can find an explanation of the key areas of the project and code snippets explained!\r\n\r\n### Project Structure\r\n\r\nThe project is divided into two parts:\r\n\r\n1. The [application](./application) folder contains the code for the front-end of the application.\r\n\r\n2. The [contracts](./contracts) folder contains our smart contract set up, including our [Mining](./contracts/contracts/Mining.sol) contract. We're using [Hardhat](https://hardhat.ethereum.org/) so that we can write tests or scripts to interact with the smart contracts locally.\r\n\r\n### Deploying the Mining Contract\r\n\r\nWe can deploy the `Mining` contract using [thirdweb deploy](https://portal.thirdweb.com/thirdweb-deploy)!\r\n\r\n```bash\r\n# Change to the contracts folder\r\ncd contracts\r\n\r\n# Deploy the Mining contract\r\nnpx thirdweb deploy\r\n```\r\n\r\n### Mining Contract Explained\r\n\r\nThe way that the game works is by staking a \"pickaxe\" NFT into the Mining contract.\r\n\r\nThen, the contract uses `block.timestamp` to calculate the player's reward.\r\n\r\nThe reward logic is calculated as follows:\r\n\r\n```js\r\n// blocks passed since last payout * reward multiplier * rewards per block\r\n```\r\n\r\n```solidity\r\nfunction calculateRewards(address _player)\r\n    public\r\n    view\r\n    returns (uint256 _rewards)\r\n{\r\n    // If playerLastUpdate or playerPickaxe is not set, then the player has no rewards.\r\n    if (!playerLastUpdate[_player].isData || !playerPickaxe[_player].isData) {\r\n        return 0;\r\n    }\r\n\r\n    // Calculate the time difference between now and the last time they staked/withdrew/claimed their rewards\r\n    uint256 timeDifference = block.timestamp - (playerLastUpdate[_player].value + 1);\r\n\r\n    // Calculate the rewards they are owed\r\n    uint256 rewards = timeDifference * 10_000_000_000_000 * playerPickaxe[_player].value;\r\n\r\n    // Return the rewards\r\n    return rewards;\r\n}\r\n```\r\n\r\n`rewards` uses the Token ID of the staked pickaxe NFT as the rewards multiplier.\r\n\r\nIn order to keep track of this information, we have two mappings:\r\n\r\n```solidity\r\nstruct MapValue {\r\n    bool isData;\r\n    uint256 value;\r\n}\r\n\r\nmapping (address =\u003e MapValue) public playerPickaxe;\r\n\r\nmapping (address =\u003e MapValue) public playerLastUpdate;\r\n```\r\n\r\n1. `playerPickaxe`: This mapping tracks the current pickaxe (token ID of the NFT) that the player has staked.\r\n\r\n2. `playerLastUpdate`: This mapping tracks the last time that the player was paid out their rewards.\r\n\r\nWhen the contract is created, we pass in the values of the other contracts we created:\r\n\r\n1. The Pickaxe Edition Drop contract\r\n2. The Gold Gems Token contract\r\n\r\n```solidity\r\n// Store our two other contracts here (Edition Drop and Token)\r\nDropERC1155 public immutable pickaxeNftCollection;\r\nTokenERC20 public immutable rewardsToken;\r\n\r\n// Constructor function to set the rewards token and the NFT collection addresses\r\nconstructor(DropERC1155 pickaxeContractAddress, TokenERC20 gemsContractAddress) {\r\n    pickaxeNftCollection = pickaxeContractAddress;\r\n    rewardsToken = gemsContractAddress;\r\n}\r\n```\r\n\r\nThis allows us to do things like check if the player has a specific NFT, and transfer tokens to and from the contract.\r\n\r\nNow, there are three key functions in the contract.\r\n\r\n1. Stake (send pickaxe to the contract)\r\n2. Withdraw (get pickaxe back from the contract)\r\n3. Claimed (pay out the player's rewards)\r\n\r\n**Stake**\r\n\r\n- `safeTransferFrom`'s the pickaxe the player currently has staked back to them.\r\n- `calculateRewards` and `transfer`'s the player's rewards to them.\r\n- `safeTransferFrom`'s the pickaxe they are staking from the player to the contract.\r\n- Updates the mappings accordingly.\r\n\r\n**Withdraw**\r\n\r\n- `calculateRewards` and `transfer`'s the player's rewards to them.\r\n- `safeTransferFrom`'s the pickaxe the player currently has staked back to them.\r\n- Updates the mappings accordingly.\r\n\r\n**Claim**\r\n\r\n- `calculateRewards` and `transfer`'s the player's rewards to them.\r\n- Updates the mappings accordingly.\r\n\r\n---\r\n\r\n## Application\r\n\r\nThe application interacts with all `4` of the contracts we created by using the thirdweb SDK.\r\n\r\nYou can learn more about the thirdweb SDK's here:\r\n\r\n- [React](https://portal.thirdweb.com/react)\r\n- [TypeScript](https://portal.thirdweb.com/typescript)\r\n\r\n### Connecting to Wallets\r\n\r\nTo allow users to interact with our contracts and make transactions, we need to connect to their wallets. Firstly, we wrap our application in the `ThirdwebProvider`:\r\n\r\n```tsx\r\nfunction MyApp({ Component, pageProps }: AppProps) {\r\n  return (\r\n    \u003cThirdwebProvider activeChain=\"mumbai\"\u003e\r\n      \u003cComponent {...pageProps} /\u003e\r\n    \u003c/ThirdwebProvider\u003e\r\n  );\r\n}\r\n```\r\n\r\nWhich allows us to use any of the React SDK's hooks in our application!\r\n\r\nOn the [index.tsx](./application/pages/index.tsx) page, we use [useMetamask](https://portal.thirdweb.com/react/react.usemetamask) and [useAddress](https://portal.thirdweb.com/react/react.useaddress) to connect and read to the user's wallet.\r\n\r\n```tsx\r\nconst connectWithMetamask = useMetamask();\r\nconst address = useAddress();\r\n```\r\n\r\nThe logic on the homepage is:\r\n\r\n1. Load the user's owned NFTs from the `Miners` NFT contract to see if they have a character NFT already.\r\n\r\n```tsx\r\nconst {\r\n  data: ownedNfts,\r\n  isLoading,\r\n  isError,\r\n} = useOwnedNFTs(editionDrop, address);\r\n```\r\n\r\n2. If they have a character, show them the `Play Game` button.\r\n\r\n3. If they don't have a character, show them the `Claim` button, allowing them to claim an NFT from our Edition Drop contract:\r\n\r\n```tsx\r\nexport default function MintContainer() {\r\n  const editionDrop = useEditionDrop(CHARACTER_EDITION_ADDRESS);\r\n  const { mutate: claim, isLoading } = useClaimNFT(editionDrop);\r\n  const address = useAddress();\r\n\r\n  return (\r\n    \u003cdiv className={styles.collectionContainer}\u003e\r\n      \u003ch1\u003eEdition Drop\u003c/h1\u003e\r\n      \u003cbutton\r\n        onClick={() =\u003e\r\n          claim({\r\n            quantity: 1,\r\n            to: address as string,\r\n            tokenId: 0,\r\n          })\r\n        }\r\n      \u003e\r\n        {isLoading ? \"Loading...\" : \"Claim\"}\r\n      \u003c/button\u003e\r\n    \u003c/div\u003e\r\n  );\r\n}\r\n```\r\n\r\nOnce they have claimed their character, they can play the game.\r\n\r\nThe logic of the game page is on the [play](./application/pages/play.tsx) page.\r\n\r\n### The Play Page\r\n\r\nThe role of this page is to connect to all of the contracts and pass this information down to a set of components.\r\n\r\nFirstly, we connect to all of our contracts:\r\n\r\n```tsx\r\nconst { contract: miningContract } = useContract(MINING_CONTRACT_ADDRESS);\r\nconst characterContract = useEditionDrop(CHARACTER_EDITION_ADDRESS);\r\nconst pickaxeContract = useEditionDrop(PICKAXE_EDITION_ADDRESS);\r\nconst tokenContract = useToken(GOLD_GEMS_ADDRESS);\r\n```\r\n\r\nThere are several components that show different information and pull data from the contracts.\r\n\r\n1. [CurrentGear Component](./application/components/CurrentGear.tsx) - Shows the owned character NFT and currently staked pickaxe\r\n2. [Rewards Component](./application/components/Rewards.tsx) - Shows the available rewards in the mining contract, the balance of the connected wallet, and a client-side estimation of the rewards they have earnt since they loaded the page in this session.\r\n3. [OwnedGear Component](./application/components/OwnedGear.tsx) - Shows the owned pickaxes the wallet has and an \"Equip\" button to stake it.\r\n4. [Shop Component](./application/components/Shop.tsx) - Shows all of the pickaxes in the Pickaxe Edition Drop contract, the price for each, and a \"Buy\" button to claim it.\r\n\r\n### Current Gear\r\n\r\n**Contracts Used in this Component**:\r\n\r\n- **Mining Contract** - View the currently staked pickaxe\r\n- **Character Contract** - View the metadata of the character NFT\r\n- **Pickaxe Contract** - View the metadata of the staked pickaxe token\r\n\r\nThis component simply shows the user the character NFT they own, the pickaxe they currently have staked, and an animation of the character \"mining\".\r\n\r\nIt looks like this:\r\n\r\n![Current Gear Preview](https://cdn.hashnode.com/res/hashnode/image/upload/v1655947595125/-iVRlmtNi.png)\r\n\r\nTo get the metadata of the character NFT:\r\n\r\n```tsx\r\n// Since we only have 1 character of token ID 0, it's quite easy to get the metadata.\r\nconst { data: playerNft } = useNFT(characterContract, 0);\r\n```\r\n\r\nTo get the staked pickaxe:\r\n\r\n```tsx\r\n// playerPickaxe is the name of the mapping we created in the contract.\r\n// It maps walletAddress -\u003e staked token ID.\r\nconst p = (await miningContract.call(\r\n  \"playerPickaxe\",\r\n  address\r\n)) as ContractMappingResponse;\r\n```\r\n\r\nTo get the metadata of the staked pickaxe:\r\n\r\n```tsx\r\n// Here, p.value is the token ID.\r\nconst pickaxeMetadata = await pickaxeContract.get(p.value);\r\n```\r\n\r\n### Rewards\r\n\r\n**Contracts Used in this Component**:\r\n\r\n- **Mining Contract** - View the available rewards of the connected wallet\r\n- **Token Contract** - View token metadata and balance of connected wallet\r\n\r\nThis component shows:\r\n\r\n- The metadata of the rewards token (name and image)\r\n- The balance of the connected wallet of the token\r\n- The \"unclaimed\" rewards the user can claim from the connected wallet\r\n- A client-side estimation of the rewards the user has earned since they loaded the page in this session\r\n\r\nIt looks like this:\r\n\r\n\u003cdiv align='center'\u003e\r\n\r\n![Rewards Component](https://cdn.hashnode.com/res/hashnode/image/upload/v1655947877637/6iVmVzMfd.png)\r\n\r\n\u003c/div\u003e\r\n\r\nTo get the metadata of the token:\r\n\r\n```tsx\r\nconst { data: tokenMetadata } = useMetadata(tokenContract);\r\n```\r\n\r\nTo get the balance of the connected wallet:\r\n\r\n```tsx\r\nconst address = useAddress();\r\nconst { data: currentBalance } = useTokenBalance(tokenContract, address);\r\n```\r\n\r\nTo get the \"unclaimed\" rewards:\r\n\r\n```tsx\r\nconst u = await miningContract.call(\"calculateRewards\", address);\r\n```\r\n\r\nTo claim the rewards from the contract:\r\n\r\n```tsx\r\nawait miningContract.call(\"claim\");\r\n```\r\n\r\nThere is a fun little component within this one caled [ApproxRewards](./application/components/ApproxRewards.tsx) that estimates the rewards that have been earnt during this session. \\_It's probably not that accurate, it just looks pretty cool! It:\r\n\r\n- Reads the token ID of the currently staked pickaxe\r\n- Multiplies it by the rewards amount `10_000_000_000_000`\r\n- Multiplies this amount by the amount of time that this sessino has been running\r\n\r\n### Owned Gear\r\n\r\n**Contracts Used in this Component**:\r\n\r\n- **Pickaxe Contract** - View all of the owned pickaxes from the Pickaxe Edition Drop contract\r\n- **Mining Contract** - To stake a selected pickaxe\r\n\r\nThis component shows the user the NFTs that they own from the pickaxe edition drop contract, and allows them to stake/equip them.\r\n\r\nIt looks like this:\r\n\r\n![Rewards Component](https://cdn.hashnode.com/res/hashnode/image/upload/v1655949865562/MLp4NsEew.png)\r\n\r\nTo view all of their owned pickaxes:\r\n\r\n```tsx\r\nconst address = useAddress();\r\nconst { data: ownedPickaxes, isLoading } = useOwnedNFTs(\r\n  pickaxeContract,\r\n  address\r\n);\r\n```\r\n\r\nMap / Display each using the [`ThirdwebNftMedia`](https://portal.thirdweb.com/react/react.thirdwebnftmedia) component to display the metadata:\r\n\r\n```tsx\r\nreturn (\r\n  \u003cdiv\u003e\r\n    {ownedPickaxes?.map((p) =\u003e (\r\n      \u003cdiv key={p.metadata.id.toString()}\u003e\r\n        \u003cThirdwebNftMedia metadata={p.metadata} /\u003e\r\n        \u003ch3\u003e{p.metadata.name}\u003c/h3\u003e\r\n\r\n        \u003cbutton onClick={() =\u003e equip(p.metadata.id)}\u003eEquip\u003c/button\u003e\r\n      \u003c/div\u003e\r\n    ))}\r\n  \u003c/div\u003e\r\n);\r\n```\r\n\r\nTo stake/\"equip\" a pickaxe:\r\n\r\nSince our contract attempts to transfer tokens from the wallet to the contract, we need to provide the contract approval to do so, before calling the `stake` function\r\n\r\n```tsx\r\nasync function equip(id: BigNumber) {\r\n  if (!address) return;\r\n\r\n  // The contract requires approval to be able to transfer the pickaxe\r\n  const hasApproval = await pickaxeContract.isApproved(\r\n    address,\r\n    MINING_CONTRACT_ADDRESS\r\n  );\r\n\r\n  if (!hasApproval) {\r\n    await pickaxeContract.setApprovalForAll(MINING_CONTRACT_ADDRESS, true);\r\n  }\r\n\r\n  await miningContract.call(\"stake\", id);\r\n}\r\n```\r\n\r\nAt this point, the page reloads and the user's character will start \"mining\", and earning rewards!\r\n\r\n### Shop\r\n\r\n**Contracts Used in this Component**:\r\n\r\n- **Pickaxe Contract** - View all of the pickaxes available in the Pickaxe Edition Drop contract\r\n\r\nThe shop is a component that maps over all of the NFTs inside the Pickaxe Edition Drop contract, and displays them, including a \"Buy\" button for each; allowing the user to claim the NFT for a price (in GEMs).\r\n\r\nIt looks like this:\r\n\r\n![Rewards Component](https://cdn.hashnode.com/res/hashnode/image/upload/v1655949917550/en2h7OUda.png)\r\n\r\nThe price for each pickaxe NFT is configured with the drop's [claim phases](https://portal.thirdweb.com/pre-built-contracts/edition-drop#setting-claim-phases).\r\n\r\nThe claim phases allows us to use our GEMs token as the currency for the NFT.\r\n\r\nTo display all of the pickaxes in the contract:\r\n\r\n```tsx\r\nexport default function Shop({ pickaxeContract }: Props) {\r\n  const { data: availablePickaxes } = useNFTs(pickaxeContract);\r\n\r\n  return (\r\n    \u003c\u003e\r\n      \u003cdiv className={styles.nftBoxGrid}\u003e\r\n        {availablePickaxes?.map((p) =\u003e (\r\n          \u003cShopItem\r\n            pickaxeContract={pickaxeContract}\r\n            item={p}\r\n            key={p.metadata.id.toString()}\r\n          /\u003e\r\n        ))}\r\n      \u003c/div\u003e\r\n    \u003c/\u003e\r\n  );\r\n}\r\n```\r\n\r\nSince the price information is inside the claim phases, we map them out into a `ShopItem` component, which fetches the claim phase information for each item:\r\n\r\n```tsx\r\nconst { data: claimCondition } = useActiveClaimCondition(\r\n  pickaxeContract,\r\n  item.metadata.id\r\n);\r\n```\r\n\r\nTo claim a pickaxe NFT:\r\n\r\n```tsx\r\nconst { mutate: claimNft } = useClaimNFT(pickaxeContract);\r\n```\r\n\r\n```tsx\r\nasync function buy(id: BigNumber) {\r\n  if (!address) return;\r\n\r\n  try {\r\n    claimNft({\r\n      to: address,\r\n      tokenId: id,\r\n      quantity: 1,\r\n    });\r\n  } catch (e) {\r\n    console.error(e);\r\n    alert(\"Something went wrong. Are you sure you have enough tokens?\");\r\n  }\r\n}\r\n```\r\n\r\n### Art Creators\r\n\r\n_The art used in this project is used under the CC-0 license._\r\n\r\nThat said, we want to credit the awesome artists for their work:\r\n\r\n- Pirate Bomb by pixelfrog: https://pixelfrog-assets.itch.io/pirate-bomb\r\n- RPG Item Pack by alexs-assets: https://alexs-assets.itch.io/16x16-rpg-item-pack-2\r\n- Gold Gem by Davit Masia - https://kronbits.itch.io/matriax-free-assets\r\n\r\n## Join our Discord!\r\n\r\nFor any questions, suggestions, join our discord at [https://discord.gg/thirdweb](https://discord.gg/thirdweb).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fplay-to-earn-game","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthirdweb-example%2Fplay-to-earn-game","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fplay-to-earn-game/lists"}