diff --git a/typescript/dynamic-pricing/.eslintrc.json b/typescript/dynamic-pricing/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/typescript/dynamic-pricing/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/typescript/dynamic-pricing/.gitignore b/typescript/dynamic-pricing/.gitignore new file mode 100644 index 0000000..16dad0e --- /dev/null +++ b/typescript/dynamic-pricing/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo \ No newline at end of file diff --git a/typescript/dynamic-pricing/LICENSE.md b/typescript/dynamic-pricing/LICENSE.md new file mode 100644 index 0000000..88e8b41 --- /dev/null +++ b/typescript/dynamic-pricing/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2021 Non-Fungible Labs, Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/typescript/dynamic-pricing/README.md b/typescript/dynamic-pricing/README.md new file mode 100644 index 0000000..7a78232 --- /dev/null +++ b/typescript/dynamic-pricing/README.md @@ -0,0 +1,55 @@ +## Intro +Build an app with NEXTJS: +1. App is token gated. Meaning only if you hold an access NFT are you able to access the website +2. Once you access the app you can claim an NFT. +3. Once all **access** NFTs are claimed the price of the NFT in the app goes up. + +Contracts used: +1. NFT DROP used for access NFTS +2. NFT DROP used for NFT in the app (behind the gate) + +Claim condition Logic: +1. Claim condition is adjusted when an API call is made. +2. API call checks if access NFTS equals certain amound. If yes, it makes the call to adjust the claim condition. +3. Check for access NFT is made at frontend, claim condition ajdusted is at backend. + +## Getting Started + +First, intall the required dependencies: + +```bash +npm install +# or +yarn install +``` + +Then, run the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +On `pages/_app.tsx`, you'll find our `ThirdwebProvider` wrapping your app, this is necessary for our hooks to work. + +on `pages/index.tsx`, you'll find the `useMetamask` hook that we use to connect the user's wallet to MetaMask, `useDisconnect` that we use to disconnect it, and `useAddress` to check the user's wallet address once connected. + +## Learn More + +To learn more about thirdweb and Next.js, take a look at the following resources: + +- [thirdweb React Documentation](https://docs.thirdweb.com/react) - learn about our React SDK. +- [thirdweb TypeScript Documentation](https://docs.thirdweb.com/react) - learn about our JavaScript/TypeScript SDK. +- [thirdweb Portal](https://docs.thirdweb.com/react) - check our guides and development resources. +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. + +You can check out [the thirdweb GitHub organization](https://github.com/thirdweb-dev) - your feedback and contributions are welcome! + +## Join our Discord! + +For any questions, suggestions, join our discord at [https://discord.gg/thirdweb](https://discord.gg/thirdweb). \ No newline at end of file diff --git a/typescript/dynamic-pricing/next-env.d.ts b/typescript/dynamic-pricing/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/typescript/dynamic-pricing/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/typescript/dynamic-pricing/next.config.js b/typescript/dynamic-pricing/next.config.js new file mode 100644 index 0000000..a843cbe --- /dev/null +++ b/typescript/dynamic-pricing/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig diff --git a/typescript/dynamic-pricing/package.json b/typescript/dynamic-pricing/package.json new file mode 100644 index 0000000..93ae99a --- /dev/null +++ b/typescript/dynamic-pricing/package.json @@ -0,0 +1,26 @@ +{ + "name": "dynamic-pricing", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@thirdweb-dev/react": "^2.0.4", + "@thirdweb-dev/sdk": "^2.0.28", + "ethers": "^5.6.2", + "next": "12.1.0", + "react": "17.0.2", + "react-dom": "17.0.2" + }, + "devDependencies": { + "@types/node": "17.0.21", + "@types/react": "17.0.40", + "eslint": "8.11.0", + "eslint-config-next": "12.1.0", + "typescript": "4.6.2" + } +} diff --git a/typescript/dynamic-pricing/pages/_app.tsx b/typescript/dynamic-pricing/pages/_app.tsx new file mode 100644 index 0000000..f939aac --- /dev/null +++ b/typescript/dynamic-pricing/pages/_app.tsx @@ -0,0 +1,16 @@ +import type { AppProps } from 'next/app'; +import { ChainId, ThirdwebProvider } from '@thirdweb-dev/react'; +import '../styles/globals.css' + +// This is the chainId your dApp will work on. +const activeChainId = ChainId.Rinkeby; + +function MyApp({ Component, pageProps }: AppProps) { + return ( + + + + ); +} + +export default MyApp; diff --git a/typescript/dynamic-pricing/pages/api/update-pricing.tsx b/typescript/dynamic-pricing/pages/api/update-pricing.tsx new file mode 100644 index 0000000..05dced8 --- /dev/null +++ b/typescript/dynamic-pricing/pages/api/update-pricing.tsx @@ -0,0 +1,66 @@ +import { ClaimCondition, ThirdwebSDK } from '@thirdweb-dev/sdk'; +import { ethers } from 'ethers'; +import { NextApiRequest, NextApiResponse } from 'next'; + +// This depend on your HTTP Server setup. In this example, we're using next.js +// api handlers. +export default async function updatePricing( + req: NextApiRequest, + res: NextApiResponse, +) { + // the RPC URL to the blockchain that the nftDrop contract is deployed on. + // "rinkeby" = rinkeby testnet, + // "https://rpc-mumbai.maticvigil.com" = mumbai testnet. + const rpcUrl = + 'https://rinkeby.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161'; + const privateKey = process.env.PRIVATE_KEY as string; + // setup a wallet using private key for the SDK. + // the wallet must have MINTER role to mint the nftDrop. + // you can assign MINTER role to the wallet through the nftDrop collection dashboard. + const wallet = new ethers.Wallet( + privateKey, + ethers.getDefaultProvider(rpcUrl), + ); + + // initialize the SDK and get the nftDrop contract + // get the contract address (0x...) from your dashboard! + const nftDrop = new ThirdwebSDK(wallet).getNFTDrop( + '0x82747Bd4e435C9D5cF2342c8361B19910259C264', + ); + + try { + // Check if the current claim phase is the second claim phase + const claimConditions = await nftDrop.claimConditions.getAll(); + const activeClaimPhase = await nftDrop.claimConditions.getActive(); + const isSecondClaimPhase = + claimConditions[1].currencyMetadata.displayValue === + activeClaimPhase.currencyMetadata.displayValue; + + if (isSecondClaimPhase) { + res.status(200).json({ message: 'Nothing to update! Claim condition is already the right one.' }); + } + + // Check if the current number of NFTs minted has reached the limit + const totalClaimedSupply = await nftDrop?.totalClaimedSupply(); + const maxQuantity = claimConditions[0].maxQuantity; + const canChangeCondition = totalClaimedSupply.eq(maxQuantity); + + if (!canChangeCondition) { + res.status(200).json({ message: "Nothing to update! We haven't reached the limit to update yet." }); + } + } catch (error) { + console.log(error); + res.status(500).json({ message: 'Error getting data' }); + } + + try { + await nftDrop.claimConditions.update( + 1, // index of our claim condition + { startTime: new Date() }, + ); + res.status(200).json({ message: 'Claim conditions updated successfully!' }); + } catch (error) { + console.log(error); + res.status(500).json({ message: 'Error updating claim conditions!' }); + } +} diff --git a/typescript/dynamic-pricing/pages/index.tsx b/typescript/dynamic-pricing/pages/index.tsx new file mode 100644 index 0000000..53bb117 --- /dev/null +++ b/typescript/dynamic-pricing/pages/index.tsx @@ -0,0 +1,100 @@ +import { useAddress, useDisconnect, useMetamask } from '@thirdweb-dev/react'; +import type { NextPage } from 'next'; +import styles from '../styles/styles.module.css'; +import Image from 'next/image'; +import tw from '../public/tw.png'; +import { useNFTDrop } from '@thirdweb-dev/react'; +import { useState, useEffect } from 'react'; + +const Home: NextPage = () => { + const address = useAddress(); + const connectWithMetamask = useMetamask(); + const disconnectWallet = useDisconnect(); + const nftDrop = useNFTDrop('0x82747Bd4e435C9D5cF2342c8361B19910259C264'); + const [hasClaimedNFT, setHasClaimedNFT] = useState(false); + const [isClaiming, setIsClaiming] = useState(false); + const [price, setPrice] = useState('0'); + + useEffect(() => { + if (!nftDrop) return; + + const getPrice = async () => { + try { + const claimCondition = await nftDrop.claimConditions.getActive(); + const price = claimCondition.currencyMetadata.displayValue; + setPrice(price); + } catch (error) { + console.log(error); + } + }; + getPrice(); + }, [nftDrop, hasClaimedNFT]); + + const mintNft = async () => { + try { + setIsClaiming(true); + await nftDrop?.claim(1); + setHasClaimedNFT(true); + } catch (error) { + console.log(error); + } finally { + setIsClaiming(false); + } + + try { + await fetch('/api/update-pricing'); + } catch (error) { + console.log(error); + } + }; + + if (!address) { + return ( +
+ +
+ ); + } + + return ( +
+
+
+

Welcome: {address}

+ +
+ {/* big image and title */} +
+
+ Image of the NFT +
+
+

Minting has started!

+ {/* mint NFT button */} +
+
+ {price !== "0" &&

Price is {price} ETH

} +
+ + +
+
+
+ + + +
+
+ ); +}; + +export default Home; diff --git a/typescript/dynamic-pricing/public/favicon.ico b/typescript/dynamic-pricing/public/favicon.ico new file mode 100644 index 0000000..81240f9 Binary files /dev/null and b/typescript/dynamic-pricing/public/favicon.ico differ diff --git a/typescript/dynamic-pricing/public/pok.jpg b/typescript/dynamic-pricing/public/pok.jpg new file mode 100644 index 0000000..740e848 Binary files /dev/null and b/typescript/dynamic-pricing/public/pok.jpg differ diff --git a/typescript/dynamic-pricing/public/thirdweb.svg b/typescript/dynamic-pricing/public/thirdweb.svg new file mode 100644 index 0000000..86f54ec --- /dev/null +++ b/typescript/dynamic-pricing/public/thirdweb.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/typescript/dynamic-pricing/public/tw.png b/typescript/dynamic-pricing/public/tw.png new file mode 100644 index 0000000..7c1f174 Binary files /dev/null and b/typescript/dynamic-pricing/public/tw.png differ diff --git a/typescript/dynamic-pricing/styles/globals.css b/typescript/dynamic-pricing/styles/globals.css new file mode 100644 index 0000000..9b1c39f --- /dev/null +++ b/typescript/dynamic-pricing/styles/globals.css @@ -0,0 +1,6 @@ +body { + padding: 0px; + margin: 0px; + /* background-color: black; */ + font-family: Arial, Helvetica, sans-serif; + } \ No newline at end of file diff --git a/typescript/dynamic-pricing/styles/styles.module.css b/typescript/dynamic-pricing/styles/styles.module.css new file mode 100644 index 0000000..9b2b829 --- /dev/null +++ b/typescript/dynamic-pricing/styles/styles.module.css @@ -0,0 +1,82 @@ + +.body { + margin: 0; + background-color: rgb(20, 23, 27); + min-height: 100vh; +} + +.header { + display: flex; + background-color: rgb(0, 53, 113); + justify-content: space-around; + align-items: center; + padding: 1rem 0; + color:white +} + +.wallet { + display: flex; + margin-left: auto; +} + +.hero { + display: flex; + padding: 66px 50px; + align-items: center; + justify-content: center; +} + +.imageContainer { + width: 30vw; +} + +.heroRight { + color: white; + padding-left: 90px; + text-align: center; +} + +.heroText { + font-size: 4rem; + margin-bottom: 0; +} + +.nfts { + display: flex; + flex-direction: column; + font-size: xx-large; + align-items: center; + flex-wrap: wrap; + justify-content: center; + align-items: center; + margin: 100px; +} + +.mintNft { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 20%; +} + +.mintNftButton { + text-align: center; + border: none; + outline: none; + background-color: purple; + padding: 20px; + position: relative; + border-radius: 8px; + background-color: #5086bd; + color: #fff; + font-size: 21px; + font-family: "Lato", sans-serif; + cursor: pointer; + box-shadow: rgba(0, 9, 61, 0.2) 0px 4px 8px 0px; +} + +.mintNftButton:disabled { + background-color: #ccc; + cursor: not-allowed; +} diff --git a/typescript/dynamic-pricing/tsconfig.json b/typescript/dynamic-pricing/tsconfig.json new file mode 100644 index 0000000..99710e8 --- /dev/null +++ b/typescript/dynamic-pricing/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +}