Build an NFT Based Ticketing System

بواسطة: egghead.io

Overview

Links to code:
React UI Starter Repo
Solidity Base64 Utilities
Final Smart Contract
NFTs, non-fungible tokens, have taken the online world by storm ushering in the proclamation of a new world-wide web... web3.
For most, NFTs mean profile pictures (pfps).
This isn't the most practical use case, even if it is a lot of fun
Even if you wanted to create useful NFTs, it’s not easy to get started.
Since the tooling is still being developed, it can be confusing as to where to get started. It also doesn't help that there's a paradigm shift with app development from web2 to web3.
Here be dragons
This course is here to get you through that initial learning curve and frustrating lack of answered questions and good documentation.
You will be building a ticketing and proof-of-attendance service complete with wallet QR code scanning. Very useful indeed!
This course is here to get you through that initial learning curve and frustrating lack of answered questions and good documentation.
You will be building a ticketing and proof-of-attendance service complete with wallet QR code scanning. Very useful indeed!
Through building this project you will learn the general development lifecycle of NFT smart contracts and dApps giving you the skills to start your own projects.
By the end of this course, you will be able to do the following
Use the OpenZeppelin Solidity library to create NFT smart-contracts
Deploy smart contracts to Ethereum testnets
Host static assets on IFPS
Create a React dApp that interacts with your smart-contract API
Confirm a wallet owns an NFT

Syllabus

  • Create a New NFT Project with scaffold-eth
  • Deploy a Smart Contract to Localhost with scaffold-eth
  • Create an ERC-721 Token with OpenZeppelin
  • Add a Mint Function to Your NFT Smart Contract
  • Add an Image to an NFT with Token Metadata
  • Set a Mint Price on Your NFT Smart Contract
  • Restrict Smart Contract Functions to a Specified Owner
  • Deploy a Smart Contract to the Rinkeby Testnet
  • Set Up a React dApp From a Starter
  • Support MetaMask Connections to a React dApp
  • Disconnect MetaMask from a React dApp
  • Cache a MetaMask Wallet Address in localStorage
  • Connect a React dApp to a Smart Contract Using ethers.js
  • Fetch the Owner's Wallet Address From a Smart Contract
  • Open and Close an NFT Sale From a React dApp
  • Fetch Mint Info From a Smart Contract
  • Mint an NFT from a React dApp
  • Scan an Ethereum Wallet's QR Code
  • Confirm a Wallet Owns an NFT in a Smart Contract
  • Upload Static Assets to IPFS with Pinata
  • Update an NFT’s Image and Other Metadata
  • Display a User's NFTs Using the OpenSea API

Taught by

Ryan Harris

Build an NFT Based Ticketing System
الذهاب الي الدورة

Build an NFT Based Ticketing System

بواسطة: egghead.io

  • egghead.io
  • مدفوعة
  • الإنجليزية
  • متاح شهادة
  • متاح في أي وقت
  • الجميع
  • N/A
8.1.2PHP Version344msRequest Duration2MBMemory UsageGET ar/الدورات/{slug}Route
    • Booting (212ms)
    • Application (131ms)
    • 1 x Booting (61.64%)
      212.02ms
      1 x Application (38.13%)
      131.15ms
      14 templates were rendered
      • public.courses.show (resources/views/public/courses/show.blade.php)3bladefile
        Params
        0
        course
        1
        links
        2
        config
      • public.courses.partials.breadcrumbs (resources/views/public/courses/partials/breadcrumbs.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.courses.partials.heading (resources/views/public/courses/partials/heading.blade.php)7bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
        6
        classes
      • public.courses.partials.details (resources/views/public/courses/partials/details.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.courses.partials.breadcrumbs (resources/views/public/courses/partials/breadcrumbs.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.courses.partials.heading (resources/views/public/courses/partials/heading.blade.php)7bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
        6
        classes
      • public.layouts.main (resources/views/public/layouts/main.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.layouts.partials.meta (resources/views/public/layouts/partials/meta.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.layouts.partials.navbar (resources/views/public/layouts/partials/navbar.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.auth.profile.partials.links (resources/views/public/auth/profile/partials/links.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      • public.auth.profile.partials.link (resources/views/public/auth/profile/partials/link.blade.php)8bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
        6
        route
        7
        title
      • public.auth.profile.partials.link (resources/views/public/auth/profile/partials/link.blade.php)8bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
        6
        route
        7
        title
      • public.auth.profile.partials.link (resources/views/public/auth/profile/partials/link.blade.php)8bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
        6
        route
        7
        title
      • public.layouts.partials.flash-session (resources/views/public/layouts/partials/flash-session.blade.php)6bladefile
        Params
        0
        __env
        1
        app
        2
        errors
        3
        course
        4
        links
        5
        config
      uri
      GET ar/الدورات/{slug}
      middleware
      web, localize:ar
      controller
      App\Http\Controllers\CourseController@show
      as
      ar.courses.show
      namespace
      prefix
      /ar
      where
      file
      app/Http/Controllers/CourseController.php:17-35
      6 statements were executed7.61ms
      • select * from `courses` where `slug_ar` = 'build-an-nft-based-ticketing-system' limit 1
        6.42ms/app/Http/Controllers/CourseController.php:20corspedia
        Metadata
        Bindings
        • 0. build-an-nft-based-ticketing-system
        Backtrace
        • 17. /app/Http/Controllers/CourseController.php:20
        • 18. /vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
        • 19. /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
        • 20. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
        • 21. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
      • update `courses` set `visitors` = `visitors` + 1, `courses`.`updated_at` = '2025-06-05 15:37:44' where `id` = 2124
        510μs/app/Http/Controllers/CourseController.php:21corspedia
        Metadata
        Bindings
        • 0. 2025-06-05 15:37:44
        • 1. 2124
        Backtrace
        • 17. /app/Http/Controllers/CourseController.php:21
        • 18. /vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
        • 19. /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
        • 20. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
        • 21. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
      • select `id`, `name_en`, `name_ar`, `topic_id`, `slug_en`, `slug_ar` from `subjects` where `subjects`.`id` in (93)
        170μs/app/Http/Controllers/CourseController.php:23corspedia
        Metadata
        Backtrace
        • 20. /app/Http/Controllers/CourseController.php:23
        • 21. /vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
        • 22. /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
        • 23. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
        • 24. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
      • select `id`, `name_en`, `name_ar`, `slug_en`, `slug_ar` from `topics` where `topics`.`id` in (1)
        140μs/app/Http/Controllers/CourseController.php:23corspedia
        Metadata
        Backtrace
        • 25. /app/Http/Controllers/CourseController.php:23
        • 26. /vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
        • 27. /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
        • 28. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
        • 29. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
      • select * from `providers` where `providers`.`id` in (29) and `providers`.`deleted_at` is null
        170μs/app/Http/Controllers/CourseController.php:23corspedia
        Metadata
        Backtrace
        • 20. /app/Http/Controllers/CourseController.php:23
        • 21. /vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
        • 22. /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
        • 23. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
        • 24. /vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
      • select * from `html_files` where `html_files`.`id` = 2115 limit 1
        200μs/app/Models/Course.php:84corspedia
        Metadata
        Bindings
        • 0. 2115
        Backtrace
        • 21. /app/Models/Course.php:84
        • 28. view::public.courses.show:29
        • 30. /vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:125
        • 31. /vendor/laravel/framework/src/Illuminate/View/Engines/PhpEngine.php:58
        • 32. /vendor/laravel/framework/src/Illuminate/View/Engines/CompilerEngine.php:72
      App\Models\HtmlFile
      1
      App\Models\Provider
      1
      App\Models\Topic
      1
      App\Models\Subject
      1
      App\Models\Course
      1
        _token
        QzhpHCDY6Gp5zRPlJ7uxn7xgz3qVChy20Co9EnDK
        locale
        ar
        _previous
        array:1 [ "url" => "https://www.corspedia.com/ar/%D8%A7%D9%84%D8%AF%D9%88%D8%B1%D8%A7%D8%AA/build-...
        _flash
        array:2 [ "old" => [] "new" => [] ]
        PHPDEBUGBAR_STACK_DATA
        []
        path_info
        /ar/%D8%A7%D9%84%D8%AF%D9%88%D8%B1%D8%A7%D8%AA/build-an-nft-based-ticketing-system
        status_code
        200
        
        status_text
        OK
        format
        html
        content_type
        text/html; charset=UTF-8
        request_query
        []
        
        request_request
        []
        
        request_headers
        0 of 0
        array:24 [ "cf-ipcountry" => array:1 [ 0 => "US" ] "cf-connecting-ip" => array:1 [ 0 => "3.135.206.145" ] "cdn-loop" => array:1 [ 0 => "cloudflare; loops=1" ] "x-forwarded-proto" => array:1 [ 0 => "https" ] "x-forwarded-for" => array:1 [ 0 => "3.135.206.145" ] "sec-fetch-site" => array:1 [ 0 => "none" ] "accept" => array:1 [ 0 => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7" ] "user-agent" => array:1 [ 0 => "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)" ] "upgrade-insecure-requests" => array:1 [ 0 => "1" ] "sec-ch-ua-platform" => array:1 [ 0 => ""Windows"" ] "sec-ch-ua-mobile" => array:1 [ 0 => "?0" ] "sec-ch-ua" => array:1 [ 0 => ""Chromium";v="130", "HeadlessChrome";v="130", "Not?A_Brand";v="99"" ] "cache-control" => array:1 [ 0 => "no-cache" ] "pragma" => array:1 [ 0 => "no-cache" ] "sec-fetch-dest" => array:1 [ 0 => "document" ] "cf-ray" => array:1 [ 0 => "94b0c0c07ae2e259-ORD" ] "accept-encoding" => array:1 [ 0 => "gzip, br" ] "priority" => array:1 [ 0 => "u=0, i" ] "sec-fetch-user" => array:1 [ 0 => "?1" ] "sec-fetch-mode" => array:1 [ 0 => "navigate" ] "cf-visitor" => array:1 [ 0 => "{"scheme":"https"}" ] "host" => array:1 [ 0 => "www.corspedia.com" ] "content-length" => array:1 [ 0 => "" ] "content-type" => array:1 [ 0 => "" ] ]
        request_server
        0 of 0
        array:50 [ "USER" => "www-data" "HOME" => "/var/www" "HTTP_CF_IPCOUNTRY" => "US" "HTTP_CF_CONNECTING_IP" => "3.135.206.145" "HTTP_CDN_LOOP" => "cloudflare; loops=1" "HTTP_X_FORWARDED_PROTO" => "https" "HTTP_X_FORWARDED_FOR" => "3.135.206.145" "HTTP_SEC_FETCH_SITE" => "none" "HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7" "HTTP_USER_AGENT" => "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)" "HTTP_UPGRADE_INSECURE_REQUESTS" => "1" "HTTP_SEC_CH_UA_PLATFORM" => ""Windows"" "HTTP_SEC_CH_UA_MOBILE" => "?0" "HTTP_SEC_CH_UA" => ""Chromium";v="130", "HeadlessChrome";v="130", "Not?A_Brand";v="99"" "HTTP_CACHE_CONTROL" => "no-cache" "HTTP_PRAGMA" => "no-cache" "HTTP_SEC_FETCH_DEST" => "document" "HTTP_CF_RAY" => "94b0c0c07ae2e259-ORD" "HTTP_ACCEPT_ENCODING" => "gzip, br" "HTTP_PRIORITY" => "u=0, i" "HTTP_SEC_FETCH_USER" => "?1" "HTTP_SEC_FETCH_MODE" => "navigate" "HTTP_CF_VISITOR" => "{"scheme":"https"}" "HTTP_HOST" => "www.corspedia.com" "REDIRECT_STATUS" => "200" "SERVER_NAME" => "corspedia.com" "SERVER_PORT" => "443" "SERVER_ADDR" => "141.95.147.152" "REMOTE_USER" => "" "REMOTE_PORT" => "30722" "REMOTE_ADDR" => "172.70.100.159" "SERVER_SOFTWARE" => "nginx/1.18.0" "GATEWAY_INTERFACE" => "CGI/1.1" "HTTPS" => "on" "REQUEST_SCHEME" => "https" "SERVER_PROTOCOL" => "HTTP/2.0" "DOCUMENT_ROOT" => "/var/www/corspedia/public" "DOCUMENT_URI" => "/index.php" "REQUEST_URI" => "/ar/%D8%A7%D9%84%D8%AF%D9%88%D8%B1%D8%A7%D8%AA/build-an-nft-based-ticketing-system" "SCRIPT_NAME" => "/index.php" "CONTENT_LENGTH" => "" "CONTENT_TYPE" => "" "REQUEST_METHOD" => "GET" "QUERY_STRING" => "" "SCRIPT_FILENAME" => "/var/www/corspedia/public/index.php" "PATH_INFO" => "" "FCGI_ROLE" => "RESPONDER" "PHP_SELF" => "/index.php" "REQUEST_TIME_FLOAT" => 1749137864.0229 "REQUEST_TIME" => 1749137864 ]
        request_cookies
        []
        
        response_headers
        0 of 0
        array:5 [ "content-type" => array:1 [ 0 => "text/html; charset=UTF-8" ] "cache-control" => array:1 [ 0 => "no-cache, private" ] "date" => array:1 [ 0 => "Thu, 05 Jun 2025 15:37:44 GMT" ] "set-cookie" => array:2 [ 0 => "XSRF-TOKEN=eyJpdiI6ImtoLzNBRFFMYklMQ1JpWEV1MjZIS0E9PSIsInZhbHVlIjoidWNrRmMzMCtBTTE1WGZ0YS8zMFI2Q1Rza09WamV2Yy9FbmJwL0tScHhWWjNyR3ZjdDY5SmRFaWdaaWlLUVpUTTdlR2NHMDZZenNMZEovUmdXSy8vbWVEcTUrR2dlWWUwWTVTMU80UXZna0FMYnJvSnJLZjcyR1BZU0N2T1dWekgiLCJtYWMiOiIwMDMyYTFiM2FmZDA3ZjU3ZGM0ODA0MTA3YzE4ODY1NDY1ZTI2OTdlZmNhMmFjMWNiMTFhZDE4ZWJjM2NhZThhIiwidGFnIjoiIn0%3D; expires=Thu, 05 Jun 2025 17:37:44 GMT; Max-Age=7200; path=/; samesite=laxXSRF-TOKEN=eyJpdiI6ImtoLzNBRFFMYklMQ1JpWEV1MjZIS0E9PSIsInZhbHVlIjoidWNrRmMzMCtBTTE1WGZ0YS8zMFI2Q1Rza09WamV2Yy9FbmJwL0tScHhWWjNyR3ZjdDY5SmRFaWdaaWlLUVpUTTdlR2NHM" 1 => "laravel_session=eyJpdiI6InhkK1Z6Umd3Y0dwM3JzU1MyTkNXcXc9PSIsInZhbHVlIjoieHI2OVV0Z1RPc3h0SXdORExnZmdCcnpaSGYwS0l3emhyWkl2NWlzcjc0cHdmOCtqTGJUWkpUY0NnaStsU0xOT2VXYWZ6RGZ0ZlJUckhCbE1OWWhUN1pUc0xtaWlFZGNQMzErbmp0L0kzUnJuUjZuK2NOSUNFU0NLbVc0MXUyTEEiLCJtYWMiOiIxOGY4MzU0ZmI5ZjZmMTY3NTQyYTAyN2U0YjRhMzhkNDk0ODMzZGM3OGRlMGYxNzY3ZWNmYjNhN2IxMGYyYjc3IiwidGFnIjoiIn0%3D; expires=Thu, 05 Jun 2025 17:37:44 GMT; Max-Age=7200; path=/; httponly; samesite=laxlaravel_session=eyJpdiI6InhkK1Z6Umd3Y0dwM3JzU1MyTkNXcXc9PSIsInZhbHVlIjoieHI2OVV0Z1RPc3h0SXdORExnZmdCcnpaSGYwS0l3emhyWkl2NWlzcjc0cHdmOCtqTGJUWkpUY0NnaStsU0xOT2VX" ] "Set-Cookie" => array:2 [ 0 => "XSRF-TOKEN=eyJpdiI6ImtoLzNBRFFMYklMQ1JpWEV1MjZIS0E9PSIsInZhbHVlIjoidWNrRmMzMCtBTTE1WGZ0YS8zMFI2Q1Rza09WamV2Yy9FbmJwL0tScHhWWjNyR3ZjdDY5SmRFaWdaaWlLUVpUTTdlR2NHMDZZenNMZEovUmdXSy8vbWVEcTUrR2dlWWUwWTVTMU80UXZna0FMYnJvSnJLZjcyR1BZU0N2T1dWekgiLCJtYWMiOiIwMDMyYTFiM2FmZDA3ZjU3ZGM0ODA0MTA3YzE4ODY1NDY1ZTI2OTdlZmNhMmFjMWNiMTFhZDE4ZWJjM2NhZThhIiwidGFnIjoiIn0%3D; expires=Thu, 05-Jun-2025 17:37:44 GMT; path=/XSRF-TOKEN=eyJpdiI6ImtoLzNBRFFMYklMQ1JpWEV1MjZIS0E9PSIsInZhbHVlIjoidWNrRmMzMCtBTTE1WGZ0YS8zMFI2Q1Rza09WamV2Yy9FbmJwL0tScHhWWjNyR3ZjdDY5SmRFaWdaaWlLUVpUTTdlR2NHM" 1 => "laravel_session=eyJpdiI6InhkK1Z6Umd3Y0dwM3JzU1MyTkNXcXc9PSIsInZhbHVlIjoieHI2OVV0Z1RPc3h0SXdORExnZmdCcnpaSGYwS0l3emhyWkl2NWlzcjc0cHdmOCtqTGJUWkpUY0NnaStsU0xOT2VXYWZ6RGZ0ZlJUckhCbE1OWWhUN1pUc0xtaWlFZGNQMzErbmp0L0kzUnJuUjZuK2NOSUNFU0NLbVc0MXUyTEEiLCJtYWMiOiIxOGY4MzU0ZmI5ZjZmMTY3NTQyYTAyN2U0YjRhMzhkNDk0ODMzZGM3OGRlMGYxNzY3ZWNmYjNhN2IxMGYyYjc3IiwidGFnIjoiIn0%3D; expires=Thu, 05-Jun-2025 17:37:44 GMT; path=/; httponlylaravel_session=eyJpdiI6InhkK1Z6Umd3Y0dwM3JzU1MyTkNXcXc9PSIsInZhbHVlIjoieHI2OVV0Z1RPc3h0SXdORExnZmdCcnpaSGYwS0l3emhyWkl2NWlzcjc0cHdmOCtqTGJUWkpUY0NnaStsU0xOT2VX" ] ]
        session_attributes
        0 of 0
        array:5 [ "_token" => "QzhpHCDY6Gp5zRPlJ7uxn7xgz3qVChy20Co9EnDK" "locale" => "ar" "_previous" => array:1 [ "url" => "https://www.corspedia.com/ar/%D8%A7%D9%84%D8%AF%D9%88%D8%B1%D8%A7%D8%AA/build-an-nft-based-ticketing-system" ] "_flash" => array:2 [ "old" => [] "new" => [] ] "PHPDEBUGBAR_STACK_DATA" => [] ]