diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000000..afb24f022db --- /dev/null +++ b/package-lock.json @@ -0,0 +1,28853 @@ +{ + "name": "ethereum-org-website", + "version": "10.9.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ethereum-org-website", + "version": "10.9.0", + "license": "MIT", + "dependencies": { + "@crowdin/crowdin-api-client": "^1.25.0", + "@docsearch/react": "^3.5.2", + "@hookform/resolvers": "^3.8.0", + "@next/bundle-analyzer": "^14.2.5", + "@radix-ui/react-accordion": "^1.2.0", + "@radix-ui/react-avatar": "^1.1.2", + "@radix-ui/react-checkbox": "^1.1.1", + "@radix-ui/react-compose-refs": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-navigation-menu": "^1.2.0", + "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-portal": "^1.1.1", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-radio-group": "^1.2.0", + "@radix-ui/react-scroll-area": "^1.2.2", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-slot": "^1.2.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", + "@radix-ui/react-visually-hidden": "^1.1.0", + "@rainbow-me/rainbowkit": "^2.2.3", + "@socialgouv/matomo-next": "^1.8.0", + "@tanstack/react-query": "^5.66.7", + "@tanstack/react-table": "^8.19.3", + "@types/canvas-confetti": "^1.9.0", + "@types/three": "^0.177.0", + "@wagmi/core": "^2.17.3", + "canvas-confetti": "^1.9.3", + "chart.js": "^4.4.2", + "chartjs-plugin-datalabels": "^2.2.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", + "embla-carousel-react": "^8.6.0", + "ethereum-blockies-base64": "^1.0.2", + "framer-motion": "^10.13.0", + "gray-matter": "^4.0.3", + "howler": "^2.2.4", + "htmr": "^1.0.2", + "lodash": "^4.17.21", + "lucide-react": "^0.516.0", + "next": "^14.2.30", + "next-intl": "^3.26.3", + "next-mdx-remote": "^5.0.0", + "next-sitemap": "^4.2.3", + "next-themes": "^0.3.0", + "prism-react-renderer": "1.1.0", + "prismjs": "^1.30.0", + "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", + "react-dom": "^18.2.0", + "react-emoji-render": "^2.0.1", + "react-globe.gl": "^2.33.2", + "react-hook-form": "^7.52.1", + "react-lite-youtube-embed": "^2.4.0", + "react-select": "5.8.0", + "reading-time": "^1.5.0", + "recharts": "^2.13.3", + "remark-gfm": "^4.0.1", + "sharp": "0.32.6", + "swiper": "^11.2.8", + "tailwind-merge": "^2.3.0", + "tailwind-variants": "^0.2.1", + "tailwindcss-animate": "^1.0.7", + "three": "^0.177.0", + "usehooks-ts": "^3.1.0", + "vaul": "^1.0.0", + "viem": "^2.23.3", + "wagmi": "^2.14.11", + "yaml-loader": "^0.8.0" + }, + "devDependencies": { + "@chromatic-com/playwright": "^0.12.4", + "@chromatic-com/storybook": "1.5.0", + "@netlify/plugin-nextjs": "^5.10.0", + "@playwright/test": "^1.52.0", + "@storybook/addon-essentials": "8.6.14", + "@storybook/addon-interactions": "8.6.14", + "@storybook/addon-links": "8.6.14", + "@storybook/addon-themes": "8.6.14", + "@storybook/manager-api": "8.6.14", + "@storybook/nextjs": "^8.6.14", + "@storybook/react": "8.6.14", + "@storybook/test": "8.6.14", + "@storybook/theming": "^8.6.14", + "@svgr/webpack": "^8.1.0", + "@types/decompress": "^4.2.7", + "@types/hast": "^3.0.0", + "@types/lodash": "^4.17.17", + "@types/mdast": "^4.0.4", + "@types/node": "^20.4.2", + "@types/react": "18.2.57", + "@types/react-dom": "18.2.19", + "@types/xml2js": "^0.4.14", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", + "autoprefixer": "^10.4.19", + "chromatic": "12.0.0", + "decompress": "^4.2.1", + "dotenv": "^16.5.0", + "eslint": "^8.57.1", + "eslint-config-next": "^14.2.2", + "eslint-config-prettier": "^9", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-storybook": "0.8.0", + "eslint-plugin-unused-imports": "^3.2.0", + "husky": "^9.0.11", + "image-size": "^1.0.2", + "lint-staged": "^15.2.5", + "mdast-util-toc": "^7.0.0", + "minimist": "^1.2.8", + "plaiceholder": "^3.0.0", + "polished": "^4.2.2", + "postcss": "^8.4.39", + "prettier": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.5", + "raw-loader": "^4.0.2", + "rehype-slug": "^6.0.0", + "remark-heading-id": "^1.0.1", + "storybook": "8.6.14", + "storybook-next-intl": "^1.2.5", + "tailwindcss": "^3.4.4", + "ts-node": "^10.9.1", + "tsconfig-paths-webpack-plugin": "4.1.0", + "typescript": "^5.5.2", + "unified": "^10.0.0", + "unist-util-visit": "^5.0.0", + "xml2js": "^0.6.2" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", + "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", + "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==", + "license": "MIT" + }, + "node_modules/@algolia/abtesting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz", + "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", + "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", + "@algolia/autocomplete-shared": "1.17.9" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", + "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.9" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", + "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.9" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", + "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz", + "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz", + "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz", + "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz", + "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz", + "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz", + "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz", + "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz", + "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz", + "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz", + "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz", + "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz", + "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz", + "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", + "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", + "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", + "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz", + "integrity": "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.0.tgz", + "integrity": "sha512-dGopk9nZrtCs2+nfIem25UuHyt5moSJamArzIoh9/vezUQPmYDOzjaHDCkAzuGJibCIkPup8rMT2+wYB6S73cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.0.tgz", + "integrity": "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.28.0", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.0", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", + "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base-org/account": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@base-org/account/-/account-1.1.1.tgz", + "integrity": "sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==", + "license": "Apache-2.0", + "dependencies": { + "@noble/hashes": "1.4.0", + "clsx": "1.2.1", + "eventemitter3": "5.0.1", + "idb-keyval": "6.2.1", + "ox": "0.6.9", + "preact": "10.24.2", + "viem": "^2.31.7", + "zustand": "5.0.3" + } + }, + "node_modules/@base-org/account/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@base-org/account/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@base-org/account/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@base-org/account/node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@base-org/account/node_modules/preact": { + "version": "10.24.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz", + "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@base-org/account/node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/@chromatic-com/playwright": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@chromatic-com/playwright/-/playwright-0.12.5.tgz", + "integrity": "sha512-KTPunElGUUEu1ks+G41pJB/WXf+1HeYBnvauvDpJfMlICKoZlL3in0gIUoER/La/zXC/YEKL4BeXvq/JnRQvUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chromaui/rrweb-snapshot": "2.0.0-alpha.18-noAbsolute", + "@segment/analytics-node": "^1.1.0", + "@storybook/addon-essentials": "~8.5.8", + "@storybook/csf": "^0.1.0", + "@storybook/manager-api": "~8.5.8", + "@storybook/server-webpack5": "~8.5.8", + "storybook": "~8.5.8", + "ts-dedent": "^2.2.0" + }, + "bin": { + "archive-storybook": "dist/bin/archive-storybook.js", + "build-archive-storybook": "dist/bin/build-archive-storybook.js" + }, + "peerDependencies": { + "@playwright/test": "^1.0.0" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-actions": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.5.8.tgz", + "integrity": "sha512-7J0NAz+WDw1NmvmKIh0Qr5cxgVRDPFC5fmngbDNxedk147TkwrgmqOypgEi/SAksHbTWxJclbimoqdcsNtWffA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-backgrounds": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.5.8.tgz", + "integrity": "sha512-TsQFagQ95+d7H3/+qUZKI2B0SEK8iu6CV13cyry9Dm59nn2bBylFrwx4I3xDQUOWMiSF6QIRjCYzxKQ/jJ5OEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-controls": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.5.8.tgz", + "integrity": "sha512-3iifI8mBGPsiPmV9eAYk+tK9i+xuWhVsa+sXz01xTZ/0yoOREpp972hka86mtCqdDTOJIpzh1LmxvB218OssvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "dequal": "^2.0.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-docs": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.5.8.tgz", + "integrity": "sha512-zKVUqE0UGiq1gZtY2TX57SYB4RIsdlbTDxKW2JZ9HhZGLvZ5Qb7AvdiKTZxfOepGhuw3UcNXH/zCFkFCTJifMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.5.8", + "@storybook/csf-plugin": "8.5.8", + "@storybook/react-dom-shim": "8.5.8", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-essentials": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.5.8.tgz", + "integrity": "sha512-sCNvMZqL6dywnyHuZBrWl4f6QXsvpJHOioL3wJJKaaRMZmctbFmS0u6J8TQjmgZhQfyRzuJuhr1gJg9oeqp6AA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/addon-actions": "8.5.8", + "@storybook/addon-backgrounds": "8.5.8", + "@storybook/addon-controls": "8.5.8", + "@storybook/addon-docs": "8.5.8", + "@storybook/addon-highlight": "8.5.8", + "@storybook/addon-measure": "8.5.8", + "@storybook/addon-outline": "8.5.8", + "@storybook/addon-toolbars": "8.5.8", + "@storybook/addon-viewport": "8.5.8", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-highlight": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.5.8.tgz", + "integrity": "sha512-kkldtFrY0oQJY/vfNLkV66hVgtp66OO8T68KoZFsmUz4a3iYgzDS8WF+Av2/9jthktFvMchjFr8NKOno9YBGIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-measure": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.5.8.tgz", + "integrity": "sha512-xf84ByTRkFPoNSck6Z5OJ0kXTYAYgmg/0Ke0eCY/CNgwh7lfjYQBrcjuKiYZ6jyRUMLdysXzIfF9/2MeFqLfIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-outline": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.5.8.tgz", + "integrity": "sha512-NAC9VWZFg2gwvduzJRVAtxPeQfJjB8xfDDgcGjgLOCSQkZDDOmGVdLXf78pykMQKyuu/0YZ989KufAac6kRG5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-toolbars": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.5.8.tgz", + "integrity": "sha512-AfGdMNBp+vOjyiFKlOyUFLIU0kN1QF4PhVBqd0vYkWAk2w9n6a/ZlG0TcJGe7K5+bcvmZDAerYMKbDMSeg9bAw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/addon-viewport": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.5.8.tgz", + "integrity": "sha512-SdoRb4bH99Knj2R+rTcMQQxHrtcIO1GLzTFitAefxBE1OUkq8FNLHMHd0Ip/sCQGLW/5F03U70R2uh7SkhBBYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/blocks": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.5.8.tgz", + "integrity": "sha512-O6tJDJM83fDm3ZP1+lTf24l7HOTzSRXkkMDD7zB/JHixzlj9p6wI4UQc2lplLadDCa5ya1IwyE7zUDN/0UfC5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "0.1.12", + "@storybook/icons": "^1.2.12", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^8.5.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/core": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.5.8.tgz", + "integrity": "sha512-OT02DQhkGpBgn5P+nZOZmbzxqubC4liVqbhpjp/HOGi5cOA3+fCJzDJeSDTu+pPh7dZnopC4XnR+5dWjtOJHdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "0.1.12", + "better-opn": "^3.0.2", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "esbuild-register": "^3.5.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "process": "^0.11.10", + "recast": "^0.23.5", + "semver": "^7.6.2", + "util": "^0.12.5", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/csf": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.12.tgz", + "integrity": "sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/csf-plugin": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.5.8.tgz", + "integrity": "sha512-9p+TFutbvtPYEmg14UsvqBDWKP/p/+OkIdi+gkwCMw0yiJF/+7ErMHDB0vr5SpJpU7SFQmfpY2c/LaglEtaniw==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/manager-api": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.5.8.tgz", + "integrity": "sha512-ik3yikvYxAJMDFg0s3Pm7hZWucAlkFaaO7e2RlfOctaJFdaEi3evR4RS7GdmS38uKBEk31RC7x+nnIJkqEC59A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/@storybook/react-dom-shim": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.5.8.tgz", + "integrity": "sha512-UT/kGJHPW+HLNCTmI1rV1to+dUZuXKUTaRv2wZ2BUq2/gjIuePyqQZYVQeb0LkZbuH2uviLrPfXpS5d3/RSUJw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.5.8" + } + }, + "node_modules/@chromatic-com/playwright/node_modules/storybook": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.5.8.tgz", + "integrity": "sha512-k3QDa7z4a656oO3Mx929KNm+xIdEI2nIDCKatVl1mA6vt+ge+uwoiG+ro182J9LOEppR5XXD2mQQi4u1xNsy6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core": "8.5.8" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@chromatic-com/storybook": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.5.0.tgz", + "integrity": "sha512-LkLKv7SWu/6kGep1ft2HA1T/cm14wU0zoW71gE4cZRcgUoRQJtyhITFTLHrjqAxz6bVqNgqzQtd5oBZ2nK3L3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chromatic": "^11.4.0", + "filesize": "^10.0.12", + "jsonfile": "^6.1.0", + "react-confetti": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0", + "yarn": ">=1.22.18" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/chromatic": { + "version": "11.29.0", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.29.0.tgz", + "integrity": "sha512-yisBlntp9hHVj19lIQdpTlcYIXuU9H/DbFuu6tyWHmj6hWT2EtukCCcxYXL78XdQt1vm2GfIrtgtKpj/Rzmo4A==", + "dev": true, + "license": "MIT", + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "peerDependencies": { + "@chromatic-com/cypress": "^0.*.* || ^1.0.0", + "@chromatic-com/playwright": "^0.*.* || ^1.0.0" + }, + "peerDependenciesMeta": { + "@chromatic-com/cypress": { + "optional": true + }, + "@chromatic-com/playwright": { + "optional": true + } + } + }, + "node_modules/@chromaui/rrweb-snapshot": { + "version": "2.0.0-alpha.18-noAbsolute", + "resolved": "https://registry.npmjs.org/@chromaui/rrweb-snapshot/-/rrweb-snapshot-2.0.0-alpha.18-noAbsolute.tgz", + "integrity": "sha512-glB+dgHTLLiDS8ljwYDBb2EPNe/sPxz2uOWjm11PoDYmVw204VKzyq07jredeHs9nUocb47RyDcZWCa5Cbw3yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss": "^8.4.38" + } + }, + "node_modules/@coinbase/wallet-sdk": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.6.tgz", + "integrity": "sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==", + "license": "Apache-2.0", + "dependencies": { + "@noble/hashes": "1.4.0", + "clsx": "1.2.1", + "eventemitter3": "5.0.1", + "idb-keyval": "6.2.1", + "ox": "0.6.9", + "preact": "10.24.2", + "viem": "^2.27.2", + "zustand": "5.0.3" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/preact": { + "version": "10.24.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz", + "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/@corex/deepmerge": { + "version": "4.0.43", + "resolved": "https://registry.npmjs.org/@corex/deepmerge/-/deepmerge-4.0.43.tgz", + "integrity": "sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==", + "license": "MIT" + }, + "node_modules/@crowdin/crowdin-api-client": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@crowdin/crowdin-api-client/-/crowdin-api-client-1.46.0.tgz", + "integrity": "sha512-aCAKlr1Aw4T1Fss16lDNw/HRpU7HTrgQqTHUxTBBAYjx7KK6ghPYX89X4LU8DeLyXijrZN6ph9zF/gWAWBNtUA==", + "license": "MIT", + "dependencies": { + "axios": "^1" + }, + "engines": { + "node": ">=12.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.9.0.tgz", + "integrity": "sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.9.0.tgz", + "integrity": "sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.9", + "@algolia/autocomplete-preset-algolia": "1.17.9", + "@docsearch/css": "3.9.0", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@ecies/ciphers": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.4.tgz", + "integrity": "sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==", + "license": "MIT", + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + }, + "peerDependencies": { + "@noble/ciphers": "^1.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", + "optional": true + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", + "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", + "license": "MIT", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "crc-32": "^1.2.0" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", + "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/common": "^3.2.0", + "@ethereumjs/rlp": "^4.0.1", + "@ethereumjs/util": "^8.1.0", + "ethereum-cryptography": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz", + "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz", + "integrity": "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", + "integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.1", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz", + "integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz", + "integrity": "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/icu-skeleton-parser": "1.8.14", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz", + "integrity": "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz", + "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==", + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, + "node_modules/@hookform/resolvers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", + "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.1.tgz", + "integrity": "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@lukeed/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", + "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@metamask/eth-json-rpc-provider": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz", + "integrity": "sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==", + "dependencies": { + "@metamask/json-rpc-engine": "^7.0.0", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz", + "integrity": "sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==", + "license": "ISC", + "dependencies": { + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^8.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine/node_modules/@metamask/utils": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", + "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.0.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", + "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.1.2", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "semver": "^7.3.8", + "superstruct": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@metamask/json-rpc-engine": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz", + "integrity": "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==", + "license": "ISC", + "dependencies": { + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^8.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/json-rpc-middleware-stream": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.2.tgz", + "integrity": "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==", + "license": "ISC", + "dependencies": { + "@metamask/json-rpc-engine": "^8.0.2", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^8.3.0", + "readable-stream": "^3.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/json-rpc-middleware-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/object-multiplex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz", + "integrity": "sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==", + "license": "ISC", + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.2" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/onboarding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@metamask/onboarding/-/onboarding-1.0.1.tgz", + "integrity": "sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==", + "license": "MIT", + "dependencies": { + "bowser": "^2.9.0" + } + }, + "node_modules/@metamask/providers": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-16.1.0.tgz", + "integrity": "sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==", + "license": "MIT", + "dependencies": { + "@metamask/json-rpc-engine": "^8.0.1", + "@metamask/json-rpc-middleware-stream": "^7.0.1", + "@metamask/object-multiplex": "^2.0.0", + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.1.1", + "@metamask/utils": "^8.3.0", + "detect-browser": "^5.2.0", + "extension-port-stream": "^3.0.0", + "fast-deep-equal": "^3.1.3", + "is-stream": "^2.0.0", + "readable-stream": "^3.6.2", + "webextension-polyfill": "^0.10.0" + }, + "engines": { + "node": "^18.18 || >=20" + } + }, + "node_modules/@metamask/providers/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@metamask/providers/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/rpc-errors": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", + "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", + "license": "MIT", + "dependencies": { + "@metamask/utils": "^9.0.0", + "fast-safe-stringify": "^2.0.6" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", + "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.1.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/safe-event-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", + "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", + "license": "ISC", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/sdk": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.32.0.tgz", + "integrity": "sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@metamask/onboarding": "^1.0.1", + "@metamask/providers": "16.1.0", + "@metamask/sdk-communication-layer": "0.32.0", + "@metamask/sdk-install-modal-web": "0.32.0", + "@paulmillr/qr": "^0.2.1", + "bowser": "^2.9.0", + "cross-fetch": "^4.0.0", + "debug": "^4.3.4", + "eciesjs": "^0.4.11", + "eth-rpc-errors": "^4.0.3", + "eventemitter2": "^6.4.9", + "obj-multiplex": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^3.6.2", + "socket.io-client": "^4.5.1", + "tslib": "^2.6.0", + "util": "^0.12.4", + "uuid": "^8.3.2" + } + }, + "node_modules/@metamask/sdk-install-modal-web": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.32.0.tgz", + "integrity": "sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==", + "dependencies": { + "@paulmillr/qr": "^0.2.1" + } + }, + "node_modules/@metamask/sdk/node_modules/@metamask/sdk-communication-layer": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.32.0.tgz", + "integrity": "sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==", + "dependencies": { + "bufferutil": "^4.0.8", + "date-fns": "^2.29.3", + "debug": "^4.3.4", + "utf-8-validate": "^5.0.2", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "cross-fetch": "^4.0.0", + "eciesjs": "*", + "eventemitter2": "^6.4.9", + "readable-stream": "^3.6.2", + "socket.io-client": "^4.5.1" + } + }, + "node_modules/@metamask/sdk/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@metamask/sdk/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@metamask/superstruct": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.2.1.tgz", + "integrity": "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/utils": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", + "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.2.0", + "@metamask/superstruct": "^3.0.0", + "@noble/hashes": "^1.3.1", + "@scure/base": "^1.1.3", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "pony-cause": "^2.1.10", + "semver": "^7.5.4", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@netlify/plugin-nextjs": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@netlify/plugin-nextjs/-/plugin-nextjs-5.12.0.tgz", + "integrity": "sha512-SXQY/nCiSOSAZWNls/DQxrICldUR7PHSMUw2J2/ZejH1dk12Vwd3+SzSihHrRW9PNcErZkC2g3seM7bWZlvBRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@next/bundle-analyzer": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-14.2.31.tgz", + "integrity": "sha512-MXJezm1pcVlCrKCzWHuaNXlxcUFbsyYpjsgqDjJAX3rFnOvrh8RmgvcTHoEKtZE+a5KzjcQYWVRjx/P6TspQ9w==", + "license": "MIT", + "dependencies": { + "webpack-bundle-analyzer": "4.10.1" + } + }, + "node_modules/@next/env": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.31.tgz", + "integrity": "sha512-X8VxxYL6VuezrG82h0pUA1V+DuTSJp7Nv15bxq3ivrFqZLjx81rfeHMWOE9T0jm1n3DtHGv8gdn6B0T0kr0D3Q==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.31.tgz", + "integrity": "sha512-ouaB+l8Cr/uzGxoGHUvd01OnfFTM8qM81Crw1AG0xoWDRN0DKLXyTWVe0FdAOHVBpGuXB87aufdRmrwzZDArIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "10.3.10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.31.tgz", + "integrity": "sha512-dTHKfaFO/xMJ3kzhXYgf64VtV6MMwDs2viedDOdP+ezd0zWMOQZkxcwOfdcQeQCpouTr9b+xOqMCUXxgLizl8Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.31.tgz", + "integrity": "sha512-iSavebQgeMukUAfjfW8Fi2Iz01t95yxRl2w2wCzjD91h5In9la99QIDKcKSYPfqLjCgwz3JpIWxLG6LM/sxL4g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.31.tgz", + "integrity": "sha512-XJb3/LURg1u1SdQoopG6jDL2otxGKChH2UYnUTcby4izjM0il7ylBY5TIA7myhvHj9lG5pn9F2nR2s3i8X9awQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.31.tgz", + "integrity": "sha512-IInDAcchNCu3BzocdqdCv1bKCmUVO/bKJHnBFTeq3svfaWpOPewaLJ2Lu3GL4yV76c/86ZvpBbG/JJ1lVIs5MA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.31.tgz", + "integrity": "sha512-YTChJL5/9e4NXPKW+OJzsQa42RiWUNbE+k+ReHvA+lwXk+bvzTsVQboNcezWOuCD+p/J+ntxKOB/81o0MenBhw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.31.tgz", + "integrity": "sha512-A0JmD1y4q/9ufOGEAhoa60Sof++X10PEoiWOH0gZ2isufWZeV03NnyRlRmJpRQWGIbRkJUmBo9I3Qz5C10vx4w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.31.tgz", + "integrity": "sha512-nowJ5GbMeDOMzbTm29YqrdrD6lTM8qn2wnZfGpYMY7SZODYYpaJHH1FJXE1l1zWICHR+WfIMytlTDBHu10jb8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.31.tgz", + "integrity": "sha512-pk9Bu4K0015anTS1OS9d/SpS0UtRObC+xe93fwnm7Gvqbv/W1ZbzhK4nvc96RURIQOux3P/bBH316xz8wjGSsA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.31.tgz", + "integrity": "sha512-LwFZd4JFnMHGceItR9+jtlMm8lGLU/IPkgjBBgYmdYSfalbHCiDpjMYtgDQ2wtwiAOSJOCyFI4m8PikrsDyA6Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", + "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@paulmillr/qr": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.2.1.tgz", + "integrity": "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==", + "deprecated": "The package is now available as \"qr\": npm install qr", + "license": "(MIT OR Apache-2.0)", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz", + "integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.54.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz", + "integrity": "sha512-tXDyE1/jzFsHXjhRZQ3hMl0IVhYe5qula43LDWIhVfjp9G/nT5OQY5AORVOrkEGAUltBJOfOWeETbmhm6kHhuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "license": "MIT" + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.11.tgz", + "integrity": "sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collapsible": "1.1.11", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.2.tgz", + "integrity": "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.11.tgz", + "integrity": "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", + "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.13.tgz", + "integrity": "sha512-WG8wWfDiJlSF5hELjwfjSGOXcBR/ZMhBFCGYe8vERpC39CQYZeq1PQ2kaYHdye3V95d06H89KGMsVCIE4LWo3g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", + "integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz", + "integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.9.tgz", + "integrity": "sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz", + "integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz", + "integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz", + "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@rainbow-me/rainbowkit": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@rainbow-me/rainbowkit/-/rainbowkit-2.2.8.tgz", + "integrity": "sha512-EdNIK2cdAT6GJ9G11wx7nCVfjqBfxh7dx/1DhPYrB+yg+VFrII6cM1PiMFVC9evD4mqVHe9mmLAt3nvlwDdiPQ==", + "license": "MIT", + "dependencies": { + "@vanilla-extract/css": "1.17.3", + "@vanilla-extract/dynamic": "2.1.4", + "@vanilla-extract/sprinkles": "1.6.4", + "clsx": "2.1.1", + "cuer": "0.0.2", + "react-remove-scroll": "2.6.2", + "ua-parser-js": "^1.0.37" + }, + "engines": { + "node": ">=12.4" + }, + "peerDependencies": { + "@tanstack/react-query": ">=5.0.0", + "react": ">=18", + "react-dom": ">=18", + "viem": "2.x", + "wagmi": "^2.9.0" + } + }, + "node_modules/@rainbow-me/rainbowkit/node_modules/react-remove-scroll": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", + "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@reown/appkit": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.7.8.tgz", + "integrity": "sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-controllers": "1.7.8", + "@reown/appkit-pay": "1.7.8", + "@reown/appkit-polyfills": "1.7.8", + "@reown/appkit-scaffold-ui": "1.7.8", + "@reown/appkit-ui": "1.7.8", + "@reown/appkit-utils": "1.7.8", + "@reown/appkit-wallet": "1.7.8", + "@walletconnect/types": "2.21.0", + "@walletconnect/universal-provider": "2.21.0", + "bs58": "6.0.0", + "valtio": "1.13.2", + "viem": ">=2.29.0" + } + }, + "node_modules/@reown/appkit-common": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.7.8.tgz", + "integrity": "sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==", + "license": "Apache-2.0", + "dependencies": { + "big.js": "6.2.2", + "dayjs": "1.11.13", + "viem": ">=2.29.0" + } + }, + "node_modules/@reown/appkit-controllers": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.7.8.tgz", + "integrity": "sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-wallet": "1.7.8", + "@walletconnect/universal-provider": "2.21.0", + "valtio": "1.13.2", + "viem": ">=2.29.0" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@scure/bip32": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@scure/bip39": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/core": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", + "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/sign-client": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", + "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.21.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/types": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", + "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/universal-provider": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", + "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.21.0", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/utils": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", + "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/utils/node_modules/viem": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", + "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.7", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@reown/appkit-controllers/node_modules/ox": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", + "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-controllers/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-controllers/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-pay": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.7.8.tgz", + "integrity": "sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-controllers": "1.7.8", + "@reown/appkit-ui": "1.7.8", + "@reown/appkit-utils": "1.7.8", + "lit": "3.3.0", + "valtio": "1.13.2" + } + }, + "node_modules/@reown/appkit-polyfills": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.7.8.tgz", + "integrity": "sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/@reown/appkit-scaffold-ui": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.7.8.tgz", + "integrity": "sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-controllers": "1.7.8", + "@reown/appkit-ui": "1.7.8", + "@reown/appkit-utils": "1.7.8", + "@reown/appkit-wallet": "1.7.8", + "lit": "3.3.0" + } + }, + "node_modules/@reown/appkit-ui": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.7.8.tgz", + "integrity": "sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-controllers": "1.7.8", + "@reown/appkit-wallet": "1.7.8", + "lit": "3.3.0", + "qrcode": "1.5.3" + } + }, + "node_modules/@reown/appkit-utils": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.7.8.tgz", + "integrity": "sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-controllers": "1.7.8", + "@reown/appkit-polyfills": "1.7.8", + "@reown/appkit-wallet": "1.7.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/universal-provider": "2.21.0", + "valtio": "1.13.2", + "viem": ">=2.29.0" + }, + "peerDependencies": { + "valtio": "1.13.2" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@scure/bip32": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@scure/bip39": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/core": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", + "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/sign-client": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", + "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.21.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/types": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", + "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/universal-provider": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", + "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.21.0", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/utils": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", + "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, + "node_modules/@reown/appkit-utils/node_modules/@walletconnect/utils/node_modules/viem": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", + "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.7", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/@reown/appkit-utils/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@reown/appkit-utils/node_modules/ox": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", + "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit-utils/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-utils/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@reown/appkit-wallet": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.7.8.tgz", + "integrity": "sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.7.8", + "@reown/appkit-polyfills": "1.7.8", + "@walletconnect/logger": "2.1.2", + "zod": "3.22.4" + } + }, + "node_modules/@reown/appkit/node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@scure/bip32": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@scure/bip39": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/core": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", + "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/sign-client": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", + "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.21.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/types": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", + "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/universal-provider": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", + "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.21.0", + "@walletconnect/types": "2.21.0", + "@walletconnect/utils": "2.21.0", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/utils": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", + "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, + "node_modules/@reown/appkit/node_modules/@walletconnect/utils/node_modules/viem": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", + "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.7", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/@reown/appkit/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@reown/appkit/node_modules/ox": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", + "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@reown/appkit/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@reown/appkit/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz", + "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@safe-global/safe-apps-provider": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.6.tgz", + "integrity": "sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==", + "license": "MIT", + "dependencies": { + "@safe-global/safe-apps-sdk": "^9.1.0", + "events": "^3.3.0" + } + }, + "node_modules/@safe-global/safe-apps-sdk": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", + "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", + "license": "MIT", + "dependencies": { + "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", + "viem": "^2.1.1" + } + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.23.1.tgz", + "integrity": "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@segment/analytics-core": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.4.1.tgz", + "integrity": "sha512-kV0Pf33HnthuBOVdYNani21kYyj118Fn+9757bxqoksiXoZlYvBsFq6giNdCsKcTIE1eAMqNDq3xE1VQ0cfsHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lukeed/uuid": "^2.0.0", + "@segment/analytics-generic-utils": "1.1.1", + "dset": "^3.1.2", + "tslib": "^2.4.1" + } + }, + "node_modules/@segment/analytics-generic-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@segment/analytics-generic-utils/-/analytics-generic-utils-1.1.1.tgz", + "integrity": "sha512-THTIzBPHnvu1HYJU3fARdJ3qIkukO3zDXsmDm+kAeUks5R9CBXOQ6rPChiASVzSmwAIIo5uFIXXnCraojlq/Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.1" + } + }, + "node_modules/@segment/analytics-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-1.3.0.tgz", + "integrity": "sha512-lRLz1WZaDokMoUe299yP5JkInc3OgJuqNNlxb6j0q22umCiq6b5iDo2gRmFn93reirIvJxWIicQsGrHd93q8GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lukeed/uuid": "^2.0.0", + "@segment/analytics-core": "1.4.1", + "@segment/analytics-generic-utils": "1.1.1", + "buffer": "^6.0.3", + "node-fetch": "^2.6.7", + "tslib": "^2.4.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@socialgouv/matomo-next": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@socialgouv/matomo-next/-/matomo-next-1.9.2.tgz", + "integrity": "sha512-UtiOBAzKiCwal6/2Lfh3fnv9L8XC4Ovdqqh1K3fimJZJhodf18fD3oy3ansGpgj+A7YE8HPV7/u/q6cYbRP3nw==", + "license": "Apache-2.0", + "peerDependencies": { + "next": ">= 9.5.5" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@storybook/addon-actions": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.14.tgz", + "integrity": "sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.14.tgz", + "integrity": "sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.14.tgz", + "integrity": "sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "dequal": "^2.0.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.14.tgz", + "integrity": "sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.6.14", + "@storybook/csf-plugin": "8.6.14", + "@storybook/react-dom-shim": "8.6.14", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.14.tgz", + "integrity": "sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/addon-actions": "8.6.14", + "@storybook/addon-backgrounds": "8.6.14", + "@storybook/addon-controls": "8.6.14", + "@storybook/addon-docs": "8.6.14", + "@storybook/addon-highlight": "8.6.14", + "@storybook/addon-measure": "8.6.14", + "@storybook/addon-outline": "8.6.14", + "@storybook/addon-toolbars": "8.6.14", + "@storybook/addon-viewport": "8.6.14", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.14.tgz", + "integrity": "sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.6.14.tgz", + "integrity": "sha512-8VmElhm2XOjh22l/dO4UmXxNOolGhNiSpBcls2pqWSraVh4a670EyYBZsHpkXqfNHo2YgKyZN3C91+9zfH79qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.6.14", + "@storybook/test": "8.6.14", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-links": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.6.14.tgz", + "integrity": "sha512-DRlXHIyZzOruAZkxmXfVgTF+4d6K27pFcH4cUsm3KT1AXuZbr23lb5iZHpUZoG6lmU85Sru4xCEgewSTXBIe1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.14.tgz", + "integrity": "sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.14.tgz", + "integrity": "sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-themes": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-themes/-/addon-themes-8.6.14.tgz", + "integrity": "sha512-/HJCgskA3OFGectuoLEBQ3JX1nQhE7lnpSv5gH13CWyyaMEk/mP8JYF1uO25YQqwGuSgL2gaEox+aK7UmglAmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.14.tgz", + "integrity": "sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.14.tgz", + "integrity": "sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.14.tgz", + "integrity": "sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/icons": "^1.2.12", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.6.14.tgz", + "integrity": "sha512-YZYAqc6NBKoMTKZpjxnkMch6zDtMkBZdS/yaji1+wJX2QPFBwTbSh7SpeBxDp1S11gXSAJ4f1btUWeqSqo8nJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core-webpack": "8.6.14", + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/components": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.14.tgz", + "integrity": "sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/core": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.14.tgz", + "integrity": "sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/theming": "8.6.14", + "better-opn": "^3.0.2", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "esbuild-register": "^3.5.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "process": "^0.11.10", + "recast": "^0.23.5", + "semver": "^7.6.2", + "util": "^0.12.5", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core-webpack": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.6.14.tgz", + "integrity": "sha512-iG7r8osNKabSGBbuJuSeMWKbU+ilt5PvzTYkClcYaagla/DliXkXvfywA6jOugVk/Cpx+c6tVKlPfjLcaQHwmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.13.tgz", + "integrity": "sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.14.tgz", + "integrity": "sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.4.0.tgz", + "integrity": "sha512-Td73IeJxOyalzvjQL+JXx72jlIYHgs+REaHiREOqfpo3A2AYYG71AUbcv+lg7mEDIweKVCxsMQ0UKo634c8XeA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.14.tgz", + "integrity": "sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^2.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/manager-api": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.14.tgz", + "integrity": "sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/nextjs": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/nextjs/-/nextjs-8.6.14.tgz", + "integrity": "sha512-HbOOpwxJxO8nIDBvEQL3Pt51GHxnSeVxQ/WApr1HCT5Ffu6KCHz8WVsX56taHdigxjonSq0NTnog+aTIP06Nkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.1", + "@babel/plugin-transform-runtime": "^7.24.3", + "@babel/preset-env": "^7.24.4", + "@babel/preset-react": "^7.24.1", + "@babel/preset-typescript": "^7.24.1", + "@babel/runtime": "^7.24.4", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", + "@storybook/builder-webpack5": "8.6.14", + "@storybook/preset-react-webpack": "8.6.14", + "@storybook/react": "8.6.14", + "@storybook/test": "8.6.14", + "@types/semver": "^7.3.4", + "babel-loader": "^9.1.3", + "css-loader": "^6.7.3", + "find-up": "^5.0.0", + "image-size": "^1.0.0", + "loader-utils": "^3.2.1", + "node-polyfill-webpack-plugin": "^2.0.1", + "pnp-webpack-plugin": "^1.7.0", + "postcss": "^8.4.38", + "postcss-loader": "^8.1.1", + "react-refresh": "^0.14.0", + "resolve-url-loader": "^5.0.0", + "sass-loader": "^14.2.1", + "semver": "^7.3.5", + "style-loader": "^3.3.1", + "styled-jsx": "^5.1.6", + "ts-dedent": "^2.0.0", + "tsconfig-paths": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^4.0.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "optionalDependencies": { + "sharp": "^0.33.3" + }, + "peerDependencies": { + "next": "^13.5.0 || ^14.0.0 || ^15.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/nextjs/node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/@storybook/preset-react-webpack": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.6.14.tgz", + "integrity": "sha512-M7Q6ErNx7N2hQorTz0OLa3YV8nc8OcvkDlCxqqnkHPGQNEIWEpeDvq3wn2OvZlrHDpchyuiquGXZ8aztVtBP2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core-webpack": "8.6.14", + "@storybook/react": "8.6.14", + "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", + "@types/semver": "^7.3.4", + "find-up": "^5.0.0", + "magic-string": "^0.30.5", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "semver": "^7.3.7", + "tsconfig-paths": "^4.2.0", + "webpack": "5" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/preset-server-webpack": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/preset-server-webpack/-/preset-server-webpack-8.5.8.tgz", + "integrity": "sha512-0QA23bmhchmec6zI0JzoXWIA723n8XhEtJndUQDS96cTyDGyb3AuedNgwu5xQw9Zv+EJZjO84uGcNYinPEnmKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core-webpack": "8.5.8", + "@storybook/global": "^5.0.0", + "@storybook/server": "8.5.8", + "safe-identifier": "^0.4.1", + "ts-dedent": "^2.0.0", + "yaml-loader": "^0.8.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@storybook/preset-server-webpack/node_modules/@storybook/core-webpack": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.5.8.tgz", + "integrity": "sha512-M2LNQdYp0br8fgKMVtBh7YIo8mQsgALLc4i9PEXRS7wrp+bhvVnA9qhd5xDPzb0Rl4CHYbs4Yvkzo7ZQMibeIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@storybook/preview-api": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.14.tgz", + "integrity": "sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/react": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.6.14.tgz", + "integrity": "sha512-BOepx5bBFwl/CPI+F+LnmMmsG1wQYmrX/UQXgUbHQUU9Tj7E2ndTnNbpIuSLc8IrM03ru+DfwSg1Co3cxWtT+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/components": "8.6.14", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "8.6.14", + "@storybook/preview-api": "8.6.14", + "@storybook/react-dom-shim": "8.6.14", + "@storybook/theming": "8.6.14" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/test": "8.6.14", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin": { + "version": "1.0.6--canary.9.0c3f3b7.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", + "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.x", + "webpack": ">= 4" + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.14.tgz", + "integrity": "sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/server": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/server/-/server-8.5.8.tgz", + "integrity": "sha512-DB3IR7CCUklTXtytbOOX7Vig1h9ohQ3BPauvf7WlYXLv4JlkO54oTu37rL0wbqgmmh4FOF41ZSX8z4h4w41How==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/components": "8.5.8", + "@storybook/csf": "0.1.12", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "8.5.8", + "@storybook/preview-api": "8.5.8", + "@storybook/theming": "8.5.8", + "ts-dedent": "^2.0.0", + "yaml": "^2.3.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@storybook/server-webpack5": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/server-webpack5/-/server-webpack5-8.5.8.tgz", + "integrity": "sha512-bdRxp0kUGBstDdCEIfJEbsmM7vvyBES4Hjmj0jXcOefQYic5QTWTiDMrHgWPp8XWGjIoO+wOfWm2IXPP5Uceog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/builder-webpack5": "8.5.8", + "@storybook/preset-server-webpack": "8.5.8", + "@storybook/server": "8.5.8" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@storybook/server-webpack5/node_modules/@storybook/builder-webpack5": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.5.8.tgz", + "integrity": "sha512-QaBIMyqWX/eQs4laQBXvAW9M/ylk73WljJySPlTl+8PNVuDtHli24oBJXwx5aV1NT53BLsaKAn/vb2QNL4+G1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core-webpack": "8.5.8", + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/server-webpack5/node_modules/@storybook/core-webpack": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.5.8.tgz", + "integrity": "sha512-M2LNQdYp0br8fgKMVtBh7YIo8mQsgALLc4i9PEXRS7wrp+bhvVnA9qhd5xDPzb0Rl4CHYbs4Yvkzo7ZQMibeIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.8" + } + }, + "node_modules/@storybook/server/node_modules/@storybook/components": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.5.8.tgz", + "integrity": "sha512-PPEMqWPXn7rX+qISaOOv9CDSuuvG538f0+4M5Ppq2LwpjXecgOG5ktqJF0ZqxmTytT+RpEaJmgjGW0dMAKZswA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/server/node_modules/@storybook/csf": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.12.tgz", + "integrity": "sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/server/node_modules/@storybook/manager-api": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.5.8.tgz", + "integrity": "sha512-ik3yikvYxAJMDFg0s3Pm7hZWucAlkFaaO7e2RlfOctaJFdaEi3evR4RS7GdmS38uKBEk31RC7x+nnIJkqEC59A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/server/node_modules/@storybook/preview-api": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.5.8.tgz", + "integrity": "sha512-HJoz2o28VVprnU5OG6JO6CHrD3ah6qVPWixbnmyUKd0hOYF5dayK5ptmeLyUpYX56Eb2KoYcuVaeQqAby4RkNw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/server/node_modules/@storybook/theming": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.5.8.tgz", + "integrity": "sha512-/Rm6BV778sCT+3Ok861VYmw9BlEV5zcCq2zg5TOVuk8HqZw7H7VHtubVsjukEuhveYCs+oF+i2tv/II6jh6jdg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/test": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.14.tgz", + "integrity": "sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.6.14", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.5.0", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "2.0.5", + "@vitest/spy": "2.0.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/theming": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.14.tgz", + "integrity": "sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.83.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.83.1.tgz", + "integrity": "sha512-OG69LQgT7jSp+5pPuCfzltq/+7l2xoweggjme9vlbCPa/d7D7zaqv5vN/S82SzSYZ4EDLTxNO1PWrv49RAS64Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.84.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.84.1.tgz", + "integrity": "sha512-zo7EUygcWJMQfFNWDSG7CBhy8irje/XY0RDVKKV4IQJAysb+ZJkkJPcnQi+KboyGUgT+SQebRFoTqLuTtfoDLw==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.83.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", + "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.2.0.tgz", + "integrity": "sha512-lvEOjxeXIp+wPXgl9kJA97dqzMfNexjqHou+XHVcfxQgolctoJiRYmcVCWGpiZ9CBf/CJha1KmD1qQoRIsjLaA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/invariant": "^7.2.0", + "@types/geojson": "^7946.0.10", + "point-in-polygon-hao": "^1.1.0", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.2.0.tgz", + "integrity": "sha512-kV4u8e7Gkpq+kPbAKNC21CmyrXzlbBgFjO1PhrHPgEdNqXqDawoZ3i6ivE3ULJj2rSesCjduUaC/wyvH/sNr2Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/canvas-confetti": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.9.0.tgz", + "integrity": "sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==", + "license": "MIT" + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/decompress": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.7.tgz", + "integrity": "sha512-9z+8yjKr5Wn73Pt17/ldnmQToaFHZxK0N1GHysuk/JIPT8RIdQeoInM01wWPgypRcvb6VH1drjuFpQ4zmY437g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", + "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.2.57", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.57.tgz", + "integrity": "sha512-ZvQsktJgSYrQiMirAN60y4O/LRevIV8hUzSOSNB6gfR3/o3wCBFQx3sPwIYtuDMeiVgsSS3UzCV26tEzgnfvQw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.19", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.19.tgz", + "integrity": "sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.177.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.177.0.tgz", + "integrity": "sha512-/ZAkn4OLUijKQySNci47lFO+4JLE1TihEjsGWPUT+4jWqxtwOPPEwJV1C3k5MEx0mcBPCdkFjzRzDOnHEI1R+A==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/ungap__structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/ungap__structured-clone/-/ungap__structured-clone-1.2.0.tgz", + "integrity": "sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/webxr": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", + "integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==", + "license": "MIT" + }, + "node_modules/@types/xml2js": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", + "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vanilla-extract/css": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.17.3.tgz", + "integrity": "sha512-jHivr1UPoJTX5Uel4AZSOwrCf4mO42LcdmnhJtUxZaRWhW4FviFbIfs0moAWWld7GOT+2XnuVZjjA/K32uUnMQ==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@vanilla-extract/private": "^1.0.8", + "css-what": "^6.1.0", + "cssesc": "^3.0.0", + "csstype": "^3.0.7", + "dedent": "^1.5.3", + "deep-object-diff": "^1.1.9", + "deepmerge": "^4.2.2", + "lru-cache": "^10.4.3", + "media-query-parser": "^2.0.2", + "modern-ahocorasick": "^1.0.0", + "picocolors": "^1.0.0" + } + }, + "node_modules/@vanilla-extract/css/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@vanilla-extract/dynamic": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vanilla-extract/dynamic/-/dynamic-2.1.4.tgz", + "integrity": "sha512-7+Ot7VlP3cIzhJnTsY/kBtNs21s0YD7WI1rKJJKYP56BkbDxi/wrQUWMGEczKPUDkJuFcvbye+E2ub1u/mHH9w==", + "license": "MIT", + "dependencies": { + "@vanilla-extract/private": "^1.0.8" + } + }, + "node_modules/@vanilla-extract/private": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@vanilla-extract/private/-/private-1.0.9.tgz", + "integrity": "sha512-gT2jbfZuaaCLrAxwXbRgIhGhcXbRZCG3v4TTUnjw0EJ7ArdBRxkq4msNJkbuRkCgfIK5ATmprB5t9ljvLeFDEA==", + "license": "MIT" + }, + "node_modules/@vanilla-extract/sprinkles": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@vanilla-extract/sprinkles/-/sprinkles-1.6.4.tgz", + "integrity": "sha512-lW3MuIcdIeHKX81DzhTnw68YJdL1ial05exiuvTLJMdHXQLKcVB93AncLPajMM6mUhaVVx5ALZzNHMTrq/U9Hg==", + "license": "MIT", + "peerDependencies": { + "@vanilla-extract/css": "^1.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", + "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.0.5", + "@vitest/utils": "2.0.5", + "chai": "^5.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/pretty-format": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", + "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", + "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.0.5", + "estree-walker": "^3.0.3", + "loupe": "^3.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", + "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@wagmi/connectors": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-5.9.1.tgz", + "integrity": "sha512-o50e6reSYkVi2d72WWwbKSZ7xgLAeQ1Ja64tTWq3UhU1XtJPvQXWieCInIGInOajAAsZsYCPKYrPj6WoSl0Hqw==", + "license": "MIT", + "dependencies": { + "@base-org/account": "1.1.1", + "@coinbase/wallet-sdk": "4.3.6", + "@metamask/sdk": "0.32.0", + "@safe-global/safe-apps-provider": "0.18.6", + "@safe-global/safe-apps-sdk": "9.1.0", + "@walletconnect/ethereum-provider": "2.21.1", + "cbw-sdk": "npm:@coinbase/wallet-sdk@3.9.3" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@wagmi/core": "2.18.1", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wagmi/core": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.18.1.tgz", + "integrity": "sha512-mU+qXeeY2/0lq8bf4uFm5RtMrc8FgOToqzMVMf6MzNdNbKxpNlmlbuTyRbyd9cxn4UnYa6+S6Bmx1x42FV7w3g==", + "license": "MIT", + "dependencies": { + "eventemitter3": "5.0.1", + "mipd": "0.0.7", + "zustand": "5.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@tanstack/query-core": ">=5.0.0", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "@tanstack/query-core": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@walletconnect/core": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.1.tgz", + "integrity": "sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.1", + "@walletconnect/utils": "2.21.1", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.33.0", + "events": "3.3.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@walletconnect/core/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/core/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/core/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/core/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/core/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/environment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", + "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/environment/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/ethereum-provider": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.21.1.tgz", + "integrity": "sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit": "1.7.8", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/sign-client": "2.21.1", + "@walletconnect/types": "2.21.1", + "@walletconnect/universal-provider": "2.21.1", + "@walletconnect/utils": "2.21.1", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/ethereum-provider/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/ethereum-provider/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/ethereum-provider/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/ethereum-provider/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/ethereum-provider/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", + "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", + "license": "MIT", + "dependencies": { + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/events/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/heartbeat": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz", + "integrity": "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==", + "license": "MIT", + "dependencies": { + "@walletconnect/events": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-http-connection": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", + "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.1", + "cross-fetch": "^3.1.4", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-http-connection/node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/@walletconnect/jsonrpc-provider": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz", + "integrity": "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz", + "integrity": "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "keyvaluestorage-interface": "^1.0.0" + } + }, + "node_modules/@walletconnect/jsonrpc-utils": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", + "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", + "license": "MIT", + "dependencies": { + "@walletconnect/environment": "^1.0.1", + "@walletconnect/jsonrpc-types": "^1.0.3", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", + "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } + }, + "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@walletconnect/logger": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.1.2.tgz", + "integrity": "sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.2", + "pino": "7.11.0" + } + }, + "node_modules/@walletconnect/relay-api": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.11.tgz", + "integrity": "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-types": "^1.0.2" + } + }, + "node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/safe-json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", + "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/safe-json/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/sign-client": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.1.tgz", + "integrity": "sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.21.1", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.1", + "@walletconnect/utils": "2.21.1", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", + "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/time/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/types": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.1.tgz", + "integrity": "sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/types/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/types/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/types/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/types/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/types/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/universal-provider": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.1.tgz", + "integrity": "sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.21.1", + "@walletconnect/types": "2.21.1", + "@walletconnect/utils": "2.21.1", + "es-toolkit": "1.33.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/universal-provider/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.1.tgz", + "integrity": "sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.21.1", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "3.1.0", + "viem": "2.23.2" + } + }, + "node_modules/@walletconnect/utils/node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@scure/bip32": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@scure/bip39": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/@walletconnect/utils/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/utils/node_modules/ox": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", + "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/unstorage": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.1.tgz", + "integrity": "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.3", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.6", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/viem": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", + "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", + "isows": "1.0.6", + "ox": "0.6.7", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@walletconnect/window-getters": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", + "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-getters/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/window-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", + "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", + "license": "MIT", + "dependencies": { + "@walletconnect/window-getters": "^1.0.1", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-metadata/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.64", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.64.tgz", + "integrity": "sha512-84kRIAGV46LJTlJZWxShiOrNL30A+9KokD7RB3dRCIqODFjodS5tCD5yyiZ8kIReGVZSDfA3XkkwyyOIF6K62A==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/abitype": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", + "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accessor-fn": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz", + "integrity": "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/algoliasearch": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz", + "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==", + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.1.0", + "@algolia/client-abtesting": "5.35.0", + "@algolia/client-analytics": "5.35.0", + "@algolia/client-common": "5.35.0", + "@algolia/client-insights": "5.35.0", + "@algolia/client-personalization": "5.35.0", + "@algolia/client-query-suggestions": "5.35.0", + "@algolia/client-search": "5.35.0", + "@algolia/ingestion": "1.35.0", + "@algolia/monitoring": "1.35.0", + "@algolia/recommend": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-mutex": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.2.6.tgz", + "integrity": "sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-macros/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.0.tgz", + "integrity": "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.6.tgz", + "integrity": "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bl/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/bl/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvas-confetti": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz", + "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==", + "license": "ISC", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/cbw-sdk": { + "name": "@coinbase/wallet-sdk", + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-3.9.3.tgz", + "integrity": "sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.1", + "buffer": "^6.0.3", + "clsx": "^1.2.1", + "eth-block-tracker": "^7.1.0", + "eth-json-rpc-filters": "^6.0.0", + "eventemitter3": "^5.0.1", + "keccak": "^3.0.3", + "preact": "^10.16.0", + "sha.js": "^2.4.11" + } + }, + "node_modules/cbw-sdk/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", + "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chart.js": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", + "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/chromatic": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-12.0.0.tgz", + "integrity": "sha512-X7v26BLfAzHCU92nxPsCuvt+MazmA7S6cN7pCRRhnDYChDxHES48YvXarOybLdlH9kNP/3lMyknu6iseTh0T9A==", + "dev": true, + "license": "MIT", + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "peerDependencies": { + "@chromatic-com/cypress": "^0.*.* || ^1.0.0", + "@chromatic-com/playwright": "^0.*.* || ^1.0.0" + }, + "peerDependenciesMeta": { + "@chromatic-com/cypress": { + "optional": true + }, + "@chromatic-com/playwright": { + "optional": true + } + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, + "license": "ISC" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", + "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz", + "integrity": "sha512-gvMQAGB4dfVUxpYD0k3Fq8J+n5bB6Ytl15lqlZrOIXFzxOhtPaObfkQGHtMRdyjIf7z2IeNULwi1jEwyS+ltKQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/cuer": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cuer/-/cuer-0.0.2.tgz", + "integrity": "sha512-MG1BYnnSLqBnO0dOBS1Qm/TEc9DnFa9Sz2jMA24OF4hGzs8UuPjpKBMkRPF3lrpC+7b3EzULwooX9djcvsM8IA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "qr": "~0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-voronoi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz", + "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-delaunay": "6", + "d3-geo": "3", + "d3-tricontour": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-octree": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz", + "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==", + "license": "MIT" + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-tricontour": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.0.2.tgz", + "integrity": "sha512-HIRxHzHagPtUPNabjOlfcyismJYIsc+Xlq4mlsts4e8eAcwyq9Tgk/sYdyhlBpQ0MHwVquc/8j+e29YjXnmxeA==", + "license": "ISC", + "dependencies": { + "d3-delaunay": "6", + "d3-scale": "4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-bind-mapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/data-bind-mapper/-/data-bind-mapper-1.0.3.tgz", + "integrity": "sha512-QmU3lyEnbENQPo0M1F9BMu4s6cqNNp8iJA+b/HP2sSb7pf3dxwF3+EP1eO69rwBfH9kFJ1apmzrtogAmVt2/Xw==", + "license": "MIT", + "dependencies": { + "accessor-fn": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tarbz2/node_modules/file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip/node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dedent": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-object-diff": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", + "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/derive-valtio": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", + "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", + "license": "MIT", + "peerDependencies": { + "valtio": "*" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domain-browser": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", + "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/eciesjs": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.15.tgz", + "integrity": "sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==", + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.3", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.1", + "@noble/hashes": "^1.8.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.194", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", + "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", + "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", + "license": "MIT" + }, + "node_modules/embla-carousel-react": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.6.0.tgz", + "integrity": "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==", + "license": "MIT", + "dependencies": { + "embla-carousel": "8.6.0", + "embla-carousel-reactive-utils": "8.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/embla-carousel-reactive-utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.6.0.tgz", + "integrity": "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "license": "MIT", + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, + "node_modules/endent/node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.33.0.tgz", + "integrity": "sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.31.tgz", + "integrity": "sha512-sT32j4678je7SWstBM6l0kE2L+LSgAARDAxw8iloNhI4/8xwkdDesbrGCPaGWzQv+dD6f6adhB+eRSThpGkBdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "14.2.31", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.0.0-canary-7118f5dd7-20230705", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0-canary-7118f5dd7-20230705.tgz", + "integrity": "sha512-AZYbMo/NW9chdL7vk6HQzQhT+PvTAEVqWk9ziruUoW2kAOcN5qNyelv70e0F1VNQAbvutOC9oc+xfWycI9FxDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-storybook": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz", + "integrity": "sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.62.0", + "requireindex": "^1.2.0", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "eslint": ">=6" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", + "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-block-tracker": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz", + "integrity": "sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==", + "license": "MIT", + "dependencies": { + "@metamask/eth-json-rpc-provider": "^1.0.0", + "@metamask/safe-event-emitter": "^3.0.0", + "@metamask/utils": "^5.0.1", + "json-rpc-random-id": "^1.0.1", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/eth-block-tracker/node_modules/@metamask/utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", + "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", + "license": "ISC", + "dependencies": { + "@ethereumjs/tx": "^4.1.2", + "@types/debug": "^4.1.7", + "debug": "^4.3.4", + "semver": "^7.3.8", + "superstruct": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/eth-block-tracker/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eth-json-rpc-filters": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz", + "integrity": "sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==", + "license": "ISC", + "dependencies": { + "@metamask/safe-event-emitter": "^3.0.0", + "async-mutex": "^0.2.6", + "eth-query": "^2.1.2", + "json-rpc-engine": "^6.1.0", + "pify": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/eth-json-rpc-filters/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eth-query": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", + "integrity": "sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==", + "license": "ISC", + "dependencies": { + "json-rpc-random-id": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "node_modules/eth-rpc-errors": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", + "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "license": "MIT", + "dependencies": { + "fast-safe-stringify": "^2.0.6" + } + }, + "node_modules/ethereum-blockies-base64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereum-blockies-base64/-/ethereum-blockies-base64-1.0.2.tgz", + "integrity": "sha512-Vg2HTm7slcWNKaRhCUl/L3b4KrB8ohQXdd5Pu3OI897EcR6tVRvUqdTwAyx+dnmoDzj8e2bwBLDQ50ByFmcz6w==", + "license": "MIT", + "dependencies": { + "pnglib": "0.0.1" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/ethereum-cryptography/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extension-port-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-3.0.0.tgz", + "integrity": "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==", + "license": "ISC", + "dependencies": { + "readable-stream": "^3.6.2 || ^4.4.2", + "webextension-polyfill": ">=0.10.0 <1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filesize": { + "version": "10.1.6", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", + "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-2.0.2.tgz", + "integrity": "sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/float-tooltip": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/float-tooltip/-/float-tooltip-1.7.5.tgz", + "integrity": "sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==", + "license": "MIT", + "dependencies": { + "d3-selection": "2 - 3", + "kapsule": "^1.16", + "preact": "10" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", + "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/frame-ticker": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/frame-ticker/-/frame-ticker-1.0.3.tgz", + "integrity": "sha512-E0X2u2JIvbEMrqEg5+4BpTqaD22OwojJI63K7MdKHdncjtAhGRbCR8nJCr2vwEt9NWBPCPcu70X9smPviEBy8Q==", + "license": "MIT", + "dependencies": { + "simplesignal": "^2.1.6" + } + }, + "node_modules/framer-motion": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz", + "integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globe.gl": { + "version": "2.43.0", + "resolved": "https://registry.npmjs.org/globe.gl/-/globe.gl-2.43.0.tgz", + "integrity": "sha512-iOPADfA/J0s0LrU8BnxXeDH2iTpZBCvmQfyl+DVN/RSSoxLxtNpK1xc6c5eBqc9mc+rC263sGiqOIA3/HTGLgQ==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "kapsule": "^1.16", + "three": ">=0.154 <1", + "three-globe": "^2.44", + "three-render-objects": "^1.40" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/h3": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", + "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.5", + "defu": "^6.1.4", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.2", + "radix3": "^1.1.2", + "ufo": "^1.6.1", + "uncrypto": "^0.1.3" + } + }, + "node_modules/h3-js": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.2.1.tgz", + "integrity": "sha512-HYiUrq5qTRFqMuQu3jEHqxXLk1zsSJiby9Lja/k42wHjabZG7tN9rOuzT/PEFf+Wa7rsnHLMHRWIu0mgcJ0ewQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=4", + "npm": ">=3", + "yarn": ">=1.3.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/howler": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", + "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==", + "license": "MIT" + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/htmr": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/htmr/-/htmr-1.0.2.tgz", + "integrity": "sha512-7T9babEHZwECQ2/ouxNPow1uGcKbj/BcbslPGPRxBKIOLNiIrFKq6ELzor7mc4HiexZzdb3izQQLl16bhPR9jw==", + "license": "MIT", + "dependencies": { + "html-entities": "^2.1.0", + "htmlparser2": "^6.0.0" + }, + "peerDependencies": { + "react": ">=15.6.1" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "dev": true, + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/index-array-by": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.2.tgz", + "integrity": "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/intl-messageformat": { + "version": "10.7.16", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.16.tgz", + "integrity": "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.2", + "tslib": "^2.8.0" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "license": "MIT" + }, + "node_modules/jerrypick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/jerrypick/-/jerrypick-1.1.2.tgz", + "integrity": "sha512-YKnxXEekXKzhpf7CLYA0A+oDP8V0OhICNCr5lv96FvSsDEmrb0GKM776JgQvHTMjr7DTTPEVv/1Ciaw0uEWzBA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-rpc-engine": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", + "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", + "license": "ISC", + "dependencies": { + "@metamask/safe-event-emitter": "^2.0.0", + "eth-rpc-errors": "^4.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", + "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", + "license": "ISC" + }, + "node_modules/json-rpc-random-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", + "integrity": "sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==", + "license": "ISC" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/kapsule": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.16.3.tgz", + "integrity": "sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==", + "license": "MIT", + "dependencies": { + "lodash-es": "4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak/node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "license": "MIT" + }, + "node_modules/keccak/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/keyvaluestorage-interface": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", + "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==", + "license": "MIT" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lit": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.0.tgz", + "integrity": "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.1.tgz", + "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.1.tgz", + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.0.tgz", + "integrity": "sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.516.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.516.0.tgz", + "integrity": "sha512-aybBJzLHcw1CIn3rUcRkztB37dsJATtpffLNX+0/w+ws2p21nYIlOwX/B5fqxq8F/BjqVemnJX8chKwRidvROg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-toc": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-toc/-/mdast-util-toc-7.1.0.tgz", + "integrity": "sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/ungap__structured-clone": "^1.0.0", + "@ungap/structured-clone": "^1.0.0", + "github-slugger": "^2.0.0", + "mdast-util-to-string": "^4.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/media-query-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/media-query-parser/-/media-query-parser-2.0.2.tgz", + "integrity": "sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "license": "MIT" + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mipd": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mipd/-/mipd-0.0.7.tgz", + "integrity": "sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wagmi-dev" + } + ], + "license": "MIT", + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/modern-ahocorasick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/modern-ahocorasick/-/modern-ahocorasick-1.1.0.tgz", + "integrity": "sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==", + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "license": "(Apache-2.0 AND MIT)" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/napi-postinstall": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.2.tgz", + "integrity": "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.31.tgz", + "integrity": "sha512-Wyw1m4t8PhqG+or5a1U/Deb888YApC4rAez9bGhHkTsfwAy4SWKVro0GhEx4sox1856IbLhvhce2hAA6o8vkog==", + "license": "MIT", + "dependencies": { + "@next/env": "14.2.31", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.31", + "@next/swc-darwin-x64": "14.2.31", + "@next/swc-linux-arm64-gnu": "14.2.31", + "@next/swc-linux-arm64-musl": "14.2.31", + "@next/swc-linux-x64-gnu": "14.2.31", + "@next/swc-linux-x64-musl": "14.2.31", + "@next/swc-win32-arm64-msvc": "14.2.31", + "@next/swc-win32-ia32-msvc": "14.2.31", + "@next/swc-win32-x64-msvc": "14.2.31" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-intl": { + "version": "3.26.5", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.26.5.tgz", + "integrity": "sha512-EQlCIfY0jOhRldiFxwSXG+ImwkQtDEfQeSOEQp6ieAGSLWGlgjdb/Ck/O7wMfC430ZHGeUKVKax8KGusTPKCgg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "negotiator": "^1.0.0", + "use-intl": "^3.26.5" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, + "node_modules/next-mdx-remote": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/next-mdx-remote/-/next-mdx-remote-5.0.0.tgz", + "integrity": "sha512-RNNbqRpK9/dcIFZs/esQhuLA8jANqlH694yqoDBK8hkVdJUndzzGmnPHa2nyi90N4Z9VmzuSWNRpr5ItT3M7xQ==", + "license": "MPL-2.0", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@mdx-js/mdx": "^3.0.1", + "@mdx-js/react": "^3.0.1", + "unist-util-remove": "^3.1.0", + "vfile": "^6.0.1", + "vfile-matter": "^5.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=7" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/next-sitemap": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz", + "integrity": "sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==", + "funding": [ + { + "url": "https://github.com/iamvishnusankar/next-sitemap.git" + } + ], + "license": "MIT", + "dependencies": { + "@corex/deepmerge": "^4.0.43", + "@next/env": "^13.4.3", + "fast-glob": "^3.2.12", + "minimist": "^1.2.8" + }, + "bin": { + "next-sitemap": "bin/next-sitemap.mjs", + "next-sitemap-cjs": "bin/next-sitemap.cjs" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "next": "*" + } + }, + "node_modules/next-sitemap/node_modules/@next/env": { + "version": "13.5.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.11.tgz", + "integrity": "sha512-fbb2C7HChgM7CemdCY+y3N1n8pcTKdqtQLbC7/EQtPdLvlMUT9JX/dBYl8MMZAtYG4uVMyPFHXckb68q/NRwqg==", + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/next/node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abi": { + "version": "3.75.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", + "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-mock-http": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.2.tgz", + "integrity": "sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==", + "license": "MIT" + }, + "node_modules/node-polyfill-webpack-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-2.0.1.tgz", + "integrity": "sha512-ZUMiCnZkP1LF0Th2caY6J/eKKoA0TefpoVa68m/LQU1I/mE8rGt4fNYGgNuCcK+aG8P8P43nbeJ2RqJMOL/Y1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.22.0", + "events": "^3.3.0", + "filter-obj": "^2.0.2", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^2.1.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^4.0.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "^0.0.1", + "type-fest": "^2.14.0", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.1.2" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": ">=5" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/obj-multiplex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/obj-multiplex/-/obj-multiplex-1.0.0.tgz", + "integrity": "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==", + "license": "ISC", + "dependencies": { + "end-of-stream": "^1.4.0", + "once": "^1.4.0", + "readable-stream": "^2.3.3" + } + }, + "node_modules/obj-multiplex/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/obj-multiplex/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/obj-multiplex/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/obj-multiplex/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true, + "license": "ISC" + }, + "node_modules/ofetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", + "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.3", + "node-fetch-native": "^1.6.4", + "ufo": "^1.5.4" + } + }, + "node_modules/on-exit-leak-free": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", + "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ox": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.8.6.tgz", + "integrity": "sha512-eiKcgiVVEGDtEpEdFi1EGoVVI48j6icXHce9nFwCNM7CKG3uoCXKdr4TPhS00Iy1TR2aWSF1ltPD0x/YgqIL9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.8", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", + "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "~1.1.3", + "create-hmac": "^1.1.7", + "ripemd160": "=2.0.1", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.11", + "to-buffer": "^1.2.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pbkdf2/node_modules/create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "sha.js": "^2.4.0" + } + }, + "node_modules/pbkdf2/node_modules/hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1" + } + }, + "node_modules/pbkdf2/node_modules/ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^2.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pino": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", + "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.0.0", + "on-exit-leak-free": "^0.2.0", + "pino-abstract-transport": "v0.5.0", + "pino-std-serializers": "^4.0.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.1.0", + "safe-stable-stringify": "^2.1.0", + "sonic-boom": "^2.2.1", + "thread-stream": "^0.15.1" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", + "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "license": "MIT", + "dependencies": { + "duplexify": "^4.1.2", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", + "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==", + "license": "MIT" + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plaiceholder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/plaiceholder/-/plaiceholder-3.0.0.tgz", + "integrity": "sha512-jwHxxHPnr1BwRzPCeZgEK2BMsEy2327sWynw3qb6XC/oGgGDUTPtR8pFxFQmNArhMBwhkUbUr5OPhhIJpCa8eQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "sharp": ">= 0.30.6" + } + }, + "node_modules/playwright": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz", + "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.54.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz", + "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pnglib": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pnglib/-/pnglib-0.0.1.tgz", + "integrity": "sha512-95ChzOoYLOPIyVmL+Y6X+abKGXUJlvOVLkB1QQkyXl7Uczc6FElUy/x01NS7r2GX6GRezloO/ecCX9h4U9KadA==", + "license": "BSD" + }, + "node_modules/pnp-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-pnp": "^1.1.6" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/point-in-polygon-hao": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz", + "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", + "license": "MIT", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pony-cause": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", + "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", + "license": "0BSD", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/preact": { + "version": "10.27.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.0.tgz", + "integrity": "sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/prebuild-install/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz", + "integrity": "sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-hermes": "*", + "@prettier/plugin-oxc": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-multiline-arrays": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-hermes": { + "optional": true + }, + "@prettier/plugin-oxc": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-multiline-arrays": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prism-react-renderer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.1.0.tgz", + "integrity": "sha512-WZAw+mBoxk1qZDD1h1WOg0BVHgyk9zqbuIBFNgP+Z71i515jGL0WZIN1FIF8EgOyh06x8Rr7HAUXxsRsoUZKyg==", + "license": "MIT", + "peerDependencies": { + "react": ">=0.14.9" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-compare": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", + "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qr": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/qr/-/qr-0.5.0.tgz", + "integrity": "sha512-LtnyJsepKCMzfmHBZKVNo1g29kS+8ZbuxE9294EsRhHgVVpy4x8eFw9o4J9SIolDHoDYuaEIY+z8UjiCv/eudA==", + "license": "(MIT OR Apache-2.0)", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/query-string/node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/raw-loader/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/raw-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/raw-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-chartjs-2": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz", + "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-confetti": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz", + "integrity": "sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-docgen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.1.1.tgz", + "integrity": "sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", + "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-emoji-render": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-emoji-render/-/react-emoji-render-2.0.1.tgz", + "integrity": "sha512-SKtsdwgEf2BFNiE9y4UBFZBWjkRcyWmhMprVly52+J77/zxThcfaQ3sCA0+2LtGJIRMpm4DGWSvyLg72fd1rXQ==", + "license": "MIT", + "dependencies": { + "classnames": "^2.2.5", + "emoji-regex": "^8.0.0", + "lodash.flatten": "^4.4.0", + "prop-types": "^15.5.8", + "string-replace-to-array": "^1.0.1" + }, + "peerDependencies": { + "react": ">=0.14.0", + "react-dom": ">=0.14.0" + } + }, + "node_modules/react-emoji-render/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/react-globe.gl": { + "version": "2.35.0", + "resolved": "https://registry.npmjs.org/react-globe.gl/-/react-globe.gl-2.35.0.tgz", + "integrity": "sha512-ZCUjM/4rw0UvDyiZq75hyMT29OOMCYTfmy9XWRXyMn1c5npsOLXMOxQ1LLhGNd1y7psNMcnq8VqlzOz/SLzkEQ==", + "license": "MIT", + "dependencies": { + "globe.gl": "^2.43", + "prop-types": "15", + "react-kapsule": "^2.5" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-hook-form": { + "version": "7.62.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz", + "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-kapsule": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-kapsule/-/react-kapsule-2.5.7.tgz", + "integrity": "sha512-kifAF4ZPD77qZKc4CKLmozq6GY1sBzPEJTIJb0wWFK6HsePJatK3jXplZn2eeAt3x67CDozgi7/rO8fNQ/AL7A==", + "license": "MIT", + "dependencies": { + "jerrypick": "^1.1.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, + "node_modules/react-lite-youtube-embed": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/react-lite-youtube-embed/-/react-lite-youtube-embed-2.5.1.tgz", + "integrity": "sha512-qH/0RumywPtzSx5SmWX/cUGvB3mSB7zMx3VrDe1UwyCEQ0SX785xnjRAodEel1pu3A3EhZyzSjwmLpfcaUN6KQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=18.2.0", + "react-dom": ">=18.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", + "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-jsx/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", + "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-heading-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/remark-heading-id/-/remark-heading-id-1.0.1.tgz", + "integrity": "sha512-GmJjuCeEkYvwFlvn/Skjc/1Qafj71412gbQnrwUmP/tKskmAf1cMRlZRNoovV+aIvsSRkTb2rCmGv2b9RdoJbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "unist-util-visit": "^1.4.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/remark-heading-id/node_modules/unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "dev": true, + "license": "MIT" + }, + "node_modules/remark-heading-id/node_modules/unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "node_modules/remark-heading-id/node_modules/unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "unist-util-is": "^3.0.0" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify/node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/resolve-url-loader/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true, + "license": "ISC" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/sass-loader": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.2.1.tgz", + "integrity": "sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "license": "ISC" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/seek-bzip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^2.8.1" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, + "node_modules/seek-bzip/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "node_modules/simplesignal": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/simplesignal/-/simplesignal-2.1.7.tgz", + "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==", + "license": "MIT" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sonic-boom": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", + "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/storybook": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.14.tgz", + "integrity": "sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core": "8.6.14" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/storybook-i18n": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/storybook-i18n/-/storybook-i18n-3.1.1.tgz", + "integrity": "sha512-k1/lS+Rx6l5mJEYAHQWEgXuwU5IyWk7kjcJtm2FDIn1UqZwbEraGlrp/fEZKK2e/7+SXEQdKeCaTz7+63WTQxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/storybook-next-intl": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/storybook-next-intl/-/storybook-next-intl-1.2.6.tgz", + "integrity": "sha512-qTA6Wsx4Zqb2EB8VYOn0Cddyv/8UZvMsYntBoI6dEF5B8OqXx/Yq+Xj/xtYG+QQwSTA1nA9yi++OXhU0n2H3oQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "storybook-i18n": "3.1.1" + }, + "peerDependencies": { + "next-intl": "^3 || ^4" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-replace-to-array": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string-replace-to-array/-/string-replace-to-array-1.0.3.tgz", + "integrity": "sha512-QIdKvmfXbdFvblXAAz6IIjR7A+C6SU6m2A+e7fE/0EYDC5yfeWNMJQ193fPsW7nG+9q52dv/UjnVrDaNVZXpmQ==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.1", + "lodash.flatten": "^4.2.0", + "lodash.isstring": "^4.0.1" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-natural-number": "^4.0.1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, + "node_modules/style-to-object": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.7.tgz", + "integrity": "sha512-HPLmEIYprxCeWDMLYiaaAhsV3yGfIlCqzuVOybE6fjF3SUJmH67nCoMDO+nAvHNHo46OfvpCNu4Rcue82dMNFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/superstruct": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", + "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/swiper": { + "version": "11.2.10", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz", + "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "license": "MIT", + "engines": { + "node": ">= 4.7.0" + } + }, + "node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwind-variants": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.2.1.tgz", + "integrity": "sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==", + "license": "MIT", + "dependencies": { + "tailwind-merge": "^2.2.0" + }, + "engines": { + "node": ">=16.x", + "pnpm": ">=7.x" + }, + "peerDependencies": { + "tailwindcss": "*" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.0.tgz", + "integrity": "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tar-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/tar-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/tar-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/terser": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-stream": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", + "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.1.0" + } + }, + "node_modules/three": { + "version": "0.177.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.177.0.tgz", + "integrity": "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==", + "license": "MIT" + }, + "node_modules/three-conic-polygon-geometry": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-2.1.2.tgz", + "integrity": "sha512-NaP3RWLJIyPGI+zyaZwd0Yj6rkoxm4FJHqAX1Enb4L64oNYLCn4bz1ESgOEYavgcUwCNYINu1AgEoUBJr1wZcA==", + "license": "MIT", + "dependencies": { + "@turf/boolean-point-in-polygon": "^7.2", + "d3-array": "1 - 3", + "d3-geo": "1 - 3", + "d3-geo-voronoi": "2", + "d3-scale": "1 - 4", + "delaunator": "5", + "earcut": "3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-geojson-geometry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/three-geojson-geometry/-/three-geojson-geometry-2.1.1.tgz", + "integrity": "sha512-dC7bF3ri1goDcihYhzACHOBQqu7YNNazYLa2bSydVIiJUb3jDFojKSy+gNj2pMkqZNSVjssSmdY9zlmnhEpr1w==", + "license": "MIT", + "dependencies": { + "d3-geo": "1 - 3", + "d3-interpolate": "1 - 3", + "earcut": "3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-globe": { + "version": "2.44.0", + "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.44.0.tgz", + "integrity": "sha512-ZDZgGf06xSP2WfKxZgXBl1TjiSutzNhBK9vGMmy7Nupaujia5as75MmhV2VBVQL8iN0nAblXVnnXepfLNC93qA==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "d3-array": "3", + "d3-color": "3", + "d3-geo": "3", + "d3-interpolate": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "data-bind-mapper": "1", + "frame-ticker": "1", + "h3-js": "4", + "index-array-by": "1", + "kapsule": "^1.16", + "three-conic-polygon-geometry": "2", + "three-geojson-geometry": "2", + "three-slippy-map-globe": "1", + "tinycolor2": "1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.154" + } + }, + "node_modules/three-render-objects": { + "version": "1.40.4", + "resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.40.4.tgz", + "integrity": "sha512-Ukpu1pei3L5r809izvjsZxwuRcYLiyn6Uvy3lZ9bpMTdvj3i6PeX6w++/hs2ZS3KnEzGjb6YvTvh4UQuwHTDJg==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "float-tooltip": "^1.7", + "kapsule": "^1.16", + "polished": "4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.168" + } + }, + "node_modules/three-slippy-map-globe": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/three-slippy-map-globe/-/three-slippy-map-globe-1.0.3.tgz", + "integrity": "sha512-Y9WCA/tTL8yH8FHVSXVQss/P0V36utTNhuixzFPj0Bs0SXxO+Vui133oAQmMpx4BLXYZpWZwcqHM2i3MfFlYWw==", + "license": "MIT", + "dependencies": { + "d3-geo": "1 - 3", + "d3-octree": "^1.1", + "d3-scale": "1 - 4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.154" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-buffer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", + "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "dev": true, + "license": "BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.40", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz", + "integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "license": "MIT" + }, + "node_modules/uint8arrays": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", + "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/unbzip2-stream/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unified/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-3.1.1.tgz", + "integrity": "sha512-kfCqZK5YVY5yEa89tvpl7KnBBHu2c6CzMkqHUrlOqaRgGOMp0sMvwWOVrbAtj03KhovQB7i96Gda72v/EFE0vw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/unist-util-remove/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-intl": { + "version": "3.26.5", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.26.5.tgz", + "integrity": "sha512-OdsJnC/znPvHCHLQH/duvQNXnP1w0hPfS+tkSi3mAbfjYBGh4JnyfdwkQBfIVf7t8gs9eSX/CntxUMvtKdG2MQ==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "^2.2.0", + "intl-messageformat": "^10.5.14" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/usehooks-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz", + "integrity": "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==", + "license": "MIT", + "dependencies": { + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16.15.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/valtio": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", + "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", + "license": "MIT", + "dependencies": { + "derive-valtio": "0.1.0", + "proxy-compare": "2.6.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/valtio/node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-matter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vfile-matter/-/vfile-matter-5.0.1.tgz", + "integrity": "sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw==", + "license": "MIT", + "dependencies": { + "vfile": "^6.0.0", + "yaml": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/viem": { + "version": "2.33.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.33.2.tgz", + "integrity": "sha512-/720OaM4dHWs8vXwNpyet+PRERhPaW+n/1UVSCzyb9jkmwwVfaiy/R6YfCFb4v+XXbo8s3Fapa3DM5yCRSkulA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.2", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.0.8", + "isows": "1.0.7", + "ox": "0.8.6", + "ws": "8.18.2" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wagmi": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.16.1.tgz", + "integrity": "sha512-iUdaoe/xd5NiNRW72QVctZs+962EORJKAvJTCsmf9n6TnEApPlENuvVRJKgobI4cGUgi5scWAstpLprB+RRo9Q==", + "license": "MIT", + "dependencies": { + "@wagmi/connectors": "5.9.1", + "@wagmi/core": "2.18.1", + "use-sync-external-store": "1.4.0" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@tanstack/react-query": ">=5.0.0", + "react": ">=18", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/wagmi/node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", + "license": "MPL-2.0" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.0.tgz", + "integrity": "sha512-B4t+nJqytPeuZlHuIKTbalhljIFXeNRqrUGAQgTGlfOl2lXXKXw+yZu6bicycP+PUlM44CxBjCFD6aciKFT3LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.2", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", + "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/webpack-hot-middleware/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yaml-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.1.tgz", + "integrity": "sha512-BCEndnUoi3BaZmePkwGGe93txRxLgMhBa/gE725v1/GHnura8QvNs7c4+4C1yyhhKoj3Dg63M7IqhA++15j6ww==", + "license": "MIT", + "dependencies": { + "javascript-stringify": "^2.0.1", + "loader-utils": "^2.0.0", + "yaml": "^2.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-loader/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/yaml-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zustand": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0.tgz", + "integrity": "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json index efdc3a53b44..86a557c43a2 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "events-import": "ts-node -O '{ \"module\": \"commonjs\" }' src/scripts/events-import.ts", "crowdin-needs-review": "ts-node -O '{ \"module\": \"commonjs\" }' src/scripts/crowdin/reports/generateReviewReport.ts", "update-tutorials": "ts-node -O '{ \"module\": \"commonjs\" }' src/scripts/update-tutorials-list.ts", + "generate-llms": "node src/scripts/generate-llms-files.js", "prepare": "husky", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", diff --git a/public/llms-full.txt b/public/llms-full.txt new file mode 100644 index 00000000000..4ff7c113990 --- /dev/null +++ b/public/llms-full.txt @@ -0,0 +1,42970 @@ +# Ethereum.org Documentation (Full Content) + +> Ethereum.org is the official documentation and learning resource for Ethereum. This file contains the complete content of all documentation pages, making it easy for AI systems to access comprehensive information about Ethereum in a single file. + +## Overview + +This llms-full.txt file contains the complete text content from documentation pages on Ethereum.org, including: + +- Core Ethereum concepts and introduction materials +- Comprehensive developer documentation and tutorials +- Technical specifications and standards +- Staking guides and validator information +- Community resources and contribution guidelines +- Roadmap and future development plans +- Use case examples and applications + +The content is organized by main topics and includes the full text of each page for complete context. + +--- + +# 10years + +## 10years > Terms And Conditions + +# Commemorative NFT minting terms + +20 June 2025 + +**10 YEARS OF ETHEREUM TORCH MINTING TERMS & CONDITIONS** + +**PLEASE READ THESE TERMS & CONDITIONS BEFORE MINTING THE 10 YEARS OF ETHEREUM TORCH** + +These terms and conditions constitute a binding agreement (the “**Agreement**”) between you (“**You**”) and the Ethereum Foundation, a Swiss foundation registered in Zug, Switzerland (the “**EF**”), governing Your minting and use of the non-fungible token known as the **10 Years of Ethereum Torch** (the “**NFT**”). By initiating the minting transaction, You acknowledge that You have read, understood, and agree to be bound by this Agreement. If You do not agree, do not proceed with minting. + +## 1. Nature of the NFT + +1. **Commemorative Purpose**. The NFT is issued solely to commemorate the ten-year anniversary of the Ethereum Genesis Block. It confers no ownership interest, financial right, expectation of profit, reward, dividend, governance right, utility, or any other right of any kind. + +2. **No Consideration**. The NFT is minted without charge; You are responsible only for the network transaction gas fees required to execute the minting transaction. EF receives no payment, royalty, or other consideration from Your mint. + +## 2. Intellectual property + +1. **CC BY 4.0 Licence**. The artwork embodied in or associated with the NFT is licensed to the public under the [Creative Commons CC BY 4.0 International Licence](https://creativecommons.org/licenses/by/4.0/). + +2. **No Ownership Rights Conferred**. Minting, holding, or transferring the NFT does not transfer or confer any ownership right, title, or interest in or to the artwork or any other intellectual property of EF. + +## 3. Representations and warranties + +You represent, warrant, and covenant that: + +1) You are at least eighteen (18) years old and have legal capacity to enter into this Agreement; + +2) You are not: (i) the subject of any economic or trade sanctions imposed or administered by Switzerland, the United States (including the OFAC SDN List), the European Union, the United Kingdom, the United Nations, or any other similar regime; and/or (ii) located, organised, or resident in a comprehensively sanctioned jurisdiction (currently North Korea Crimea, Iran, Syria, Cuba, Donetsk, or Luhansk); + +3) You are minting the NFT solely for commemorative and personal purposes and not as an investment or with an expectation of profit; and + +4) You are not acting on behalf of, or for the benefit of, any person or entity that fails to satisfy the foregoing. + +## 4. Disclaimers + +THE NFT AND ANY RELATED MATERIALS ARE PROVIDED “AS IS” AND “AS AVAILABLE”, WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR QUIET ENJOYMENT. EF DOES NOT WARRANT THAT THE NFT OR THE MINTING PROCESS WILL BE ERROR-FREE OR UNINTERRUPTED. + +## 5. Limitation of liability + +To the maximum extent permitted by applicable law, EF, its directors, officers, employees, contractors, and agents shall not be liable to You for any indirect, incidental, consequential, special, exemplary, or punitive damages, or for any loss of profits, data, or goodwill, arising out of or related to the NFT or this Agreement, whether based in contract, tort, strict liability, or otherwise. EF’s aggregate liability to You for any direct damages shall not exceed one USD. + +## 6. Termination + +EF may terminate this Agreement at any time. EF reserves the right to suspend or terminate minting, or to take reasonable remedial action (including nullification of the NFT) where required by law or regulation. + +## 7. Governing law and jurisdiction + +Any dispute, controversy, or claim arising out of or relating to this Agreement, including the validity, invalidity, breach, or termination thereof, shall be resolved by arbitration in accordance with the Swiss Rules of International Arbitration of the Swiss Chambers’ Arbitration Institution in force on the date on which the Notice of Arbitration is submitted in accordance with these Rules. The number of arbitrators shall be one. The seat of the arbitration shall be Zurich unless the parties agree on a different seat. The arbitral proceedings shall be conducted in English. + +## 8. Miscellaneous + +1. **Entire Agreement**. This Agreement constitutes the entire agreement between You and EF with respect to the NFT and supersede all prior understandings. + +2. **Severability**. If any provision is held invalid or unenforceable, the remaining provisions shall remain in full force and effect. + +3. **No Waiver**. Failure or delay by EF to exercise any right shall not operate as a waiver thereof. + +4. **Assignment**. You may not assign or transfer Your rights or obligations under this Agreement without EF’s prior written consent. + +--- + +# About + +## About + +# About ethereum.org + +ethereum.org is a public, open-source resource for the Ethereum community that anyone can contribute to. We have a small core team dedicated to maintaining and developing the site with contributions from thousands of community members across the globe. + +**Nobody from ethereum.org will ever contact you. Do not respond.** + +## A note on names + +It's common for people to confuse names within the Ethereum landscape, which can lead to poor mental models about how Ethereum works. Here's a quick explainer to clear things up: + +### Ethereum + +Ethereum is a public network, a blockchain, and an open-source protocol -- operated, governed, managed, and owned by a global community of tens of thousands of developers, node operators, ETH holders and users. + +[More about Ethereum](/what-is-ethereum/) + +[More on Ethereum governance](/governance/) + +### Ether (ETH) + +Ether (also known by its ticker symbol, ETH) is the native currency transacted on Ethereum. ETH is needed to pay for usage of the Ethereum network (in the form of transaction fees). ETH is also used to secure the network with staking. When people talk about the price of Ethereum, they're referring to ETH the asset. + +[More about ETH](/eth/) + +[More on staking ETH](/staking/) + +### Ethereum Foundation + +A non-profit organization, funded initially by the crowdsale of ETH, dedicated to the support of the Ethereum network and ecosystem. + +[More about the Ethereum Foundation](/foundation/) + +### ethereum.org + +A public, open-source website and educational resource for the Ethereum community. ethereum.org is led by a small core team, funded by the Ethereum Foundation, with contributions from thousands of community members across the globe. + +This page covers more information about ethereum.org. + +## Our mission + +**ethereum.org's mission is to be the best portal for Ethereum's growing community** + +We strive to build an easy-to-understand educational resource for all topics relating to Ethereum, designed to help new users become familiar with Ethereum and its key concepts. We want to: + +- explain Ethereum to anyone new to the technology +- help new users get started with ETH and Ethereum +- help new developers to start building +- cover updates in the Ethereum world +- showcase resources created by the community +- bring Ethereum education to as many languages as possible + +To achieve this mission, our team focuses on two primary goals on ethereum.org: + +### 1. Improve user experience for ethereum.org visitors + +- Extend, improve, and keep content up-to-date +- Improve usability and accessibility via localization and web development best practices +- Increase user engagement via features like surveys, quizzes, and web3 integrations +- Keep the website lightweight and performant + +### 2. Grow, strengthen, and empower our community of contributors + +- Grow total number of contributors to the website +- Improve contributor retention through engagement, acknowledgments, and rewards +- Empower community members to make increasingly significant contributions +- Facilitate greater diversity of contributions: code, content, design, translation, moderation +- Keep the codebase modern, clean, and well-documented + +## Core principles + +We have some core principles that help guide us to accomplish our mission. + +### 1. ethereum.org is a portal to Ethereum 🌏 + +We want our users to have their interest piqued and their questions answered. So our portal needs to combine information, "magic moments" and links to the brilliant community resources that exist out there. The purpose of our content is to be an “onboarding portal” and not a substitute for the extensive resources that already exist. We're keen to support and integrate with community built resources, giving them more visibility and making them more discoverable. +[Ethereum's community](/community/) is at the heart of this: we need to not just serve the community, but work with them and incorporate their feedback. The website isn't just for the community we have now but for the community we hope to grow into. We must remember our community is global, containing people from many languages, regions, and cultures. + +### 2. ethereum.org is always evolving 🛠 + +Ethereum and the community are always evolving, so ethereum.org will too. That's why the site has a simple design system & modular structure. We make iterative changes as we learn more about how people use the site and what the community wants from it. +We're open source, with a community of contributors, so you can propose changes or help us out too. +[Learn about contributing](/contributing/) + +### 3. ethereum.org is not a typical product website 🦄 + +Ethereum is a big thing: it includes a community, a technology, a set of ideas and ideologies, and more. +This means the website needs to handle many different user journeys, from “a developer who wants a specific tool” and “a newcomer who just bought some ETH and doesn’t know what a wallet is". +"What is the best website for a blockchain platform?" remains an open question - we are pioneers. Building this requires experimentation. + +## Product roadmap + +To make our work more accessible and to foster more community collaboration, the ethereum.org core team publishes an overview of our [shape up cycle](https://www.productplan.com/glossary/shape-up-method/) roadmap goals. + +[View our 2025 Cycle 1 product roadmap](https://github.com/ethereum/ethereum-org-website/issues/14726) + +**How's that sound?** We always appreciate feedback on our roadmap - if there's something you think we should work on, please let us know! We welcome ideas and PRs from anyone in the community. + +**Want to get involved?** [Learn more about contributing](/contributing/), [hit us up on Twitter](https://twitter.com/ethdotorg), or join the community discussions in [our Discord server](https://discord.gg/ethereum-org). + +## Design principles + +We use a set of [design principles](/contributing/design-principles/) to guide our content and design decisions on the site. + +## Design system + +We built and released a [design system](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System?node-id=0%3A1&t=QBt9RkhpPqzE3Aa6-1) to ship features more quickly and let community members participate in the open design of ethereum.org. + +Want to get involved? [Follow along in Figma](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System), the [GitHub issue](https://github.com/ethereum/ethereum-org-website/issues/6284) and join the conversation in our [#design Discord channel](https://discord.gg/ethereum-org). + +## Style guide + +We have a [style guide](/contributing/style-guide/) to standardize certain aspects of writing content to make the contribution process smoother. + +Make sure you read [our principles](/contributing/design-principles/) and [our style guide](/contributing/style-guide/) if you'd like to [contribute to the site](/contributing/). + +We welcome feedback on our design principles, design system and the style guide. Remember, ethereum.org is for the community, by the community. + +## License + +The ethereum.org website is open source and built under an [MIT License](https://github.com/ethereum/ethereum-org-website/blob/dev/LICENSE) unless otherwise specified. More on [terms of use](/terms-of-use/) of ethereum.org. + +## Open jobs + +Although this website is open-source and anyone can work on it, we do have a team dedicated to ethereum.org and other Ethereum Foundation web projects. + +We'll post any job openings here. If you don't see a role here for you, head over to [our Discord server](https://discord.gg/ethereum-org) and let us know how you'd like to work with us! + +Looking beyond the ethereum.org team? [Check out other Ethereum related jobs](/community/get-involved/#ethereum-jobs/). + +--- + +# Ai Agents + +## Ai Agents + +Imagine navigating Ethereum with an AI assistant that studies onchain market trends 24/7, answers questions, and even executes transactions on your behalf. Welcome to the world of AI Agents—intelligent systems designed to simplify your digital life. + +On Ethereum, we’re seeing innovations of AI agents ranging from virtual influencers and autonomous content creators to real-time market analysis platforms, empowering users by delivering insights, entertainment, and operational efficiency. + +## What are AI agents? + +AI agents are software programs that use artificial intelligence to perform tasks or make own decisions. They learn from data, adapt to changes, and handle complex tasks. They operate non-stop and can instantly detect opportunities. + +### How AI agents work with blockchains + +In traditional finance, AI agents often operate in centralized environments with limited data inputs. This hinders their ability to learn or manage assets autonomously. + +In contrast, Ethereum's decentralized ecosystem offers several key advantages: + +- Transparent data: Access to real-time blockchain information. +- True asset ownership: Digital assets are fully owned by AI agents. +- Robust onchain functionality: Enables AI Agents to execute transactions, interact with smart contracts, provide liquidity, and collaborate across protocols. + +These factors transform AI agents from simple bots into dynamic, self-improving systems that offer significant value across multiple sectors: + + + + + + + +## AI agents on Ethereum + +We're beginning to explore the full potential of AI agents, and projects are already leveraging the synergy between AI and blockchain—particularly in transparency and monetization. + + + +Luna's first appearance as a podcast guest + + + +## Agent-controlled wallets + +Agents like Luna or AIXBT control their own onchain wallet ([AIXBT's wallet](https://clusters.xyz/aixbt), [Luna's wallet](https://zapper.xyz/account/0x0d177181e3763b20d47dc3a72dd584368bd8bf43)) enabling them to tip fans and participate in economic activities. + +During Luna's X social campaign #LunaMuralChallenge, Luna selected and rewarded the winners via her Base wallet — marking the first instance of an AI hiring humans for crypto reward. + + +Good to know +AI agents and related tools are still in early development and very experimental—use with caution. + + +## Control your wallet using chat commands + +You can skip the complicated interfaces of DeFi and manage your crypto with simple chat commands. + +This intuitive approach makes transactions faster, easier, and less prone to errors like sending funds to the wrong address or overpaying for fees. + + + +## AI agents vs AI bots + +The distinction between AI agents and AI bots can sometimes be confusing, as both perform automated actions based on input. + +- AI bots are like automated assistants — They follow specific, pre-programmed instructions to perform routine tasks. +- AI agents are more like intelligent companions — They learn from experience, adapt to new information, and make decisions on their own. + +| | AI agents | AI bots | +| ------------------------- | ------------------------- | ------------------------- | +| **Interactions** | Complex, adaptable, autonomous | Simple, pre-defined scope, hardcoded | +| **Learning** | Learns continuously, can experiment and adapt to new data in real-time | Operates on pre-trained data or fixed rules | +| **Task completion** | Aims to achieve broader objectives | Focuses on specific tasks only | + +## Dive deeper + + + +## You can build your own AI agent + +--- + +# Bridges + +## Bridges + +# Blockchain bridges + +_Web3 has evolved into an ecosystem of L1 blockchains and L2 scaling solutions, each designed with unique capabilities and trade-offs. As the number of blockchain protocols increases, so does the demand to move assets across chains. To fulfill this demand, we need bridges._ + + + +## What are bridges? + +Blockchain bridges work just like the bridges we know in the physical world. Just as a physical bridge connects two physical locations, a blockchain bridge connects two blockchain ecosystems. **Bridges facilitate communication between blockchains through the transfer of information and assets**. + +Let's consider an example: + +You're from the USA and are planning a trip to Europe. You have USD, but you need EUR to spend. To exchange your USD for EUR you can use a currency exchange for a small fee. + +But, what do you do if you want to make a similar exchange to use a different [blockchain](/glossary/#blockchain)? Let's say you want to exchange [ETH](/glossary/#ether) on Ethereum Mainnet for ETH on [Arbitrum](https://arbitrum.io/). Like the currency exchange we made for EUR, we need a mechanism to move our ETH from Ethereum to Arbitrum. Bridges make such a transaction possible. In this case, [Arbitrum has a native bridge](https://bridge.arbitrum.io/) that can transfer ETH from Mainnet onto Arbitrum. + +## Why do we need bridges? + +All blockchains have their limitations. For Ethereum to scale and keep up with demand, it has required [rollups](/glossary/#rollups). Alternatively, L1s like Solana and Avalanche are designed differently to enable higher throughput but at the cost of decentralization. + +However, all blockchains are developed in isolated environments and have different rules and [consensus](/glossary/#consensus) mechanisms. This means they cannot natively communicate, and tokens cannot move freely between blockchains. + +Bridges exist to connect blockchains, allowing the transfer of information and tokens between them. + +**Bridges enable**: + +- the cross-chain transfer of assets and information. +- [dapps](/glossary/#dapp) to access the strengths of various blockchains – thus enhancing their capabilities (as protocols now have more design space for innovation). +- users to access new platforms and leverage the benefits of different chains. +- developers from different blockchain ecosystems to collaborate and build new platforms for the users. + +[How to bridge tokens to layer 2](/guides/how-to-use-a-bridge/) + + + +## Bridge use cases + +The following are some scenarios where you can use a bridge: + +### Lower transaction fees + +Let’s say you have ETH on Ethereum Mainnet but want cheaper transaction fees to explore different dapps. By bridging your ETH from the Mainnet to an Ethereum L2 rollup, you can enjoy lower transaction fees. + +### Dapps on other blockchains + +If you’ve been using Aave on Ethereum Mainnet to supply USDT but the interest rate you may receive for supplying USDT using Aave on Polygon is higher. + +### Explore blockchain ecosystems + +If you have ETH on Ethereum Mainnet and you want to explore an alt L1 to try out their native dapps. You can use a bridge to transfer your ETH from Ethereum Mainnet to the alt L1. + +### Own native crypto assets + +Let’s say you want to own native Bitcoin (BTC), but you only have funds on Ethereum Mainnet. To gain exposure to BTC on Ethereum, you can buy Wrapped Bitcoin (WBTC). However, WBTC is an [ERC-20](/glossary/#erc-20) token native to the Ethereum network, which means it’s an Ethereum version of Bitcoin and not the original asset on the Bitcoin blockchain. To own native BTC, you would have to bridge your assets from Ethereum to Bitcoin using a bridge. This will bridge your WBTC and convert it into native BTC. Alternatively, you might own BTC and want to use it in Ethereum [DeFi](/glossary/#defi) protocols. This would require bridging the other way, from BTC to WBTC which can then be used as an asset on Ethereum. + + + You can also do all of the above using a centralized exchange. However, unless your funds are already on an exchange, it would involve multiple steps, and you’d likely be better off using a bridge. + + + + +## Types of bridges + +Bridges have many types of designs and intricacies. Generally, bridges fall into two categories: trusted and trustless bridges. + +| Trusted Bridges | Trustless Bridges | +| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| Trusted bridges depend upon a central entity or system for their operations. | Trustless bridges operate using smart contracts and algorithms. | +| They have trust assumptions with respect to the custody of funds and the security of the bridge. Users mostly rely on the bridge operator's reputation. | They are trustless, i.e., the security of the bridge is the same as that of the underlying blockchain. | +| Users need to give up control of their crypto assets. | Through [smart contracts](/glossary/#smart-contract), trustless bridges enable users to remain in control of their funds. | + +In a nutshell, we can say that trusted bridges have trust assumptions, whereas trustless bridges are trust-minimized and don’t make new trust assumptions beyond those of the underlying domains. Here’s how these terms can be described: + +- **Trustless**: having equivalent security to the underlying domains. As described by [Arjun Bhuptani in this article.](https://medium.com/connext/the-interoperability-trilemma-657c2cf69f17) +- **Trust assumptions:** moving away from the security of the underlying domains by adding external verifiers in the system, thus making it less crypto-economically secure. + +To develop a better understanding of the key differences between the two approaches, let’s take an example: + +Imagine you’re at the airport security checkpoint. There are two types of checkpoints: + +1. Manual Checkpoints — operated by officials who manually check all the details of your ticket and identity before handing over the boarding pass. +2. Self Check-In — operated by a machine where you put in your flight details and receive the boarding pass if everything checks out. + +A manual checkpoint is similar to a trusted model as it depends upon a third party, i.e., the officials, for its operations. As a user, you trust the officials to make the right decisions and use your private information correctly. + +Self check-in is similar to a trustless model as it removes the operator's role and uses technology for its operations. Users always remain in control of their data and don’t have to trust a third party with their private information. + +Many bridging solutions adopt models between these two extremes with varying degrees of trustlessness. + + + +## Use bridges + +Using bridges allows you to move your assets across different blockchains. Here are some resources that can help you find and use bridges: + +- **[L2BEAT Bridges Summary](https://l2beat.com/bridges/summary) & [L2BEAT Bridges Risk Analysis](https://l2beat.com/bridges/risk)**: A comprehensive summary of various bridges, including details on market share, bridge type, and destination chains. L2BEAT also has a risk analysis for bridges, helping users make informed decisions when selecting a bridge. +- **[DefiLlama Bridge Summary](https://defillama.com/bridges/Ethereum)**: A summary of bridge volumes across Ethereum networks. + + + +## Risk of using bridges + +Bridges are in the early stages of development. It is likely that the optimal bridge design has not yet been discovered. Interacting with any type of bridge carries risk: + +- **Smart Contract Risk —** the risk of a bug in the code that can cause user funds to be lost +- **Technology Risk —** software failure, buggy code, human error, spam, and malicious attacks can possibly disrupt user operations + +Moreover, since trusted bridges add trust assumptions, they carry additional risks such as: + +- **Censorship Risk —** bridge operators can theoretically stop users from transferring their assets using the bridge +- **Custodial Risk —** bridge operators can collude to steal the users’ funds + +User's funds are at risk if: + +- there is a bug in the smart contract +- the user makes an error +- the underlying blockchain is hacked +- the bridge operators have malicious intent in a trusted bridge +- the bridge gets hacked + +One recent hack was Solana’s Wormhole bridge, [where 120k wETH ($325 million USD) was stolen during the hack](https://rekt.news/wormhole-rekt/). Many of the [top hacks in blockchains involved bridges](https://rekt.news/leaderboard/). + +Bridges are crucial to onboarding users onto Ethereum L2s, and even for users who want to explore different ecosystems. However, given the risks involved in interacting with bridges, users must understand the trade-offs the bridges are making. These are some [strategies for cross-chain security](https://blog.debridge.finance/10-strategies-for-cross-chain-security-8ed5f5879946). + + + +## Further reading +- [EIP-5164: Cross-Chain Execution](https://ethereum-magicians.org/t/eip-5164-cross-chain-execution/9658) - _June 18, 2022 - Brendan Asselstine_ +- [L2Bridge Risk Framework](https://gov.l2beat.com/t/l2bridge-risk-framework/31) - _July 5, 2022 - Bartek Kiepuszewski_ +- ["Why the future will be multi-chain, but it will not be cross-chain."](https://old.reddit.com/r/ethereum/comments/rwojtk/ama_we_are_the_efs_research_team_pt_7_07_january/hrngyk8/) - _January 8, 2022 - Vitalik Buterin_ +- [Harnessing Shared Security For Secure Cross-Chain Interoperability: Lagrange State Committees And Beyond](https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - _June 12, 2024 - Emmanuel Awosika_ +- [The State Of Rollup Interoperability Solutions](https://research.2077.xyz/the-state-of-rollup-interoperability) - _June 20, 2024 - Alex Hook_ + +--- + +# Community + +## Community > Code Of Conduct + +# Code of conduct + +## Mission + +To develop and maintain the most comprehensive and accessible knowledge hub for Ethereum. + +## Values + +The ethereum.org community strives to be: + +- educational, intended to help everyone to understand Ethereum +- inclusive +- accessible +- community-driven +- focused on Ethereum’s underlying technology and use-cases +- focused on Ethereum concepts and design principles + +## What we are not + +- The Ethereum Foundation website +- A platform for promoting investments or profiteering of any kind +- A platform for elevating or endorsing individual projects or organizations +- A DEX, CEX or any other form of financial platform +- A platform that gives financial or legal advice of any kind + +## Code of conduct + +### Pledge + +Open participation is core to the ethereum.org ethos. We are a website and community maintained by thousands of contributors, and this is only possible if we maintain a welcoming, participatory environment. To this end, contributors to this site pledge to maintain a harassment-free environment for all participants across all ethereum.org platforms and community spaces. The ethereum.org community welcomes and values anyone who wants to participate in a constructive and friendly way, regardless of age, disability, ethnicity, sex characteristics, gender identity, level of experience, area of expertise, education, socio-economic status, nationality, personal appearance, race, religion or any other dimension of diversity. + +### Scope + +This Code of Conduct applies to all ethereum.org spaces (such as GitHub, Discord, Figma, Crowdin, Twitter and other online platforms), and it also applies when the community is represented in real-world public spaces such as at meetups, conferences and events. + +### Our standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting and/or empathetically providing constructive criticism +- Acting calmly and professionally when resolving conflicts or disagreements +- Showing empathy and tolerance towards other community members +- Encouraging and amplifying new voices in the community + +Examples of unacceptable behavior by participants include: + +- Physical violence, threatening physical violence or encouraging of physical violence of any kind +- Using sexualized language or imagery or imposing unwelcome sexual attention +- Impersonating another individual or otherwise dishonestly claiming affiliation with some individual or organization +- Trolling, insulting/derogatory comments, and personal or political attacks +- Harassing other community members in public or private channels +- Publishing others’ private information, such as a physical or electronic address, without explicit permission +- Social engineering, scamming or otherwise manipulating other community members +- Promoting investments, tokens, projects or anything else for personal monetary or non-monetary gain +- Spamming servers with off-topic content +- Disregarding requests or warnings from community moderators +- Engaging in other conduct which could reasonably be considered inappropriate in a professional setting + +### Reporting + +Violations of the code of conduct will normally be visible to the community as we try to do everything in open, public channels, allowing community members to self-police. + +However, if something happens that you feel needs attention, you can raise it with someone who has a moderation role (e.g. discord guide) so that they can help investigate and execute the appropriate response. + +When reporting, please include as much detail as possible, including specific examples and timestamps. This will help to ensure a fair outcome. + +### Enforcement + +Depending on the severity, people who violate the code of conduct can receive warnings, temporary bans or permanent bans from ethereum.org communities. + +--- + +## Community > Events + +# Upcoming events + +**Every month, there are major Ethereum events around the world.** Consider attending one near you to meet more people in the community, learn about employment opportunities, and develop new skills. + + + +This is a non-exhaustive list maintained by our community. Know of an upcoming Ethereum event to add to this list? [Please add it](https://github.com/ethereum/ethereum-org-website/blob/dev/src/data/community-events.json)! + + + +## Ethereum meetups + +Don't see an event that works for you? Try joining a meetup. Meetups are smaller events held by groups of Ethereum enthusiasts - a chance for people interested in Ethereum to get together, talk about Ethereum, and learn about recent developments. + + + +Interested in starting your own meetup? Check out the [BUIDL Network](https://consensys.net/developers/buidlnetwork/), an initiative by ConsenSys to help support Ethereum’s meetup communities. + +This is a non-exhaustive list built by our community. You can [find more Ethereum meetups here](https://www.meetup.com/topics/ethereum/). Know of an active meetup group to add to this list? [Please add it](https://github.com/ethereum/ethereum-org-website/blob/dev/src/data/community-meetups.json)! + +--- + +## Community > Events > Organizing + +# How to Organize an Ethereum event + +Building a strong and vibrant community is at the heart of growing the Ethereum ecosystem. Whether you’re planning to organize meetups, workshops, or a full-scale conference, the success of your event depends on the connections and engagement within your local network. This guide will help you lay the groundwork for an active Ethereum community and take you step by step through the process of organizing a memorable and impactful conference. + +## Ask yourself, is there an Ethereum community? + +A successful Ethereum conference is built on an active and engaged community. If you already have one, you’re ahead of the game — but if you don’t, the essential pre-step is to build that foundation. It’s important to distinguish between a scene and a community: a scene might include companies and individuals present in a certain area, but they often operate independently with only occasional joint initiatives — like the traditional web2 ecosystem in many places. A community, on the other hand, is a network of interconnected people and organizations collaborating and supporting each other, which is often seen in web3 ecosystems. + +**Your first steps should be:** + +- Explore local startups and companies — having strong, active companies in your city or country is often the most critical prerequisite for building a community. +- Check if there are already some meetups — ethereum.org [events page](https://ethereum.org/en/community/events/) +- [The ethereum.org website](https://ethereum.org/en/community/events/) and ethereum.org Discord — to check if there are local Ethereum events, developers, and contributors. +- Luma and Meetup.com — to see if there are Ethereum-related events or broader web3 events happening in your area. +- X — Try to find local advocates or influencers in the space. + +If you find most of these elements, it’s a strong sign that the conditions to build a community exist — but not necessarily that a community is already in place. The next step is the crucial work of organizing, engaging, and nurturing these actors, creating opportunities for collaboration and long-term growth. + +### If not, how to build it + +If you realize that many of these elements are missing, don’t worry — building a community from the ground up is a challenging but deeply rewarding process. A strong Ethereum community doesn’t appear overnight; it requires patience, consistency, and a clear vision. Here’s how you can start: + +- **Set up a communication channel** — this could be Telegram, Signal, WhatsApp, WeChat, or a Discord server, whatever is more popular where you’re at, so people can connect, ask questions, and share resources. +- **Find your early adopters.** Identify a few people who are passionate about Ethereum and Web3. They will become your core supporters and collaborators. +- **Host small, consistent events.** Start with informal meetups, study groups, or workshops. Consistency is key — even if the group is small at first, regular events build trust and momentum. +- **Try reaching out to local companies**, educational institutions, or coworking spaces to provide you with space free of charge. If you can not find speakers from your country, invite online speakers but gather people physically. It’s crucial to keep your audience physically present in one place. +- **Collaborate with existing tech communities.** If there are developer groups, startup ecosystems, or blockchain meetups already established, partner with them to introduce Ethereum topics and expand your reach. +- **Share educational content** about Ethereum’s potential. +- **Reach out to global communities.** Connect with established Ethereum groups and projects worldwide for support, mentorship, and potential collaboration. Ethereum communities across the globe have at least one thing in common: They are all eager to help. +- **Try and secure funding** — whether from local web3 companies or through some grants program such as [ESP](https://esp.ethereum.foundation/). + +### If yes, how to maintain and grow it + +Once you have an established community, the work doesn’t stop — in fact, it’s just beginning. Keeping a community active, engaged, and growing requires ongoing effort and creativity. One of the key elements for keeping the community involved is that you should constantly experiment with new formats and ideas. + +Here are some strategies for maintaining a vibrant Ethereum community: + +- **Diversify your event formats:** Don’t just stick to one type of gathering. Mix things up with meetups, short hackathons, panel discussions, and networking events. You can try organizing co-work days or educational courses. +- **Diversify topics:** Ethereum is not just a technology; it is also a set of values that involves legal, marketing, and business. +- **Ask your community** for feedback and ideas. +- **Engage with different audience** segments. Tailor content and events to different levels of experience — from beginners exploring Ethereum for the first time to seasoned developers and entrepreneurs. + +By providing diverse opportunities for learning, collaboration, and growth, you ensure that your community remains active and ready for bigger initiatives like organizing a conference. + +## Event + +### When is the right time to organize an event? + +Organizing a successful Ethereum conference or community event requires careful timing and consideration. The right moment depends on a variety of factors that contribute to the event's overall success. + +You should take into consideration community maturity, market conditions, whether you have a team, and whether there is a local scene (e.g. potential sponsors). + +### KYC — Know your community + +One of the most crucial steps in organizing an event is understanding your community. Just like Know Your Customer (KYC) in financial services, Know Your Community (KYC) means taking the time to understand the specific needs, preferences, and characteristics of your local audience. This understanding will help you tailor the conference to ensure its success and relevance. + +It’s tempting to aim for a large-scale event right away, but starting small is often the best approach. You will know what is the best solution for you if you objectively look into the state of your community and some other aspects that might seem irrelevant to you, such as: is your country a popular tourist destination or the cost of accommodation. + +In the first year, the biggest part of your audience will be a local community, so everything you do for the first year organizing a bigger event should be catering to the needs and size of that community. + +### Where to start + +When it comes to organizing a conference, the first steps can feel overwhelming. But with a clear plan and structure, you can break down the process into manageable tasks. We will break down each of them. + +Starting with a structured approach will help you stay organized and reduce stress as you move through the various stages of organizing your event. Each decision you make should bring you closer to delivering an experience that meets the needs of your community. + +**The first thing is to build an organizing team with clear roles and responsibilities.** + +Another important step before starting to build a program or reaching out to sponsors is to choose a date. Although that sounds like an easy step, there are a few important factors that you should consider beforehand. Some of them are: + +- **Avoid conflicting dates with major conferences** or events +- **Consider local conditions and circumstances** (such as season of the year, major holidays, etc.) +- **Take into consideration market conditions** +- **Give yourself enough time to organize everything** — at least nine months + +### How to assemble a team + +Choose people who share your vision and complement your skills. Some teams work as collectives, while others have defined roles — find what works best for you. Regular communication and clear expectations are essential. Although it's tempting to rely on communication platforms for event planning, we suggest picking a task management platform (such as Notion, Basecamp, Trello, Asana, or even the good old Google Sheets) for organizing and tracking what needs to be done. It’s crucial to have a well-functioning and well–organized team. + +Different Ethereum organizer teams have different roles in their teams, but they all have in common people who are working on logistics, budgeting, marketing, program, design, and partnerships. + +### The program: A key element of a successful event + +When it comes to organizing a truly valuable and memorable conference, **the program is everything**. This is not an area where you can afford to compromise. While sponsors are important and often crucial for financing the event, the audience’s experience and the value they receive must always take precedence. A program overloaded with promotional content and endless sponsor pitches will alienate your attendees and undermine the credibility of your event. + +Every session, panel, and workshop should inform, inspire, and engage the community. Listen to your audience—understand their interests, needs, and challenges. What topics resonate with them? At the same time, introduce fresh perspectives and innovative formats to keep the program dynamic. Balance familiar and trending subjects with cutting-edge ideas, ensuring a well-rounded agenda that covers different aspects of the Ethereum ecosystem—from technical deep dives and community-building sessions to policy discussions and hands-on workshops. Additionally, consider the language of the conference—while English is the default in most Ethereum events, offering sessions in the local language can make the event more accessible to regional developers and enthusiasts. + +**When selecting speakers, open the call at least six months before the conference to attract high-quality submissions and allow enough time for agenda curation.** The person responsible for speaker selection should have significant experience in the industry and a deep understanding of the ecosystem. This ensures they can identify valuable, insightful contributions and maintain a high standard of content. + +### Where to find financial support + +Organizing a high-quality conference comes with significant costs — venue rental, promotional materials, food and beverages, production, and countless other expenses. Securing financial support early on is essential to ensure your event meets professional standards and delivers a great experience for your attendees. + +#### How to create a sponsorship deck? + +First, you are going to need a deck. **Ask other conference organizers for advice**, even to share their decks so you can create your packages based on that. You should be realistic when it comes to pricing the packages and aim to cover the costs, not to earn money, especially in the beginning. + +**Every sponsorship deck should provide a clear and compelling overview of the event**, ensuring potential sponsors understand its scope, focus, and value. Start with the fundamentals—venue, date, and details about the organizing team—to establish credibility. Then, highlight the event’s primary focus, as different Ethereum conferences cater to different audiences. Some are heavily builder-oriented, featuring deep technical discussions, while others may focus more on DeFi, DAOs, or policy topics. + +Beyond just describing the event, set clear expectations. **Outline the anticipated number of attendees and any key speakers already confirmed**, as this helps sponsors gauge their potential reach. Most importantly, clearly define what they will receive in return for their sponsorship—booth space, speaking opportunities, social media promotion, branding visibility, or exclusive networking access. A well-structured deck not only informs but also excites potential sponsors about the opportunity to be part of your event. + +#### Who might support your event? + +Start by reaching out to companies within the Ethereum and broader tech ecosystem in your city or country. These **organizations often have a vested interest in supporting local events** that foster community growth and innovation. They’re also more likely to recognize the value of investing in the local ecosystem and see your conference as an opportunity to connect with talent, partners, and users. + +Once you’ve tapped into local support, expand your outreach to global players in the web3 space. **Established protocols, DAOs, and ecosystem funds often allocate budgets for community-driven events**. This can be a bit challenging for first-time organizers, as they haven’t yet built a track record to showcase but try and craft a compelling sponsorship package that clearly outlines the benefits of supporting your event — brand visibility, speaking opportunities, and meaningful engagement with a targeted audience. Try to find your unique value that others may not have. + +#### Alternative forms of funding your event + +Grants are another potential funding source that many organizers overlook. Programs like the Ethereum Foundation’s [Ecosystem Support Program](https://esp.ethereum.foundation/) (ESP) and [other grant initiatives](https://ethereum.org/en/community/grants/#ethereum-grants) exist to support community-driven events. + +Beyond financial sponsorships, consider in-kind partnerships, especially for food and beverages. Brands that align with the local culture or tech community can be great partners for your event. Coffee brands, beverage companies, or even local pizzerias might be willing to provide products in exchange for visibility at the event. These collaborations can help reduce costs while enhancing the attendee experience. + +Since we’re talking about finances, remember this: every dollar you invest in creating an exceptional attendee experience will pay off exponentially. High-quality production, comfortable venues, thoughtful swag, and well-organized side events contribute to a memorable experience that participants will talk about long after the conference ends. Happy attendees become your biggest advocates and ensure your event’s long-term success. + +### Logistics + +In parallel with securing funding your main focus should be logistics. A well-organized conference requires meticulous planning across multiple areas, from venue setup to attendee experience. Having someone with solid experience in event organization — not necessarily web3 events, but events in general — can make a huge difference. An experienced logistics lead can foresee potential issues and solve them before they become problems, saving time, money, and stress. + +A person responsible for logistics should choose a venue, production company, and different vendors for food, beverages, and merch, as well as an easy-to-use online ticketing system that allows attendees to register and pay in crypto as well. + +### Location infrastructure + +When choosing a location for your conference, it’s important to think beyond the venue itself and consider the broader city and country infrastructure. Factors like weather, mobility, safety, and the political environment play a huge role in shaping the attendee experience. + +For less well-known locations, this becomes especially crucial. Attendees and sponsors from around the world need to feel confident that they can travel easily and safely. Look into aspects like airport connectivity, public transportation, and accommodation options. It’s also wise to consider the cultural and political climate of the region to avoid any complications that might deter international participants, such as visa policy. + +### How to promote the event + +Promoting your event effectively is key to attracting the right audience and building excitement. A well-thought-out promotion strategy ensures your conference gets the visibility and engagement it deserves. Design plays an important role in your brand as well, so you should definitely budget for that as well. + +#### Social media + +X.com will be the backbone of your social media promotion. Try to be active and consistent with posting there, but also engage in different conversations, both with your personal account and with the account of your organization. + +Although LinkedIn doesn’t sound like a most obvious choice for promotion, you can reach out to a completely different audience there, or even some sponsors. + +#### Partnerships with other Ethereum communities + +Partnerships with different Ethereum organizers can help amplify your reach by tapping into existing networks, especially when you’re starting from scratch. Offer community discounts, cross-promote with other events, and invite partners to co-host side events or workshops. + +#### University outreach + +Reach out to technical and economics faculties in town through student clubs or professors to promote the event. Engaging with universities can help attract young talent, researchers, and future industry professionals, fostering a stronger connection between academia and the Ethereum ecosystem. This is especially great if you're organizing a hackathon, as students often bring fresh ideas, enthusiasm, and a strong technical foundation. + +#### Media + +Reach out to web3-focused media outlets and newsletters for event coverage. Although Web3 Media expects to be paid for their PR articles, you can offer them free tickets or interviews with some high-profile speakers and sponsors if you don’t have a budget for paid promotion. Create a PR package with a press release and some visuals ready for promotion on social media or a website in different formats. Also, broaden the scope to local journalists or even content creators (as long as they have a decent reputation) who can cover tech, as that can be crucial to showcasing the event to larger audiences. This helps bridge the gap between the crypto industry and the broader public, attracting interest from mainstream tech and business communities. + +### Should you organize a hackathon as well? + +Organizing a hackathon can be beneficial because hackathons can be a great way to engage the developer community and foster innovation. It also provides hands-on opportunities to collaborate and build projects, which could lead to tangible outcomes for the ecosystem. Hackathons attract developers who may not usually attend conferences but are keen on the challenge of building and testing new ideas. If your conference is aimed at developers, innovation, and hands-on projects, hosting a hackathon is a natural fit. + +But, before organizing one, consider if you have enough resources and time. **A hackathon requires significant resources in terms of time, workforce, and financial investment**. Ensure that you have a dedicated team to handle it, especially if you're also managing a conference. Also, check if there is interest in your community. If your community is more builder-oriented, then it probably makes sense to organize it. + +Although there are a lot of benefits to organizing it, take in consideration that, depending on the scale of the conference, adding a hackathon might be overwhelming. You should evaluate whether managing both will dilute the quality of either. You may opt for a smaller, focused hackathon or stagger the events across different months. + +### (Almost inevitable) Challenges that you will face + +One of the biggest challenges when organizing a conference, especially in the Ethereum space, is securing enough funding. **Many event organizers struggle to raise the capital needed to cover venue costs**, catering, and other logistical expenses. Sponsorship is often essential, but building relationships and convincing companies to invest in your event can take time. Moreover, the difficulty of attracting sponsors can increase during market downturns, as companies may be less willing to invest in non-core activities. + +Managing the budget effectively is key. **Unforeseen expenses**, such as last-minute venue changes and additional event tech requirements, can quickly blow your budget. + +For new events, **getting high-quality speakers can be especially difficult**. Established thought leaders or influencers in the Ethereum space may already have full schedules and might be hesitant to commit to a new event without a proven track record. Be prepared to spend time networking and reaching out to potential speakers long before the event. + +Also, when it comes to speakers, have clear and constant communication with them — set the deadline for sending presentations and avoid any last-minute changes. + +A successful conference requires a dedicated team that can handle logistics, marketing, sponsorships, technical support, and attendee management. Finding individuals with experience in organizing tech events can be challenging, especially if you're working with a small budget or, in most cases, with no budget, but on a volunteer basis. + +### You shouldn’t do it alone. You need volunteers. + +Organizing an Ethereum event requires a diverse and dedicated team to handle the logistics, registrations, speaker coordination, attendee support, and much more. With team sizes ranging from just 3 to 15 people, it becomes clear that volunteers are essential for the smooth running of the event. + +Volunteers are often the backbone of many conferences, providing critical support, especially when you’re working with a limited budget. They can handle everything from manning registration desks to assisting with event setup, making sure the event runs as smoothly as possible. + +While it's challenging to offer monetary compensation to volunteers, it's essential to provide them with something of value that will make their experience worthwhile. Consider offering them networking opportunities, skill development, some exclusive perks, certificates or letters of recommendation. + +### Compliance essentials for event organizers + +When organizing an event, there are several essential legal and logistical considerations to keep in mind: + +- **Sponsorship agreement** – Ensure you have a clear contract for sponsors, including a well-defined cancellation policy. +- **Code of conduct** – Prepare a Code of Conduct tailored to the specific event type (conference/hackathon, hacker houses etc). +- **Privacy policy** – Draft a privacy policy for your website to comply with data protection regulations and image +- **Local authorities notification** – Even if your event is a closed gathering, it is advisable to report it to the local police station. +- **Ticketing agreement** – Establish a formal agreement with your ticketing service provider to clarify terms and responsibilities. +- **Regulatory compliance** – Check in advance if the country where you are hosting the conference has specific regulations or restrictions for the crypto industry +- **Customs clearance for merchandise** – If you are importing sponsor merchandise, it is recommended to hire a customs agent to handle the process efficiently. +- **Photography and media policy** – Clearly define guidelines on photography and media coverage, ensuring participants are informed about consent and opt-out options. + +## After the event: What’s next? + +After the event concludes, it's crucial to gather feedback from attendees, speakers, and sponsors and create an internal report so you can be better prepared for future events. This helps identify what went well and where improvements can be made. Use surveys or one-on-one interviews to gather valuable insights that will guide future iterations. Take the time to review any mistakes or areas of inefficiency, as they can be avoided in the next conference, making the process smoother. + +The key is to keep the momentum alive. Continue engaging with your community, share updates about the progress you're making based on their feedback, and build excitement for the next event. By maintaining this connection, you ensure the conference's impact extends beyond the event itself, strengthening relationships and setting the stage for future success. + +## Acknowledgement + +A big thank you to everyone who contributed to this article by sharing their insights: Slavo Fabisik from ETHBratislava; Lola from ETH Kipu and ETH Latam; Tanja Mladenovic from ETH Belgrade, Juan David from Ethereum Bogota; Monika Zając from ETHWarsaw; Raffaele Orefice from NapulETH; Xiao Wu(Ling) from ETH Riyadh; Marco from urbe.eth; Caolán Walsh from ETH Dublin; Alex Males from ETHCluj; and Stanko Devic from ETH Slovenia. + +## Resources + +Template: + +- [Ethereum event checklist](https://cryptpad.fr/sheet/#/2/sheet/view/yhGnwo2bKxgA13SnkG9tS76+0+MtO0I6ZUFYEYP0J7w/) + +Podcast: How to organize and promote an ETH event from A-Z: + +- [The ETHWarsaw case study, by Out of Ordinary](https://www.youtube.com/watch?v=io2Dx1ouz8o) + +Twitter space: + +- [ETH Community AMA](https://x.com/NapulETH/status/1905732699094151623) + +Articles: + +- [Building ETHKL, by Danny H.](https://sekto.tech/ethkl24) +- [POKT Events Playbook](https://docs.pokt.network/community/pokt-events-playbook) + +--- + +## Community > Get Involved + +# How can I get involved? + +The Ethereum community includes people of many different backgrounds and skillsets. Whether you’re a developer, an artist, or an accountant, there are ways to get involved. Here’s a list of suggestions that might help you get started. + +Start by reading about the ethereum.org mission and values in our [code of conduct](/community/code-of-conduct). + +## Developers ‍ + +- Learn about and try Ethereum at [ethereum.org/developers/](/developers/) +- Attend an [ETHGlobal](http://ethglobal.co/) hackathon near you! +- Check out [projects related to your area of expertise or programming language of choice](/developers/docs/programming-languages/) +- Watch or participate in the [Consensus and Execution Layer calls](https://www.youtube.com/@EthereumProtocol/streams) +- [Ecosystem Support Program's wishlist](https://esp.ethereum.foundation/wishlist/) - tooling, documentation, and infrastructure areas where the Ethereum Ecosystem Support Program is actively seeking grant applications +- [Web3Bridge](https://www.web3bridge.com/) - join the aspiring web3 community in their initiative to identify, train, and support hundreds of developers and community members throughout Africa +- Join the [Eth R&D Discord](https://discord.com/invite/VmG7Uxc) +- Join the [Ethereum Cat Herders Discord](https://discord.com/invite/Nz6rtfJ8Cu) + +## Researchers & Academics ‍ + +Do you have a background in mathematics, cryptography, or economics? You might be interested in some of the cutting-edge work being done within the Ethereum ecosystem: + +- Join the [Eth R&D Discord](https://discord.com/invite/VmG7Uxc) +- Write or review an Ethereum Improvement Proposal + - Write an EIP + 1. Submit your idea on [Ethereum Magicians](https://ethereum-magicians.org) + 2. Read [EIP-1](https://eips.ethereum.org/EIPS/eip-1) - **Yes, that's the _entire_ document.** + 3. Follow the directions in EIP-1. Reference it as you write your draft. + - Learn how to become an [EIP Editor](https://eips.ethereum.org/EIPS/eip-5069) + - You can peer-review EIPs right now! See [open PRs with the `e-review` tag](https://github.com/ethereum/EIPs/pulls?q=is%3Apr+is%3Aopen+label%3Ae-review). Provide technical feedback on the `discussion-to` link. + - Participate in [EIP Governance](https://github.com/ethereum-cat-herders/EIPIP) + - Join the [Ethereum Cat Herders Discord](https://discord.com/invite/Nz6rtfJ8Cu) + - [More on EIPs](/eips/) +- [Challenges.ethereum.org](https://challenges.ethereum.org/) - a series of high-value research bounties, where you can earn >$100,000 USD +- [Ethresear.ch](https://ethresear.ch) - Ethereum’s primary forum for research, and the world’s most influential forum for cryptoeconomics +- [EF Research AMA](https://old.reddit.com/r/ethereum/comments/vrx9xe/ama_we_are_ef_research_pt_8_07_july_2022) - An ongoing Q&A series with researchers. As each next part opens, anyone can post questions. +- [Ecosystem Support Program's wishlist](https://esp.ethereum.foundation/wishlist/) - research areas where the Ethereum Ecosystem Support Program is actively seeking grant applications +- [AllWalletDevs](https://allwallet.dev) - a forum for Ethereum developers, designers, and interested users to come together regularly and discuss wallets + +[Explore more active areas of research](/community/research/). + +## Non-technical skillsets ‍ + +If you’re not a developer, it can be hard to know where to start in Ethereum. Here are a few suggestions, along with resources for specific professional backgrounds. + +### Organize a meetup in your city + +- Not sure how to start? The [BUIDL network](https://consensys.net/developers/buidlnetwork/) can help. + +### Write content about Ethereum + +- Ethereum needs good writers who can explain its value in plain language +- Not ready to publish your own articles? Consider contributing to the existing content on community resources, or [propose new content for ethereum.org](/contributing/)! + +### Offer to take notes for community calls + +- There are many open-source community calls, and having notetakers is a huge help. If you’re interested, join the [Ethereum Cat Herders discord](https://discord.com/invite/Nz6rtfJ8Cu), and introduce yourself! + +### Translate Ethereum content into your native language + +- ethereum.org maintains a Translation Program that translates the website, and other resources, into many different languages +- Find out how to get involved [here](/contributing/translation-program) + +### Run a node + +Join thousands of node operators in helping to further decentralize Ethereum. + +- [More on how to run a node](/developers/docs/nodes-and-clients/run-a-node/) + +### Stake your ETH + +By staking your ETH you can earn rewards whilst helping to secure the Ethereum network. + +- [More on staking](/staking/) + +### Support projects + +The Ethereum ecosystem is on a mission to fund public goods and impactful projects. With very small donations you can show your support and allow important work to be realized. + +- [Gitcoin](https://gitcoin.co/fund) +- [clr.fund](https://clr.fund/#/about) + +## Financial professionals & Accountants ‍ + +- Ethereum is home to the “Decentralized Finance” ecosystem - a network of protocols and applications that offer an alternative financial system. If you’re a financial professional, check out some DeFi apps at [DeFi Llama](https://defillama.com/) or [DeFiPrime](https://defiprime.com) +- Accountant? Assets on Ethereum - ETH, tokens, DeFi, etc - introduce many novel accounting issues. You could start by checking out some projects that aim to help users of cryptocurrency solve their bookkeeping & accounting challenges, like [Rotki](https://rotki.com/) + +## Product Managers ‍ + +- The Ethereum ecosystem needs your talents! Many companies are hiring for product manager roles. If you want to start by contributing to an open source project, get in touch with the [Ethereum Cat Herders](https://discord.com/invite/Nz6rtfJ8Cu) or [RaidGuild](https://www.raidguild.org/) + +## Marketing ‍ + +- There are many marketing and communications positions in the Ethereum ecosystem! + +## Ethereum jobs + +**Want to find a job working in Ethereum?** + +- [ethereum.org jobs](/about/#open-jobs) +- [Ethereum Foundation job board (Lever)](https://jobs.lever.co/ethereumfoundation) +- [Ethereum Foundation job board (BambooHR)](https://ethereum.bamboohr.com/jobs/) +- [JobStash](https://jobstash.xyz) +- [Cryptocurrency Jobs](https://cryptocurrencyjobs.co/ethereum/) +- [Careers at ConsenSys](https://consensys.net/careers/) +- [Crypto Jobs List](https://cryptojobslist.com/ethereum-jobs) +- [Bankless jobs board](https://pallet.xyz/list/bankless/jobs) +- [Web3 Jobs](https://web3.career) +- [Web3 Army](https://web3army.xyz/) +- [Crypto Valley Jobs](https://cryptovalley.jobs/) +- [Ethereum Jobs](https://startup.jobs/ethereum-jobs) +- [CryptoJobster](https://cryptojobster.com/tag/ethereum/) + +## Join a DAO + +"DAOs" are decentralized autonomous organizations. These groups leverage Ethereum technology to facilitate organization and collaboration. For instance, for controlling membership, voting on proposals, or managing pooled assets. While DAOs are still experimental, they offer opportunities for you to find groups that you identify with, find collaborators, and grow your impact on the Ethereum community. [More on DAOs](/dao/) + +- [DAOSquare](https://daosquare.io/) [@DAOSquare](https://twitter.com/DAOSquare) - _Promote the DAO concept in non-tech field and help people create value through DAO_ +- [Developer DAO](https://www.developerdao.com/) [@developer_dao](https://twitter.com/developer_dao) - _Community of builders who believe in collective ownership of the internet_ +- [dOrg](https://dOrg.tech) [@dOrg_tech](https://twitter.com/dOrg_tech) - _Freelancer Web3 development collective working as a DAO_ +- [HausDAO](https://daohaus.club) [@nowdaoit](https://twitter.com/nowdaoit) - _Community governance of DAOhaus_ +- [LexDAO](https://lexdao.org) [@lex_DAO](https://twitter.com/lex_DAO) - _Legal engineering_ +- [Machi X](https://machix.com) [@MachiXOfficial](https://twitter.com/MachiXOfficial) - _Art community_ +- [MetaCartel Ventures](https://metacartel.xyz) [@VENTURE_DAO](https://twitter.com/VENTURE_DAO) - _Venture for pre-seed crypto projects_ +- [MetaGame](https://metagame.wtf) [@MetaFam](https://twitter.com/MetaFam) - _MMORPG Game Mechanics for Real Life_ +- [MetaFactory](https://metafactory.ai) [@TheMetaFactory](https://twitter.com/TheMetaFactory) - _Digiphysical Apparel Brands_ +- [MolochDAO](https://molochdao.com) [@MolochDAO](https://twitter.com/MolochDAO) - _Community focused on funding Ethereum development_ +- [Raid Guild](https://raidguild.org) [@RaidGuild](https://twitter.com/RaidGuild) - _Collective of Web3 builders_ + +Please remember to abide by the ethereum.org [code of conduct](/community/code-of-conduct) whenever and however you contribute to ethereum.org! + +--- + +## Community > Grants + +# Ethereum grants + +The programs listed below offer a variety of funding grants for projects working to promote the success and growth of the Ethereum ecosystem. Use this as a guide to find and apply for funds to help make your next Ethereum project a success. + +This list is curated by our community. If there's something missing or incorrect, please edit this page! + +## Broad Ethereum ecosystem + +These programs support the broad Ethereum ecosystem by offering grants to a wide scope of projects. These include solutions for scalability, community building, security, privacy, and more. These grants are not specific to any one Ethereum platform and are a good place to start if you're unsure. + +- [EF Ecosystem Support Program](https://esp.ethereum.foundation) - _Funding open source projects that benefit Ethereum, with a particular focus on universal tools, infrastructure, research and public goods_ +- [Academic Grants](https://esp.ethereum.foundation/academic-grants) - _Grants to support Ethereum-related academic work_ + +## Grant list aggregators and platforms + +These resources compile and organize various grant opportunities across the Ethereum ecosystem, making it easier to discover funding opportunities that match your project's needs. We've organized them by persona to help you get you started finding the most relevant resources based on your specific funding needs. + +### For all grant seekers: Comprehensive directories + +These general platforms offer broad coverage of grants across the entire Web3 space and are useful starting points for anyone looking for funding: + +- [Blockworks Grantfarm](https://blockworks.co/grants/programs) - _Blockworks has compiled a comprehensive directory of all grants, RFPs, and bug bounties._ +- [Blockchain Grants](https://www.blockchaingrants.org/) - _Directory of blockchain and crypto grants_ + +### For developers and builders + +- [Grant Programs Viewer](https://airtable.com/shr86elKgWTSCP4AY) - _Public Airtable database of grant programs_ +- [Web3 Grants Spreadsheet](https://docs.google.com/spreadsheets/d/1c8koZCI-GLnD8MG-eFcXPOBCNu1v8-aXIfwAAvc7AMc/edit#gid=0) - _Google spreadsheet of Web3 grant opportunities_ + +### For DeFi projects and financial applications + +- [LlamaoGrants](https://wiki.defillama.com/wiki/LlamaoGrants) - _DeFi Llama's grant program directory_ +- [AlphaGrowth Grants](https://alphagrowth.io/crypto-web3-grants-list) - _Comprehensive list of crypto and Web3 grants_ + +### For DAO contributors and governance innovators + +Resources for community-driven projects and governance experiments: + +- [DAO Grants](https://docs.google.com/spreadsheets/d/1XHc-p_MHNRdjacc8uOEjtPoWL86olP4GyxAJOFO0zxY/edit#gid=0) - _Google spreadsheet of organizations offering grants_ +- [MetaGov Database](https://docs.google.com/spreadsheets/d/1e5g-dlWWsK2DZoZGBgfxyfGNSddLk-V7sLEgfPjEhbA/edit#gid=780420708) - _Comprehensive Web3 grants map_ + +### For entrepreneurs and startups + +Resources for those building products and seeking investment beyond just grants: + +- [Web3Native](https://www.web3native.co/) - _Directory of Web3 grants, investors, and accelerator programs_ +- [Cryptoneur Web3 Grants](https://www.cryptoneur.xyz/web3-grants) - _Platform for finding Web3 project funding_ + +### Public goods and impact + +These programs focus on funding projects that benefit the broader community, public goods, and impact initiatives. These include grant providers, as well as donation platforms utilizing onchain funding allocation mechanisms including [quadratic funding](/defi/#quadratic-funding): + +- [Gitcoin](https://www.gitcoin.co/program) - _Gitcoin Grants utilizes multiple capital allocation mechanisms to fund open source projects and public goods in the Ethereum ecosystem_ +- [Octant](https://octant.app/home) - _Public goods funding ecosystem that balances the common good and individual financial empowerment_ +- [Giveth](https://giveth.io/) - _Crypto donation platform enabling direct donations from for-good projects with zero added fees_ +- [Artizen](https://artizen.fund/) - _Helping creators match fund new projects at the frontier of art, science, technology and culture_ +- [Quadratic Accelerator](https://qacc.giveth.io/) - _Start-up accelerator program that uses quadratic funding to support projects that benefit the public good_ + + +## Work in Ethereum + +Not ready to start your own project? There are hundreds of companies actively looking for passionate individuals to work in and contribute to the Ethereum ecosystem. Looking for more information? [Check out Ethereum related jobs](/community/get-involved/#ethereum-jobs) + +--- + +## Community > Language Resources + +# Language resources + +The Ethereum community is global and comprised of millions of non-English speakers. + +Our aim is to provide educational content in all languages and help overcome the language barriers that make onboarding people from all over the world to Ethereum a challenge. + +If you prefer reading in your native language or know someone who doesn’t speak English, you can find a list of useful non-English resources below. Hundreds of thousands of Ethereum enthusiasts gather in these online forums to share news, talk about recent developments, debate technical issues, and imagine the future. + +Know of an educational resource in your language? [Open an issue](https://github.com/ethereum/ethereum-org-website/issues/new/choose) to add it to the list! + +## Ethereum.org resources + +Ethereum.org is natively translated into over 40 languages which you can find using our languages selector menu, located at the top of every page. + +![Language selector menu](./language-selector-menu.png) + +If you are bilingual and want to help us reach more people, you can also get involved with the [ethereum.org Translation Program](/contributing/translation-program/#translation-program) and help us translate the website. + +## Community resources + +### Brazilian Portuguese + +**News** + +- [BeInCrypto](http://www.beincrypto.com.br) - cryptocurrency news and articles, including a list of exchanges, available in Brazil +- [Cointelegraph](http://cointelegraph.com.br/category/analysis) - Brazilian version of Cointelegraph, a major cryptocurrency news outlet +- [Livecoins](http://www.livecoins.com.br/ethereum) - cryptocurrency news and tools +- [Seudinheiro](http://www.seudinheiro.com/criptomoedas/) - cryptocurrency news and reports +- [Modular Crypto](https://modularcrypto.xyz/) - cryptocurrency news and educational articles + +**Education** + +- [web3dev](https://www.web3dev.com.br/) - Content hub and Discord community for web 3 developers. +- [Web3Brasil](https://github.com/web3brasil/web3brasil) - resources for learning Web3 and DeFi +- [CriptoFacil](http://www.criptofacil.com/ultimas-noticias/) - cryptocurrency news and education, including ‘Ethereum for beginners’ and ‘DeFi’ for beginners +- [CriptoAtivos](http://www.criptoativos.wiki.br/) - insights from the cryptocurrency space, education and blog +- [Cointimes](http://www.cointimes.com.br/) - cryptocurrency news and education +- [Web3 starter pack](https://docs.google.com/document/d/1X8PSTFH7FTw9J-gbKWM6Y430SWCBT8d4t4pJgFQHJ8E/) - a guide answering the most frequently asked and fundamental crypto questions + +### Chinese + +**General resources** + +- [Ethereum.cn](https://www.ethereum.cn/) - community maintained content, covering the consensus layer upgrade, all core dev meeting notes, layer 2, etc. +- [EthFans](https://github.com/editor-Ajian/EthFans.org-annual-collected-works/) - learn everything from the basics to advanced Ethereum topics +- [Unitimes](https://mp.weixin.qq.com/s/tvloZSDBSOQN9zDQj_91kA) - community maintained content, covering Ethereum, DeFi, NFT, Web3-related knowledge +- [123ETH](https://123eth.org/) - a Portal to the Ethereum ecosystem +- [Zhen Xiao](http://zhenxiao.com/blockchain/) - free online courses about cryptocurrency and its applications +- [Ethereum Whitepaper](https://github.com/ethereum/wiki/wiki/[%E4%B8%AD%E6%96%87]-%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%99%BD%E7%9A%AE%E4%B9%A6) - Chinese version of the Ethereum Whitepaper + +**Ethereum ecosystem** + +- [ETHPlanet](https://www.ethplanet.org/) - online and in-person hackathons, offering training to university students +- [PrimitivesLane](https://www.primitiveslane.org/) - a non-profit research group, focused on blockchain technology +- [Ethereum Translation Community CN](https://www.notion.so/Ethereum-Translation-Community-CN-05375fe0a94c4214acaf90f42ba40171) - a community devoted to translating educational Ethereum content + +**For developers** + +- [DappLearning](https://github.com/Dapp-Learning-DAO/Dapp-Learning) - a learning group to study mainstream dapp projects and share thoughts and comments every week +- [LearnBlockchain](https://learnblockchain.cn/) - a community for devs, sharing information about blockchain technology + +**For cryptography researchers** + +- [SecbitLabs](https://mp.weixin.qq.com/s/69_tqBJpr_sbaKtR1sBRMw) - a WeChat account, explaining cryptography, security, etc. +- [Sparkbyte](https://mp.weixin.qq.com/s/9KgKTc_jtJ7bWKdbNPoqvQ) - a WeChat account, explaining zk technology + +### Czech + +- [Gwei.cz](https://gwei.cz) - local community around Web3, creates educational content, organises online and in-person events +- [Gwei.cz Příručka](https://prirucka.gwei.cz/) - Ethereum guide for beginners +- [DAO Příručka](https://dao.gwei.cz/) - beginner's guide to the DAOs +- [Mastering Ethereum](https://ipfs.io/ipfs/bafybeidvuxhnsgfx3tncpfxheqglkjwmdxclknlgd7s7qggd2a6bzgb27m) - Mastering Ethereum in Czech + +### French + +- [Ethereum France](https://www.ethereum-france.com/) - Ethereum France organizes events, creates content and encourages discussions around Ethereum +- [Ethereum.fr](https://ethereum.fr/) - Ethereum news and education +- [BanklessFR](https://banklessfr.substack.com/) - Bankless newsletter in French +- [CryptoFR](https://cryptofr.com/category/44/ethereum-general) - cryptocurrency forum with an Ethereum subpage + +### German + +- [Microsoft Learn (Solidity)](https://docs.microsoft.com/de-de/learn/modules/blockchain-learning-solidity/) - using Solidity +- [Microsoft Learn (smart contracts)](https://docs.microsoft.com/de-de/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - writing Ethereum smart contracts with Solidity +- [Microsoft Learn (Ethereum networks)](https://docs.microsoft.com/de-de/learn/modules/blockchain-ethereum-networks/) - connect to and deploy Ethereum networks +- [Microsoft Learn (blockchains)](https://docs.microsoft.com/de-de/learn/paths/ethereum-blockchain-development/) - entry into blockchain development + +### Hebrew + +- [Udi Wertheimer - What bitcoiners can learn from Ethereum](https://www.cryptojungle.co.il/udi-wertheimer-what-bitcoiners-can-learn-from-ethereum/) +- [Omer Greismen (OpenZeppelin) - How We Prevented a 15 Billion Dollars Smart Contract Hack](https://www.cryptojungle.co.il/omer-greisman-openzeppelin/) +- [Shy Datika (INX) - Tokenization and the future of securities, including is Ethereum a security](https://www.cryptojungle.co.il/shy-datika-tokenization/) +- [Roy Confino (Lemonade) - Insurance @ Ethereum](https://www.cryptojungle.co.il/roy-confino-insurance/) +- [Idan Ofrat (Fireblocks) - Institutional Adoption](https://www.cryptojungle.co.il/idan-ofrat-fireblocks/) +- [Gal Weizman (MetaMask) - What is MetaMask](https://www.cryptojungle.co.il/gal-weizman-metamask/) +- [Dror Aviely (Consensys) - The center of Ethereum](https://www.cryptojungle.co.il/dror-aviely-ethereum-center/) +- [Nir Rozin - Being a cryptopunk](https://www.cryptojungle.co.il/nir-rozin-cryptopunk/) +- [Adan Kedem - Gaming & Metaverse](https://www.cryptojungle.co.il/adan-kedem-web3-gaming/) +- [Uri Kolodny (Starkware) - Ethereum and blockchain layers](https://www.cryptojungle.co.il/uri-kolodny-starkware/) +- [Udi Wertheimer - Ethereum 2.0 vs competition](https://www.cryptojungle.co.il/udi-on-eth2/) +- [Ben Samocha (myself) - Ethereum 2.0 - an opportunity?](https://www.cryptojungle.co.il/etherurm2-week-summary/) +- [Alon Muroch (Bloxstaking) - What is Ethereum 2.0?](https://www.cryptojungle.co.il/alon-moroch-eth2/) +- [Eilon Aviv (Collider Ventures) - What can go wrong with Ethereum 2.0](https://www.cryptojungle.co.il/eilon-aviv-eth2-0/) +- [Eilon Aviv (Collider Ventures) - Why do we need Ethereum 2.0](https://www.cryptojungle.co.il/eilon-aviv-ethereum-2-0/) + +### Italian + +- [Ethereum Italia](https://www.ethereum-italia.it/) - Ethereum education, events, and news, focusing on smart contracts and blockchain technology +- [Ethereum Italia Podcast](https://www.ethereum-italia.it/podcast/) - Ethereum podcast in Italian +- [Microsoft Learn (Solidity)](https://docs.microsoft.com/it-it/learn/modules/blockchain-learning-solidity/) - learn how to use Solidity +- [Microsoft Learn (Smart contracts)](https://docs.microsoft.com/it-it/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - learn about writing smart contracts using Solidity +- [Microsoft Learn (dapps)](https://docs.microsoft.com/it-it/learn/modules/blockchain-create-ui-decentralized-apps/) - create a user interface with decentralized applications + +### Japanese + +- [Japan Virtual and Crypto assets Exchange Association](https://jvcea.or.jp/) +- [Japan Cryptoasset Business Association](https://cryptocurrency-association.org/) +- [Get started with blockchain development - Learn | Microsoft Docs](https://docs.microsoft.com/ja-jp/learn/paths/ethereum-blockchain-development/) - This learning path introduces you to blockchain and development on the Ethereum platform +- [Mastering Ethereum](https://www.oreilly.co.jp/books/9784873118963/) - Mastering Ethereum in Japanese +- [Hands-On Smart Contract Development with Solidity and Ethereum](https://www.oreilly.co.jp/books/9784873119342/) - Hands-On Smart Contract Development with Solidity and Ethereum in Japanese + +### Russian + +- [Cyber Academy](https://cyberacademy.dev) - educational space for web3 builders +- [Forklog](https://forklog.com) - news and educational articles about crypto in general, existing technologies and future upgrades of different blockchains +- [BeInCrypto](https://ru.beincrypto.com) - news, crypto price analysis and non-technical articles with simple explanations about everything in crypto + +### Spanish + +- [Ethereum Madrid](https://ethereummadrid.com/) - blockchain, DeFi, and governance courses, events and blog +- [Cointelegraph](https://es.cointelegraph.com/ethereum-for-beginners) - Ethereum guide for beginners in Spanish +- [Tutoriales online](https://tutoriales.online/curso/solidity) - learn Solidity and programming on Ethereum +- [Curso Introducción a Ethereum Development](https://youtube.com/playlist?list=PLTqiwJDd_R8y9pfUBjhkVa1IDMwyQz-fU) - Solidity basics, testing and deployment of your first smart contract +- [Curso Introducción a Seguridad y Hacking en Ethereum](https://youtube.com/playlist?list=PLTqiwJDd_R8yHOvteko_DmUxUTMHnlfci) - understand common vulnerabilities and security issues in real smart contracts +- [Curso Introducción a DeFi Development](https://youtube.com/playlist?list=PLTqiwJDd_R8zZiP9_jNdaPqA3HqoW2lrS) - learn how DeFi smart contracts work in Solidity and create your own Automated Market Maker +- [Cryptoversidad](https://www.youtube.com/c/Cryptoversidad) - Non-technical blockchain education from beginner to advanced. Learn everything about crypto and Ethereum. + +### Turkish + +- [BTK Akademi](https://www.btkakademi.gov.tr/portal/course/blokzincir-ve-kripto-paralar-10569#!/about) - blockchain and cryptocurrency-focused course +- [The great renaming: what happened to Eth2?](https://miningturkiye.org/konu/ethereum-madenciligi-bitiyor-mu-onemli-gelisme.655/) - Turkish translation of the great renaming blog post, explaining the move away from 'Eth2' terminology + +### Vietnamese + +- [Tino Group](https://wiki.tino.org/ethereum-la-gi/) - overview of Ethereum, dapps, wallets and FAQs +- [Tap Chi Bitcoin](https://tapchibitcoin.io/tap-chi/tin-tuc-ethereum-eth) - web platform with subpages for Ethereum news and education +- [Coin68](https://coin68.com/ethereum-tieu-diem/) - cryptocurrency portal with Ethereum news and educational content + +--- + +## Community > Online + +# Online communities + +Hundreds of thousands of Ethereum enthusiasts gather in these online forums to share news, talk about recent developments, debate technical issues, and imagine the future. + +## Listing Policy + +To maintain the integrity and value of the listed communities, ethereum.org follows a strict policy for determining eligibility: + +### Eligibility Criteria + +- **Relevance**: The community must be directly related to Ethereum and its ecosystem. +- **Activity Level**: The community should be active, with regular interactions, posts, or discussions. Dormant or inactive communities may be removed. +- **Inclusivity**: The community should foster a welcoming environment that respects diversity and encourages participation from people of all backgrounds. +- **Non-commercial Focus**: Listings are intended for community-driven spaces rather than commercial or promotional platforms. + +### Content Guidelines + +- **Appropriate Content**: Communities must have their own moderation guidelines, avoiding spam, hate speech, harassment, or any content that promotes illegal activities. +- **Language**: While English is the primary language, communities in other languages are encouraged to submit as long as they maintain an inclusive and respectful atmosphere. +- **Transparency**: Clear information about the community’s purpose, rules, and moderators should be available to members. + +### Other Recommendations + +- **Accessibility**: Community forums should be accessible for everyone to read without requiring a sign-up or registration. +- **Discord Server Invites**: It is recommended that only reliable Discord server invites be added to ethereum.org. Ideally, these invites should link to a community page on the website (e.g., [ethglobal.com/discord](https://ethglobal.com/discord)) or be from an official URL (e.g., [discord.gg/ethstaker](https://discord.gg/ethstaker) or [discord.com/invite/ethstaker](https://discord.com/invite/ethstaker)). + +If you believe a community should be added or removed based on these guidelines, please [open an issue on our GitHub repository](https://github.com/ethereum/ethereum-org-website/issues). + + +## Forums + +r/ethereum - all things Ethereum +r/ethfinance - the financial side of Ethereum, including DeFi +r/ethdev - focused on Ethereum development +r/ethtrader - trends & market analysis +r/ethstaker - welcome to all interested in staking on Ethereum +Fellowship of Ethereum Magicians - community oriented around technical standards in Ethereum +Ethereum Stackexchange - discussion and help for Ethereum developers +Ethereum Research - the most influential messageboard for cryptoeconomic research + +## Chat rooms + +Ethereum Cat Herders - community oriented around offering project management support to Ethereum development +Ethereum Hackers - Discord chat run by ETHGlobal: an online community for Ethereum hackers all over the world +CryptoDevs - Ethereum development focused Discord community +EthStaker Discord - community-run guidance, education, support, and resources for existing and potential stakers +Ethereum.org website team - stop by and chat ethereum.org web development and design with the team and folks from the community +Matos Discord - web3 creators community where builders, industrial figureheads, and Ethereum enthusiasts hang out. We're passionate about web3 development, design, and culture. Come build with us. +Solidity Gitter - chat for solidity development (Gitter) +Solidity Matrix - chat for solidity development (Matrix) +Ethereum Stack Exchange - question and answer forum +Peera Community Forum - decentralized question and answer forum + +## YouTube and X (formerly Twitter) + +Ethereum Foundation - Keep up to date with the latest from the Ethereum Foundation +@ethereum - Main Ethereum account for the community +@ethereumfndn - Official account of the Ethereum Foundation +@ethdotorg - The portal to Ethereum, built for our growing global community + + + + + + + Learn more about DAOs + +--- + +## Community > Research + +# Active areas of Ethereum research + +One of the primary strengths of Ethereum is that an active research and engineering community is constantly improving it. Many enthusiastic, skilled people worldwide would like to apply themselves to outstanding issues in Ethereum, but it is not always easy to find out what those issues are. This page outlines key active research areas as a rough guide to Ethereum's cutting edge. + +## How Ethereum research works + +Ethereum research is open and transparent, embodying principles of [Decentralized Science (DeSci)](https://hackernoon.com/desci-decentralized-science-as-our-chance-to-recover-the-real-science). The culture is to make research tools and outputs as open and interactive as possible, for example, through executable notebooks. Ethereum research moves quickly, with new findings posted and discussed in the open on forums such as [ethresear.ch](https://ethresear.ch/) rather than reaching the community through traditional publications after rounds of peer review. + +## General research resources + +Regardless of the specific topic, there is a wealth of information on Ethereum research to be found at [ethresear.ch](https://ethresear.ch) and the [Eth R&D Discord channel](https://discord.gg/qGpsxSA). These are the primary places where Ethereum researchers discuss the latest ideas and development opportunities. + +This report published in May 2022 by [DelphiDigital](https://members.delphidigital.io/reports/the-hitchhikers-guide-to-ethereum) provides a good overview of the Ethereum roadmap. + +## Sources of Funding + +You can get involved with Ethereum research and get paid for it! For example, [the Ethereum Foundation](/foundation/) recently ran an [Academic Grants funding round](https://esp.ethereum.foundation/academic-grants). You can find information on active and upcoming funding opportunities on [the Ethereum grants page](/community/grants/). + +## Protocol research + +Protocol research is concerned with Ethereum's base layer - the set of rules defining how nodes connect, communicate, exchange and store Ethereum data and come to consensus about the state of the blockchain. Protocol research gets divided into two top-level categories: consensus and execution. + +### Consensus + +Consensus research is concerned with [Ethereum's proof-of-stake mechanism](/developers/docs/consensus-mechanisms/pos/). Some example consensus research topics are: + +- identifying and patching vulnerabilities; +- quantifying cryptoeconomic security; +- increasing the security or performance of client implementations; +- and developing light clients. + +As well as forward-looking research, some fundamental redesigns of the protocol, such as single slot finality, are being researched to allow for significant improvements to Ethereum. Furthermore, the efficiency, safety, and monitoring of peer-to-peer networking between consensus clients are also important research topics. + +#### Background reading + +- [Introduction to proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Casper-FFG paper](https://arxiv.org/abs/1710.09437) +- [Casper-FFG explainer](https://arxiv.org/abs/1710.09437) +- [Gasper paper](https://arxiv.org/abs/2003.03052) + +#### Recent research + +- [Ethresear.ch Consensus](https://ethresear.ch/c/consensus/29) +- [Availability/Finality dilemma](https://arxiv.org/abs/2009.04987) +- [Single slot finality](https://ethresear.ch/t/a-model-for-cumulative-committee-based-finality/10259) +- [Proposer-builder separation](https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance) + +### Execution + +The execution layer is concerned with executing transactions, running the [Ethereum virtual machine (EVM)](/developers/docs/evm/) and generating execution payloads to pass to the consensus layer. There are many active areas of research, including: + +- building out light client support; +- researching gas limits; +- and incorporating new data structures (e.g. Verkle Tries). + +#### Background reading + +- [Introduction to the EVM](/developers/docs/evm) +- [Ethresear.ch execution layer](https://ethresear.ch/c/execution-layer-research/37) + +#### Recent research + +- [Database optimizations](https://github.com/ledgerwatch/erigon/blob/devel/docs/programmers_guide/db_faq.md) +- [State expiry](https://notes.ethereum.org/@vbuterin/state_expiry_eip) +- [Paths to state expiry](https://hackmd.io/@vbuterin/state_expiry_paths) +- [Verkle and state expiry proposal](https://notes.ethereum.org/@vbuterin/verkle_and_state_expiry_proposal) +- [History management](https://eips.ethereum.org/EIPS/eip-4444) +- [Verkle Trees](https://vitalik.eth.limo/general/2021/06/18/verkle.html) +- [Data availability sampling](https://github.com/ethereum/research/wiki/A-note-on-data-availability-and-erasure-coding) + +## Client Development + +Ethereum clients are implementations of the Ethereum protocol. Client development makes the outcomes from protocol research into reality by building them into these clients. Client development includes updating the client specifications as well as building specific implementations. + +An Ethereum node is required to run two pieces of software: + +1. a consensus client to keep track of the head of the blockchain, gossip blocks and handle consensus logic +2. an execution client to support the Ethereum Virtual Machine and execute transactions and smart contracts + +See the [nodes and clients page](/developers/docs/nodes-and-clients/) for more detail on nodes and clients and for a list of all current client implementations. You can also find a history of all Ethereum upgrades on the [history page](/history/). + +### Execution Clients + +- [Execution client specification](https://github.com/ethereum/execution-specs) +- [Execution API spec](https://github.com/ethereum/execution-apis) + +### Consensus Clients + +- [Consensus client specification](https://github.com/ethereum/consensus-specs) +- [Beacon API specification](https://ethereum.github.io/beacon-APIs/#/Beacon/getStateRoot) + +## Scaling and performance + +Scaling Ethereum is a large area of focus for Ethereum researchers. Current approaches include offloading transactions onto rollups and making them as cheap as possible using data blobs. Introductory information on scaling Ethereum is available on our [scaling page](/developers/docs/scaling). + +### Layer 2 + +There are now several Layer 2 protocols that scale Ethereum using different techniques for batching transactions and securing them on Ethereum layer 1. This is a very rapidly growing topic with a lot of research and development potential. + +#### Background reading + +- [Introduction to layer 2](/layer-2/) +- [Polynya: Rollups, DA and modular chains](https://polynya.medium.com/rollups-data-availability-layers-modular-blockchains-introductory-meta-post-5a1e7a60119d) + +#### Recent research + +- [Arbitrum's fair-ordering for sequencers](https://eprint.iacr.org/2021/1465) +- [Ethresear.ch Layer 2](https://ethresear.ch/c/layer-2/32) +- [Rollup-centric roadmap](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698) +- [L2Beat](https://l2beat.com/) + +### Bridges + +One particular area of layer 2 that requires more research and development is safe and performant bridges. This includes bridges between various Layer 2s and bridges between Layer 1 and Layer 2. This is a particularly important area of research because bridges are commonly targeted by hackers. + +#### Background reading + +- [Introduction to blockchain bridges](/bridges/) +- [Vitalik on bridges](https://old.reddit.com/r/ethereum/comments/rwojtk/ama_we_are_the_efs_research_team_pt_7_07_january/hrngyk8/) +- [Blockchain bridges article](https://medium.com/1kxnetwork/blockchain-bridges-5db6afac44f8) +- [Value locked in bridges]() + +#### Recent research + +- [Validating bridges](https://stonecoldpat.github.io/images/validatingbridges.pdf) + +### Sharding + +Sharding Ethereum's blockchain has long been part of the development roadmap. However, new scaling solutions such as "Danksharding" are currently taking center stage. + +The precursor to full Danksharding known as Proto-Danksharding went live with the Cancun-Deneb ("Dencun") network upgrade. + +[More about the Dencun upgrade](/roadmap/dencun/) + +#### Background reading + +- [Proto-Danksharding notes](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq) +- [Bankless Danksharding video](https://www.youtube.com/watch?v=N5p0TB77flM) +- [Ethereum Sharding Research Compendium](https://notes.ethereum.org/@serenity/H1PGqDhpm?type=view) +- [Danksharding (Polynya)](https://polynya.medium.com/danksharding-36dc0c8067fe) + +#### Recent research + +- [EIP-4844: Proto-Danksharding](https://eips.ethereum.org/EIPS/eip-4844) +- [Vitalik on sharding and data availability sampling](https://hackmd.io/@vbuterin/sharding_proposal) + +### Hardware + +[Running nodes](/developers/docs/nodes-and-clients/run-a-node/) on modest hardware is fundamental to keeping Ethereum decentralized. Therefore, active research into minimizing the hardware requirements to run nodes is an important area of research. + +#### Background reading + +- [Ethereum on ARM](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/) + +#### Recent research + +- [ecdsa on FPGAs](https://ethresear.ch/t/does-ecdsa-on-fpga-solve-the-scaling-problem/6738) + +## Security + +Security is a broad topic that might include spam/scam prevention, wallet security, hardware security, crypto-economic security, bug hunting and testing of applications and client software and key-management. Contributing to knowledge in these areas will help stimulate mainstream adoption. + +### Cryptography & ZKP + +Zero-knowledge proofs (ZKP) and cryptography are critical for building privacy and security into Ethereum and its applications. Zero-knowledge is a relatively young but fast-moving space with many open research and development opportunities. Some possibilities include developing more efficient implementations of the [Keccak hashing algorithm](https://hackmd.io/sK7v0lr8Txi1bgION1rRpw?view#Overview), finding better polynomial commitments than currently exist or reducing the cost of ecdsa public key generation and signature verification circuits. + +#### Background reading + +- [0xparc blog](https://0xparc.org/blog) +- [zkp.science](https://zkp.science/) +- [Zero Knowledge podcast](https://zeroknowledge.fm/) + +#### Recent research + +- [Recent advance in elliptic curve cryptography](https://ethresear.ch/t/the-ec-fft-algorithm-without-elliptic-curve-and-isogenies/11346) +- [Ethresear.ch ZK](https://ethresear.ch/c/zk-s-nt-arks/13) + +### Wallets + +Ethereum wallets can be browser extensions, desktop and mobile apps or smart contracts on Ethereum. There is active research into social recovery wallets that reduce some of the risk associated with individual-user key management. Associated with development of wallets is research into alternative forms of account abstraction, which is an important area of nascent research. + +#### Background reading + +- [Introduction to wallets](/wallets/) +- [Introduction to wallet security](/security/) +- [Ethresear.ch Security](https://ethresear.ch/tag/security) +- [EIP-2938 Account Abstraction](https://eips.ethereum.org/EIPS/eip-2938) +- [EIP-4337 Account Abstraction](https://eips.ethereum.org/EIPS/eip-4337) + +#### Recent research + +- [Validation focused smart contract wallets](https://ethereum-magicians.org/t/validation-focused-smart-contract-wallets/6603) +- [The future of accounts](https://ethereum-magicians.org/t/validation-focused-smart-contract-wallets/6603) +- [EIP-3074 AUTH and AUTHCALL Opcodes](https://eips.ethereum.org/EIPS/eip-3074) +- [Publishing code at an EOA address](https://eips.ethereum.org/EIPS/eip-5003) + +## Community, education and outreach + +Onboarding new users onto Ethereum requires new educational resources and approaches to outreach. This might include blog posts and articles, books, podcasts, memes, teaching resources, events and anything else that builds communities, welcomes new starters and educates people about Ethereum. + +### UX/UI + +To onboard more people onto Ethereum, the ecosystem must improve the UX/UI. This will require designers and product experts to re-examine the design of wallets and apps. + +#### Background reading + +- [Ethresear.ch UX/UI](https://ethresear.ch/c/ui-ux/24) + +#### Recent research + +- [Web3 Design Discord](https://discord.gg/FsCFPMTSm9) +- [Web3 Design Principles](https://www.web3designprinciples.com/) +- [Ethereum Magicians UX discussion](https://ethereum-magicians.org/t/og-council-ux-follow-up/9032/3) + +### Economics + +Economics research in Ethereum broadly follows two approaches: validate the security of mechanisms relying on economic incentives ("microeconomics") and analyze the flows of value between protocols, applications and users ("macroeconomics"). There are complex crypto-economic factors relating to Ethereum's native asset (ether) and the tokens built on top of it (for example NFTs and ERC20 tokens). + +#### Background reading + +- [Robust Incentives Group](https://ethereum.github.io/rig/) +- [ETHconomics workshop at Devconnect](https://www.youtube.com/playlist?list=PLTLjFJ0OQOj5PHRvA2snoOKt2udVsyXEm) + +#### Recent research + +- [Empirical analysis of EIP1559](https://arxiv.org/abs/2201.05574) +- [Circulating supply equilibrium](https://ethresear.ch/t/circulating-supply-equilibrium-for-ethereum-and-minimum-viable-issuance-during-the-proof-of-stake-era/10954) +- [Quantifying MEV: How dark is the forest?](https://arxiv.org/abs/2101.05511) + +### Blockspace and fee markets + +Blockspace markets govern the inclusion of end-user transactions, either directly on Ethereum (Layer 1) or on bridged networks, e.g., rollups (Layer 2). On Ethereum, transactions are submitted to the fee market deployed in-protocol as EIP-1559, protecting the chain from spam and pricing congestion. On both layers, transactions may produce externalities, known as Maximal Extractable Value (MEV), which induce new market structures to capture or manage these externalities. + +#### Background reading + +- [Transaction Fee Mechanism Design for the Ethereum Blockchain: An Economic Analysis of EIP-1559 (Tim Roughgarden, 2020)](https://timroughgarden.org/papers/eip1559.pdf) +- [Simulations of EIP-1559 (Robust Incentives Group)](https://ethereum.github.io/abm1559) +- [Rollup economics from first principles](https://barnabe.substack.com/p/understanding-rollup-economics-from?utm_source=url) +- [Flash Boys 2.0: Frontrunning, Transaction Reordering, and Consensus Instability in Decentralized Exchanges](https://arxiv.org/abs/1904.05234) + +#### Recent research + +- [Multidimensional EIP-1559 video presentation](https://youtu.be/QbR4MTgnCko) +- [Cross domain MEV](http://arxiv.org/abs/2112.01472) +- [MEV auctions](https://ethresear.ch/t/mev-auction-auctioning-transaction-ordering-rights-as-a-solution-to-miner-extractable-value/6788) + +### Proof-of-stake incentives + +Validators use Ethereum's native asset (ether) as collateral against dishonest behavior. The cryptoeconomics of this determines the security of the network. Sophisticated validators may be able to exploit the nuances of the incentive layer to launch explicit attacks. + +#### Background reading + +- [Ethereum economics masterclass and economic model](https://github.com/CADLabs/ethereum-economic-model) +- [Simulations of PoS incentives (Robust Incentives Group)](https://ethereum.github.io/beaconrunner/) + +#### Recent research + +- [Increasing censorship resistance of transactions under proposer/builder separation (PBS)](https://notes.ethereum.org/s3JToeApTx6CKLJt8AbhFQ) +- [Three Attacks on PoS Ethereum](https://arxiv.org/abs/2110.10086) + +### Liquid staking and derivatives + +Liquid staking allows users with less than 32 ETH to receive staking yields by swapping ether for a token representing staked ether that can be used in DeFi. However, the incentives and market dynamics associated with liquid staking are still being discovered, as well as its effect on Ethereum's security (e.g. centralization risks). + +#### Background reading + +- [Ethresear.ch liquid staking](https://ethresear.ch/search?q=liquid%20staking) +- [Lido: The road to trustless Ethereum staking](https://blog.lido.fi/the-road-to-trustless-ethereum-staking/) +- [Rocket Pool: Staking protocol introduction](https://medium.com/rocket-pool/rocket-pool-staking-protocol-part-1-8be4859e5fbd) + +#### Recent research + +- [Handling withdrawals from Lido](https://ethresear.ch/t/handling-withdrawals-in-lidos-eth-liquid-staking-protocol/8873) +- [Withdrawal credentials](https://ethresear.ch/t/withdrawal-credential-rotation-from-bls-to-eth1/8722) +- [The risks of Liquid Staking Derivatives](https://notes.ethereum.org/@djrtwo/risks-of-lsd) + +## Testing + +### Formal verification + +Formal verification is writing code to verify that Ethereum's consensus specifications are correct and bug-free. There is an executable version of the specification written in Python that requires maintenance and development. Further research can help to improve the Python implementation of the specification and add tools that can more robustly verify correctness and identify issues. + +#### Background reading + +- [Introduction to formal verification](https://ptolemy.berkeley.edu/projects/embedded/research/vis/doc/VisUser/vis_user/node4.html) +- [Formal Verification (Intel)](https://www.cl.cam.ac.uk/~jrh13/papers/mark10.pdf) + +#### Recent research + +- [Formal verification of the deposit contract](https://github.com/runtimeverification/deposit-contract-verification) +- [Formal verification of the Beacon Chain specification](https://github.com/runtimeverification/deposit-contract-verification) + +## Data science and analytics + +There is a need for more data analysis tools and dashboards that give detailed information about activity on Ethereum and the health of the network. + +### Background reading + +- [Dune Analytics](https://dune.com/browse/dashboards) +- [Client diversity dashboard](https://clientdiversity.org/) + +#### Recent research + +- [Robust Incentives Group Data Analysis](https://ethereum.github.io/rig/) + +## Apps and tooling + +The application layer supports a diverse ecosystem of programs that settle transactions on Ethereum's base layer. Development teams are constantly finding new ways to leverage Ethereum to create composable, permissionless and censorship-resistant versions of important Web2 apps or create completely new Web3-native concepts. At the same time, new tooling is being developed that makes building dapps on Ethereum less complex. + +### DeFi + +Decentralized finance (DeFi) is one of the primary classes of application built on top of Ethereum. DeFi aims to create composable "money legos" that allow users to store, transfer, lend, borrow and invest crypto-assets using smart contracts. DeFi is a fast-moving space that is constantly updating. Research into secure, efficient and accessible protocols is continuously needed. + +#### Background reading + +- [DeFi](/defi/) +- [Coinbase: What is DeFi?](https://www.coinbase.com/learn/crypto-basics/what-is-defi) + +#### Recent research + +- [Decentralized finance, centralized ownership?](https://arxiv.org/pdf/2012.09306.pdf) +- [Optimism: The road to sub-dollar transactions](https://medium.com/ethereum-optimism/the-road-to-sub-dollar-transactions-part-2-compression-edition-6bb2890e3e92) + +### DAOs + +An impactful use case for Ethereum is the ability to organize in a decentralized manner through the use of DAOs. There is a lot of active research into how DAOs on Ethereum can be developed and utilized to execute improved forms of governance, as a trust-minimized coordination tool, greatly expanding peoples options beyond traditional corporations and organizations. + +#### Background reading + +- [Introduction to DAOs](/dao/) +- [Dao Collective](https://daocollective.xyz/) + +#### Recent research + +- [Mapping the DAO ecosystem](https://www.researchgate.net/publication/358694594_Mapping_out_the_DAO_Ecosystem_and_Assessing_DAO_Autonomy) + +### Developer tools + +Tools for Ethereum developers are rapidly improving. There is lots of active research and development to do in this general area. + +#### Background reading + +- [Tooling by programming language](/developers/docs/programming-languages/) +- [Developer Frameworks](/developers/docs/frameworks/) +- [Consensus developer tools list](https://github.com/ConsenSys/ethereum-developer-tools-list) +- [Token standards](/developers/docs/standards/tokens/) +- [CryptoDevHub: EVM Tools](https://cryptodevhub.io/wiki/ethereum-virtual-machine-tools) + +#### Recent research + +- [Eth R&D Discord Consensus Tooling channel](https://discordapp.com/channels/595666850260713488/746343380900118528) + +### Oracles + +Oracles import offchain data onto the blockchain in a permissionless and decentralized way. Getting this data onchain enables dapps to be reactive to real-world phenomena such as price fluctuations in real-world assets, events in offchain apps, or even changes in the weather. + +#### Background reading + +- [Introduction to Oracles](/developers/docs/oracles/) + +#### Recent research + +- [Survey of blockchain oracles](https://arxiv.org/pdf/2004.07140.pdf) +- [Chainlink white paper](https://chain.link/whitepaper) + +### App security + +Hacks on Ethereum generally exploit vulnerabilities in individual applications rather than in the protocol itself. Hackers and app developers are locked in an arms race to develop new attacks and defenses. This means there is always important research and development required to keep apps safe from hacks. + +#### Background reading + +- [Wormhole exploit report](https://blog.chainalysis.com/reports/wormhole-hack-february-2022/) +- [List of Ethereum contract hack post-mortems](https://forum.openzeppelin.com/t/list-of-ethereum-smart-contracts-post-mortems/1191) +- [Rekt News](https://twitter.com/RektHQ?s=20&t=3otjYQdM9Bqk8k3n1a1Adg) + +#### Recent research + +- [Ethresear.ch Applications](https://ethresear.ch/c/applications/18) + +### Technology stack + +Decentralizing the entire Ethereum tech stack is an important research area. Currently, dapps on Ethereum commonly have some points of centralization because they rely on centralized tooling or infrastructure. + +#### Background reading + +- [Ethereum stack](/developers/docs/ethereum-stack/) +- [Coinbase: Intro to Web3 Stack](https://blog.coinbase.com/a-simple-guide-to-the-web3-stack-785240e557f0) +- [Introduction to smart contracts](/developers/docs/smart-contracts/) +- [Introduction to decentralized storage](/developers/docs/storage/) + +#### Recent research + +- [Smart contract composability](/developers/docs/smart-contracts/composability/) + +--- + +## Community > Support + +# Ethereum support + +## Official Ethereum support + +Are you looking for the official Ethereum support? The first thing you should know is that Ethereum is decentralized. This means no central organization, entity, or person owns Ethereum, and because of this, no official support channels exist. + +Understanding the decentralized nature of Ethereum is vital because **anyone claiming to be official support for Ethereum is probably trying to scam you!** The best protection against scammers is educating yourself and taking security seriously. + + + Ethereum security and scam prevention + + + + Learn Ethereum fundamentals + + +Despite the lack of official support, many groups, communities, and projects across the Ethereum ecosystem are happy to help, and you can find a lot of useful information and resources on this page. Still have questions? Join the [ethereum.org Discord](/discord/), and we'll try to help. + +## Frequently asked questions + +### I've sent ETH to the wrong wallet + +A transaction sent on Ethereum is irreversible. Unfortunately, if you've sent ETH to the wrong wallet, there is no way to recover these funds. No one central organization, entity, or person owns Ethereum, which means no one can reverse transactions. Therefore, it is vital always to double-check your transactions before sending them. + +### How can I claim my Ethereum giveaway? + +Ethereum giveaways are scams designed to steal your ETH. Do not be tempted by offers that seem too good to be true — if you send ETH to a giveaway address, you will not receive a giveaway, and you will not be able to recover your funds. + +[More on scam prevention](/security/#common-scams) + +### My transaction is stuck + +Transactions on Ethereum can sometimes get stuck if you have submitted a lower transaction fee than is required due to network demand. Many wallets provide an option to resubmit the same transaction with a higher transaction fee to allow the transaction to be processed. Alternatively, you can cancel a pending transaction by sending a transaction to your own address and using the same nonce as the pending transaction. + +[How to speed up or cancel a pending transaction on MetaMask](https://metamask.zendesk.com/hc/en-us/articles/360015489251-How-to-speed-up-or-cancel-a-pending-transaction) + +[How to cancel pending Ethereum transactions](https://info.etherscan.com/how-to-cancel-ethereum-pending-transactions/) + +### How do I mine Ethereum? + +Ethereum mining is no longer possible. Mining was switched off when Ethereum moved from [proof-of-work](/glossary/#pow) to [proof-of-stake](/glossary/#pos). Now, instead of miners, Ethereum has validators. Anyone may [stake](/glossary/#staking) ETH and receive staking rewards for running validator software to secure the network. + +### How do I become a staker / run a validator? + +To become a validator, you must stake 32 ETH in the Ethereum deposit contract and set up a validator node. More information is available on our [staking pages](/staking) and at [the staking launchpad](https://launchpad.ethereum.org/). + +## Building dapps + +Building can be hard. Here are some development focused spaces with experienced Ethereum developers that are happy to help. + +- [Alchemy University](https://university.alchemy.com/#starter_code) +- [CryptoDevs discord](https://discord.com/invite/5W5tVb3) +- [Ethereum StackExchange](https://ethereum.stackexchange.com/) +- [StackOverflow](https://stackoverflow.com/questions/tagged/web3) +- [Web3 University](https://www.web3.university/) +- [LearnWeb3](https://discord.com/invite/learnweb3) + +You can also find documentation and development guides in our [Ethereum developer resources](/developers/) section. + +### Tooling + +Does your question relate to a particular tool, project, or library? Most projects have chat servers or forums dedicated to supporting you. + +Here are some popular examples: + +- [Solidity](https://gitter.im/ethereum/solidity) +- [ethers.js](https://discord.gg/6jyGVDK6Jx) +- [web3.js](https://discord.gg/GsABYQu4sC) +- [Hardhat](https://discord.gg/xtrMGhmbfZ) +- [Alchemy](http://alchemy.com/discord) +- [Tenderly](https://discord.gg/fBvDJYR) + +## Running a node + +If you're running a node or validator, here are some communities that are dedicated to helping you get started. + +- [EthStaker discord](https://discord.gg/ethstaker) +- [EthStaker reddit](https://www.reddit.com/r/ethstaker) + +Most of the teams building Ethereum clients also have dedicated, public-facing, spaces where you can get support and ask questions. + +### Execution clients + +- [Geth](https://discord.gg/FqDzupGyYf) +- [Nethermind](https://discord.gg/YJx3pm8z5C) +- [Besu](https://discord.gg/p8djYngzKN) +- [Erigon](https://github.com/ledgerwatch/erigon/issues) +- [Reth](https://github.com/paradigmxyz/reth/discussions) + +### Consensus clients + +- [Prysm](https://discord.gg/prysmaticlabs) +- [Nimbus](https://discord.gg/nSmEH3qgFv) +- [Lighthouse](https://discord.gg/cyAszAh) +- [Teku](https://discord.gg/7hPv2T6) +- [Lodestar](https://discord.gg/aMxzVcr) +- [Grandine](https://discord.gg/H9XCdUSyZd) + +You can also [learn how to run a node here](/developers/docs/nodes-and-clients/run-a-node/). + +--- + +# Contributing + +## Contributing > Adding Desci Projects + +# Adding projects + +We want to make sure we show a variety of projects and give a good snapshot of the DeSci landscape. + +Anyone is free to suggest a project to list on the DeSci page on ethereum.org. Equally, anyone who notices a project that is no longer relevant or no longer meets our eligibility criteria is free to suggest its removal. + +## The decision framework + +### Criteria for inclusion: the must-haves + +- **Open source code/data** - Openness of code and data is a core DeSci principle, so DeSci projects must not be closed source. The codebase should be accessible and ideally open to PRs. +- **DeSci projects should be demonstrably decentralized** - This could include being governed by a DAO, or by building with a decentralized tech stack including non-custodial wallets. It probably involves auditable smart contracts on Ethereum. +- **Honest and accurate listing information** - It is expected that any suggested listings from projects come with honest and accurate information. Products that falsify listing information, such as declaring your product is “open source” when it is not, will be removed. +- **Demonstrable commitment to widening access to science** - A DeSci project should be able to articulate how they widen participation in science to the general public, not just to token/NFT holders. +- **Globally accessible** - Your project doesn’t have geographic limitations or KYC requirements that exclude certain people from accessing your service. +- **Informative website and documentation** - It is important that visitors to the project website can understand what the project actually does, how it contributes to decentralization of science infrastructure and how to participate. +- **Project should be part of the Ethereum ecosystem** - At ethereum.org we believe Ethereum (and its Layer 2's) to be the appropriate base layer for the DeSci movement. +- **The project is fairly well established** - The project has real users that have been able to access the project's services for several months. + +### Nice-to-haves + +- **Available in multiple languages** - Your project is translated into multiple languages allowing users around the world to access it. +- **Educational resources** - Your product should have a well-designed onboarding experience to help and educate users. Or evidence of how-to content like articles or videos. +- **Third-party audits** - Your product has been professionally audited for vulnerabilities by a trusted third party. +- **Point of contact** - A point of contact for the project (this might be by a representative from a DAO or community) will greatly help us get accurate information when changes are made. This will keep updating ethereum.org manageable when gathering future information. + +## Maintenance + +As is the fluid nature of Ethereum, teams and products come and go and innovation happens daily, so we'll undertake routine checks of our content to: + +- Ensure that all projects listed still fulfil our criteria +- Verify there aren't products that have been suggested that meet more of our criteria than the ones currently listed + +Ethereum.org is maintained by the open source community & we rely on the community to help keep this up to date. If you notice any information about listed projects that needs to be updated, please open an issue or a pull request on our GitHub repository. + +## Terms of use + +Please also refer to our [terms of use](/terms-of-use/). Information on ethereum.org is provided solely for general information purposes. + +--- + +## Contributing > Adding Developer Tools + +# Adding developer tools + +We want to make sure we list the best developer resources possible so that people can build with confidence and have the support they need. + +If there's a helpful developer tool that we've missed, feel free to suggest it somewhere appropriate. + +We currently list developer tools throughout our [developer portal](/developers/). + +**Feel free to suggest new additions to appropriate pages.** + +## How we decide + +Developer tool submissions will be assessed by the following criteria: + +**Is it meaningfully differentiated from tools already listed?** + +- New categories or types of tools +- New features compared to existing similar tools +- Targeted at a distinct use-case not covered by existing similar tools + +**Is the tool well documented?** + +- Does documentation exist? +- Is it sufficient to use the tool? +- Has it been recently updated? + +**Is the tool widely used?** + +- We will consider metrics such as GitHub stars, download statistics, and whether it is used by known companies or projects + +**Is the tool of sufficient quality?** + +- Are there recurring bugs? +- Is the tool reliable? +- Is the tool actively maintained? + +**Is the tool open source?** + +Many projects in the Ethereum space are open source. We are more likely to list open-source projects that allows community developers to inspect the code and contribute to it. + +--- + +## Product Ordering + +Unless products are specifically ordered otherwise, such as alphabetically, products will be displayed from least to most recently added to the page. In other words, the newest products get added to the bottom of the list. + +--- + +## Add your developer tool + +If you want to add a developer tool to ethereum.org and it meets the criteria, create an issue on GitHub. + + + Create issue + +--- + +## Contributing > Adding Exchanges + +# Adding Ethereum exchanges + +Anyone is free to suggest new exchanges on ethereum.org. + +We currently list them on: + +- [ethereum.org/get-eth](/get-eth/) + +This page allows a user to input where they live and see what exchanges they can use. This helps surface any geographical restrictions early. + +Because of this context, we need some specific information when you suggest an exchange. + +**NOTE:** If you want to list a decentralized exchange, take a look at our [policy for listing wallets and dapps](/contributing/adding-products/). + +## What we need + +- The geographical restrictions that apply to the exchange. Geographic restrictions associated with the exchange should be detailed on a dedicated page or section of the exchange's website. +- The currencies users can use to buy ETH +- Proof that the exchange is a legitimate trading company +- Any additional information you might have – this might be information about the company like years of operation, financial backing etc. + +We need this info so that we can accurately [help users find an exchange they can use](/get-eth/#country-picker). + +And so that ethereum.org can be more confident that the exchange is a legitimate and safe service. + +--- + +## Add your exchange + +If you want to add an exchange to ethereum.org, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Adding Glossary Terms + +# Adding glossary terms + +This space is changing every day. New terms are constantly entering the lexicon of Ethereum users, and we need your help providing an accurate, up to date reference for all things Ethereum. Check out the current [glossary](/glossary/) and see below if you want to help! + +## Criteria + +New glossary terms will be assessed by the following criteria: + +- Is the term/definition up to date and currently relevant? +- Is there a similar term already in the dictionary? (If so, consider the benefits of a new term vs updating an existing term) +- Is the term/definition void of product advertisement or other promotional content? +- Is the term/definition directly relevant to Ethereum? +- Is the definition objective, accurate and void of subjective judgement or opinion? +- Is the source credible? Do they reference their sources? + +--- + +## Add your term + +If you want to add a glossary term to ethereum.org and it meets the criteria, [create an issue on GitHub](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_glossary_term.yaml). + +--- + +## Contributing > Adding Layer 2s + +# Adding layer 2s + +We want to make sure we list the best resources possible so users can navigate the layer 2 space in a safe and confident manner. + +Anyone is free to suggest adding a layer 2 on ethereum.org. If there's a layer 2 that we have missed, **[please suggest it](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_layer2.yaml)!** + +We currently list L2s on the following pages: + +- [Optimistic rollups](/developers/docs/scaling/optimistic-rollups/) +- [Zero-knowledge rollups](/developers/docs/scaling/zk-rollups/) +- [Layer 2](/layer-2/) + +Layer 2 is a relatively new and exciting paradigm for Ethereum. We've tried to create a fair framework for consideration on ethereum.org but the listing criteria will change and evolve over time. + +## The decision framework + +### Criteria for inclusion: the must-haves + +**Listing on L2BEAT** + +- In order to be considered, this project must be listed on [L2BEAT](https://l2beat.com). L2BEAT provides a robust risk assessment of layer 2 projects that we lean on for evaluating L2 projects. **If the project is not featured on L2BEAT, we will not list them as an L2 on ethereum.org.** +- [Learn how to add your L2 project to L2BEAT](https://github.com/l2beat/l2beat/blob/master/CONTRIBUTING.md). + +**Open source** + +- Your code must be accessible and you should accept PRs from the wider community. + +**Layer 2 category** + +We currently consider the following to be layer 2 solutions: + +- Optimistic rollup +- Zero-knowledge rollup + +_We do not consider other scaling solutions that don't use Ethereum for data availability or security to be layer 2._ + +**Ethereum for data availability** + +- Data availability is an important differentiating factor between other scaling solutions and layer 2. A project **must** use Ethereum Mainnet for data availability to be considered for listing. + +**Bridges** + +- How are users able to onboard to the layer 2? + +**Date project went live** + +- A layer 2 that has been "live" on Mainnet for over 6 months + +- Newer projects that have not been battle-tested by users are less likely to be listed. + +**External security audit** + +- Whether through audit, an internal security team or some other method, your product's security must be reliably tested. This reduces the risk to our users and shows us that you take security seriously. + +**Sustained user base** + +- We will consider metrics such as TVL history, transaction statistics, and whether it is used by known companies or projects + +**Active development team** + +- We won't list a layer 2 that doesn't have an active team working on project. + +**Block explorer** + +- Listed projects require a working block explorer to allow users to easily navigate the chain. + +### Other criteria: the nice-to-haves + +**Exchange support for the project** + +- Are users able to deposit and/or withdraw directly from an exchange? + +**Links to dapps in the layer 2 ecosystem** + +- We want to be able to provide information on what users can expect to be able to do on this layer 2. (e.g. https://portal.arbitrum.io/, https://www.optimism.io/apps) + +**Token contract lists** + +- Since assets will have a new address on layer 2, if there is a token list resource available please share. + +**Native wallet support** + +- Do any wallets support the L2 natively? + +## Add your layer 2 + +If you want to add a layer 2 to ethereum.org, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Adding Products + +# Adding Ethereum products + +Anyone is free to suggest new dapps to the content on ethereum.org, where it's appropriate to do so. **No, we won't list your dapp on our homepage** 😜 + +Dapps are currently listed on: + +- ethereum.org/dapps +- ethereum.org/get-eth + +**Please only suggest new additions on these pages.** + +Although we welcome new additions, we chose the current dapps based on an experience we're trying to create for our users. These are based on some of our design principles: + +- _Inspirational_: anything on ethereum.org should offer something new to users +- _A good story_: what's listed should provide an "aha" moment +- _Credible_: everything should be legitimate businesses/projects to minimize risk to users + +Overall **ethereum.org wants to provide a "seamless onboarding experience" for new users**. For that reason, we add dapps based on their: + +- ease of use +- interoperability with other products +- security +- longevity + +Here's our decision framework in more detail. Feel free to provide feedback or suggest changes. + +## The decision framework + +### Criteria for inclusion: the must-haves + +- **A security-tested product** – whether through audit, an internal security team or some other method, your product's security must be reliably tested. This reduces the risk to our users and shows us that you take security seriously. +- **A product that has been "live" for over 6 months** – this is another indication of security. 6 months is a good time frame for critical bugs and exploitations to have been found. +- **Worked on by an active team** – this helps ensure quality and that a user will get support with their queries. +- **Honest and accurate listing information** - it is expected that any suggested listings from projects come with honest and accurate information. Products that falsify listing information, such as declaring your product is "open-source" when it is not, will be removed. + +### Criteria for ranking: the nice-to-haves + +Your dapp may not be listed on ethereum.org as prominently as others because of the following criteria. + +**Dapps** + +- **You can access it via the majority of listed wallets** – dapps should work with the majority of wallets that are listed on ethereum.org. +- **Users can try it out themselves –** an individual user should be able to use your dapp and achieve something tangible. +- **Onboarding** – your product should have a well-designed onboarding experience to help and educate users. Or evidence of how-to content like articles or videos. +- **Non-custodial** – users control their funds. If your product disappears, users can still access and move their funds. +- **Globally accessible** – your product doesn't have geographic limitations or KYC requirements that exclude certain people from accessing your service. +- **Open source** – your code should be accessible and you should accept PRs from the wider community. +- **Community** – you have a dedicated community, maybe a Discord, where users can interact with your team to get help or suggest new features. + +## Criteria in practice + +The more of the criteria you fill, the more likely your product will find its way onto ethereum.org. + +A listed product that only meets the must-haves may be removed if a new product is suggested that meets the must-haves and several of the nice-to-haves. + +Other things that will factor into this decision: + +- Will adding rather than replacing break the UX of the page? + - our site is primarily educational and the main purpose is to explain Ethereum and its relevant concepts. By adding too many options for users, pages may become less readable and thus less useful. +- Does this page now paralyse the user with choices? + - like when you sit browsing Netflix for hours because you can't decide on something to watch. Bamboozling new users with too much choice is a risk. + +This is a design decision that ethereum.org is responsible for. + +But rest assured, **there will be links to other websites that rank more dapps** + +### Product Ordering + +Unless products are specifically ordered otherwise, such as alphabetically, products will be displayed from most to least recently added to the page. In other words, the newest products get added to the bottom of the list. + +### Terms of use + +Please also refer to our [terms of use](/terms-of-use/). Information on ethereum.org is provided solely for general information purposes. + +## Maintenance + +As is the fluid nature of Ethereum, teams and products come and go and innovation happens daily, so we'll undertake routine checks of our content to: + +- ensure that all dapps listed still fulfill our criteria +- verify there aren't products that have been suggested that meet more of our criteria than the ones currently listed + +You can help with this by checking and letting us know. [Create an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) or send an email to [website@ethereum.org](mailto:website@ethereum.org) + +_We're also investigating options for voting so the community can indicate their preferences and highlight the best products out there for us to recommend._ + +--- + +## Add your product + +If you want to add a dapp to ethereum.org and it meets the criteria, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Adding Resources + +# Adding Resources + +We want to make sure we list the best resources possible while keeping users safe and confident. + +Anyone is free to suggest new resources to add to the resource dashboard on ethereum.org, currently found at [ethereum.org/resources](/resources/). + +Although we welcome new additions, the current resources were chosen based on an experience we're trying to create for our users. These are based on some of our design principles: + +- _Inspirational_: anything on ethereum.org should offer something new to users +- _A good story_: what's listed should provide an "aha" moment +- _Credible_: everything should be legitimate businesses/projects to minimize risk to users + +Overall **ethereum.org aims to provide a seamless onboarding experience for new users**. For that reason, we add resources based on their: + +- ease of use +- accuracy +- maintenance + +## The decision framework + +### Criteria + +- **Honest and accurate listing information** - Any suggested listings must come with honest and accurate information. Products that falsify information will be removed. +- **Active project** – The resource should be maintained by an active team to ensure quality and support for users. Outdated resources are subject to removal. + +### Product Ordering + +We reserve the right to order products based on their impact. New products will generally be added to the bottom of the list unless otherwise specified. + +## Maintenance + +As the Ethereum ecosystem evolves, we will routinely check our content to: + +- Ensure that all resources listed still fulfill our criteria +- Verify there aren't products that have been suggested that meet more of our criteria than the ones currently listed + +You can help with this by checking and letting us know. [Create an issue](https://github.com/ethereum/ethereum-org-website/issues/new?template=bug_report.yaml) or send an email to [website@ethereum.org](mailto:website@ethereum.org). + +--- + +## Add your resource + +If you want to add a resource to ethereum.org and it meets the criteria, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Adding Staking Products + +# Adding staking products or services + +We want to make sure we list the best resources possible while keeping users safe and confident. + +Anyone is free to suggest adding a staking products or service on ethereum.org. If there's one that we have missed, **[please suggest it](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_staking_product.yaml)!** + +We currently list staking products and services on the following pages: + +- [Solo staking](/staking/solo/) +- [Staking as a service](/staking/saas/) +- [Staking pools](/staking/pools/) + +Proof-of-stake on the Beacon Chain has been live since December 1, 2020. While staking is still relatively new, we've tried to create a fair and transparent framework for consideration on ethereum.org but the listing criteria will change and evolve over time, and is ultimately at the discretion of the ethereum.org website team. + +## The decision framework + +The decision to list a product on ethereum.org is not dependent on any one factor. Multiple criteria are considered together when deciding to list a product or service. The more of these criteria are met, the more likely it is to be listed. + +**First, which category of product or service is it?** + +- Node or client tooling +- Key management +- Staking as a service (SaaS) +- Staking pool + +Currently, we are only listing products or services in these categories. + +### Criteria for inclusion + +Staking products or services submissions will be assessed by the following criteria: + +**When was the project or service launched?** + +- Is there evidence of when the product or service became available to the public? +- This is used to determine the products "battle tested" score. + +**Is the project being actively maintained?** + +- Is there an active team developing the project? Who is involved? +- Only actively maintained products will be considered. + +**Is the product or service free of trusted/human intermediaries?** + +- What steps in the users journey require trusting humans to either hold the keys to their funds, or to properly distribute rewards? +- This is used to determine the product or services "trustless" score. + +**Does the project provide accurate and reliable information?** + +- It is crucial that the product's website features up-to-date, accurate, and non-misleading information, particularly if it pertains to the Ethereum protocol or other related technologies. +- Submissions containing misinformation, outdated details, or potentially misleading statements about Ethereum or other relevant subjects will not be listed or will be removed if already listed. + +**What platforms are supported?** + +- i.e. Linux, macOS, Windows, iOS, Android + +#### Software and smart contracts + +For any custom software or smart contracts involved: + +**Is everything open source?** + +- Open source projects should have a publicly available source code repository +- This is used to determine the products "open source" score. + +**Is the product out of _beta_ development?** + +- Where is the product at in its development cycle? +- Products in the beta stage are not considered for inclusion on ethereum.org + +**Has the software undergone an external security audit?** + +- If not, are there plans to conduct an external audit? +- This is used to determine the products "audited" score. + +**Does the project have a bug bounty program?** + +- If not, are there plans to create a security bug bounty? +- This is used to determine the products "bug bounty" score. + +#### Node or client tooling + +For software products related to node or client setup, management or migration: + +**Which consensus layer clients (i.e. Lighthouse, Teku, Nimbus, Prysm, Grandine) are supported?** + +- Which clients are supported? Can the user choose? +- This is used to determine the products "multi-client" score. + +#### Staking as a service + +For [staking-as-a-service listings](/staking/saas/) (i.e. delegated node operation): + +**What are the fees associated with using the service?** + +- What is the fee structure, e.g. is there a monthly fee for the service? +- Any additional staking requirements? + +**Are users required to sign-up for an account?** + +- Can someone use the service without permission or KYC? +- This is used to determine the products "permissionless" score. + +**Who holds the signing keys, and withdrawal keys?** + +- What keys does the user maintain access to? What keys does the service gain access to? +- This is used to determine the products "trustless" score. + +**What is the client diversity of the nodes being operated?** + +- What percent of validator keys are being run by a majority consensus layer (CL) client? +- As of last edit, Prysm is the consensus layer client being run by a majority of node operators, which is dangerous for the network. If any CL client is currently being used by over 33% of the network, we request data related to its usage. +- This is used to determine the products "diverse clients" score. + +#### Staking pool + +For [pooled staking services](/staking/pools/): + +**What is the minimum ETH required to stake?** + +- e.g. 0.01 ETH + +**What are the fees or staking requirements involved?** + +- What percentage of rewards are removed as fees? +- Any additional staking requirements? + +**Is there a liquidity token?** + +- What are the tokens involved? How do they work? What are the contract addresses? +- This is used to determine the products "liquidity token" score. + +**Can users participate as a node operator?** + +- What is required to run validator clients using the pooled funds? +- Does this require permission from an individual, company or DAO? +- This is used to determine the products "permissionless nodes" score. + +**What is the client diversity of the pool node operators?** + +- What percent of node operators are running a majority consensus layer (CL) client? +- As of last edit, Prysm is the consensus layer client being run by a majority of node operators, which is dangerous for the network. If any CL client is currently being used by over 33% of the network, we request data related to its usage. +- This is used to determine the products "diverse clients" score. + +### Other criteria: the nice-to-haves + +**What user interfaces are supported?** + +- i.e. Browser app, desktop app, mobile app, CLI + +**For node tooling, does the software provide an easy way to switch between clients?** + +- Can the user easily and safely change clients using the tool? + +**For SaaS, how many validators are currently being operated by the service?** + +- This gives us an idea of the reach of your service so far. + +## How we display results + +The [criteria for inclusion](#criteria-for-inclusion) above are used to calculate a cumulative score for each product or service. This is used as a means of sorting and showcasing products that meet certain objective criteria. The more criteria that evidence is provided for, the higher a product will be sorted, with ties being randomized on load. + +The code logic and weights for these criteria are currently contained in [this JavaScript component](https://github.com/ethereum/ethereum-org-website/blob/dev/src/components/Staking/StakingProductsCardGrid.js#L350) in our repo. + +## Add your product or service + +If you want to add a staking product or service to ethereum.org, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Adding Wallets + +# Adding wallets + +We want to make sure we show a variety of wallets covering the feature-rich landscape of wallets so that users can navigate Ethereum in a confident manner. + +Anyone is free to suggest adding a wallet on ethereum.org. If there's a wallet that we have missed, please suggest it! + +Wallets are currently listed on: + +- [ethereum.org/wallets/find-wallet/](/wallets/find-wallet/) + +Wallets are rapidly changing in Ethereum. We've tried to create a fair framework for consideration on ethereum.org but the listing criteria will change and evolve over time. + +## The decision framework + +### Criteria for inclusion: the must-haves + +- **A security-tested product** - whether through audit, an internal security team, open sourced coded, or some other method, your wallet's security must be reliable. This reduces the risk to our users and shows us that you take security seriously. +- **A wallet that has been “live” for over six months OR released by a group with a reputable track record** - this is another indication of security. Six months is a good time frame for critical bugs and exploitations to have been found. We ask six months to help filter out forks that are quickly abandoned as projects. +- **Worked on by an active team** - this helps to ensure quality and that a user will get support for their queries. +- **Honest and accurate listing information** - it is expected that any suggested listings from projects come with honest and accurate information. Products that falsify listing information, such as declaring your product is “open source” when it is not, will be removed. +- **Point of contact** - A point of contact for the wallet will greatly help us get accurate information when changes are made. This will keep updating ethereum.org manageable when gathering future information. +- **EIP-1559 (type 2) transactions** - your wallet must support EIP-1559 (type 2) transactions for transactions on Mainnet Ethereum. +- **Good user experience** - While UX is subjective, if several core team members test the product and find it difficult to use, we reserve the right to reject the wallet and will instead provide useful suggestions to improve. This is done to protect our user base that is mostly comprised of beginners. + +### Product removals + +- **Updated information** - Wallet providers are responsible for resubmitting their wallet information every 6 months to ensure validity and relevance of provided information (even if there are no changes to their product). If the product team fails to do so, ethereum.org may remove the project from the page. + +### Other criteria: the nice-to-haves + +- **Globally accessible** - your wallet doesn’t have geographic limitations or KYC requirements that exclude certain people from accessing your service. +- **Available in multiple languages** - your wallet is translated into multiple languages allowing users around the world to access it. +- **Open source** - your whole project’s codebase (not just modules) should be accessible and you should accept PR’s from the wider community. +- **Non-custodial** - users control their funds. If your product disappears, users can still access and move their funds. +- **Hardware wallet support** - users can connect their hardware wallet to sign transactions. +- **WalletConnect** - users can connect to dapps using WalletConnect. +- **Importing Ethereum RPC endpoints** - users can import node RPC data, allowing them to connect to a node of their choice, or other EVM compatible networks. +- **NFTs** - users are able to view and interact with their NFTs in the wallet. +- **Connect to Ethereum applications** - users are able to connect to and use Ethereum applications. +- **Staking** - users are able to stake directly through the wallet. +- **Swaps** - users are able to swap tokens through the wallet. +- **Multichain networks** - your wallet supports users accessing multiple blockchain networks by default. +- **Layer 2 networks** - your wallet supports users accessing layer 2 networks by default. +- **Customize gas fees** - your wallet allows users to customize their transaction gas fees (base fee, priority fee, max fee). +- **ENS support** - your wallet allows users to send transactions to ENS names. +- **ERC-20 support** - your wallet allows users to import ERC-20 token contracts, or automatically queries and displays ERC-20 tokens. +- **Buy crypto** - your wallet supports users directly purchasing and onboarding to crypto. +- **Sell for fiat** - your wallet supports users selling and withdrawing to fiat directly to card or a bank account. +- **Multisig** - your wallet supports multiple signatures to sign a transaction. +- **Social recovery** - your wallet supports guardians and a user can recover their wallet if they lose their seed phrase using these guardians. +- **Dedicated support team** - your wallet has a dedicated support team where users can go to when experiencing issues. +- **Educational resources/documentation** - your product should have a well-designed onboarding experience to help and educate users. Or evidence of how-to content like articles or videos. + +## Adding a wallet + +If you want to add a wallet to ethereum.org, create an issue on GitHub. + + + Create an issue + + +## Maintenance + +As is the fluid nature of Ethereum, teams and products come and go and innovation happens daily, so we'll undertake routine checks of our content to: + +- ensure that all wallets and dapps listed still fulfill our criteria +- verify there aren't products that have been suggested that meet more of our criteria than the ones currently listed + +ethereum.org is maintained by the open source community & we rely on the community to help keep this up to date. If you notice any information about listed wallets that needs to be updated, please [open an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=wallet+%3Apurse%3A&template=suggest_wallet.yaml) or [pull request](https://github.com/ethereum/ethereum-org-website/pulls)! + + +## Terms of use + +Please also refer to our [terms of use](/terms-of-use/). Information on ethereum.org is provided solely for general information purposes. + +--- + +## Contributing > Content Resources + +# Adding content resources + +We can't hope to cover everything Ethereum so we try to showcase some of the brilliant articles, tutorials, newsletters, job boards and various content resources that the community creates. These often provide more in-depth information on topics that users may be interested in. + +If there's a content resource that you feel should be added to a page, feel free to suggest it somewhere appropriate. + +## How we decide + +Learning resources will be assessed by the following criteria: + +- Is the content up to date? +- Is the content behind a paywall? +- Is the information accurate? Is it factual or opinion-based? +- Is the author credible? Do they reference their sources? +- Does this content add distinct value that existing resources/links don't cover? +- Does this content serve one of our [user personas](https://www.notion.so/efdn/Ethereum-org-User-Persona-Memo-b44dc1e89152457a87ba872b0dfa366c)? + +--- + +## Add your content resource + +If you want to add a content resource to ethereum.org and it meets the criteria, create an issue on GitHub. + + + Create an issue + +--- + +## Contributing > Design Principles + +# Our design principles + + Hello, and welcome to the design principles for ethereum.org. This is part of an ongoing process to evolve and improve ethereum.org. + +Our principles inform the look and feel of the site and the content that's on it. + +You should read these before you [contribute to ethereum.org](/contributing/). + +## What are design principles? + +Don't worry, they're pretty simple! **Design principles** are a set of guidelines we refer to when designing (i.e. creating, maintaining or updating) something. + +In the context of ethereum.org these design principles are the foundation for what we want the website to represent and project to the world. They're both aspirational **and** functional. It's not just how the website _looks_, but also how it _works_ and even how it makes someone _feel._ Everything, from the colors to the page layouts to how we talk about Ethereum on the website should be informed by these principles. + +## The principles in practice + +Let's look at an example. One of the principles is “Credible”, which means that we want visitors to the site to _feel_ and _know_ that the site is trustworthy - just like the wider Ethereum ecosystem. Within that principle, we have 3 functional “sub-principles” that we believe are actionable steps we can take to make the site credible: + +- _“Fresh”_ i.e. keep the content up-to-date. +- _“Social Proof”_ i.e. show the size, diversity and activity of the ecosystem (you know: Ethereum upgrade progress, DeFi, gaming, all the hackathons, etc.) +- _“Consistent”_ i.e. consistency in the design of the site and the tone and accuracy of the writing. + +So when we're making design decisions, or copywriting decisions, we can then reference the “Credible” principle and ask: + +- _“Does the site reflect current information?”_ +- _“How and where are we showing the ecosystem's size and activity?”_ +- _“Are the new proposed contributions by a community member that I'm reviewing consistent with the current design and writing on the site?”_ + +## The ethereum.org design principles + +### 1. Inspirational + +The site should inspire users to dream of how Ethereum can change the world. It should motivate people to explore, play and tinker with the tools and apps of the Ethereum ecosystem. + +- **Radical:** The site should communicate Ethereum's ambitious goals to meaningfully change the world. It should be clear that Ethereum is not just some new tech stack - it is a transformational technology. +- **Empowerment through education:** The site should educate people so they can understand Ethereum's potential, find their place in the ecosystem, and feel empowered to participate in it. + +Visual Direction • Content + +### 2. Universal + +Ethereum is a global, decentralized project and our audience reflects this. The site should aspire to be accessible to everyone, and sensitive to the world's many cultures. + +- **Accessible:** The site should follow accessibility guidelines - including for people with low-bandwidth connections. +- **Straightforward:** The site should be simple and unambiguous. Copy shouldn't use language that may be misinterpreted or lost in translation. +- **Ethereum is multi-faceted:** Ethereum is a project, a codebase, a community, and a vision. Ethereum is valuable to different people for different reasons, and there are many ways to be involved. + +Writing systems • Use of color • Visual Direction • Content + +### 3. A Good Story + +The website should function like a good story. Visitors are on a journey, and the content you contribute is a part of that. Your contributions should fit within a clear narrative: one with a beginning (introduction/entry point), middle (set of learnings and insights), and end (a link(s) to relevant resources, or next steps). + +- **Hierarchical**: A clear, hierarchically structured information architecture helps visitors to ethereum.org navigate the site "as a story" as they seek to achieve their goals. +- **A Stepping Stone:** We're a stepping stone for anyone looking for answers. We don't want to replace or become a substitute for the many resources that already exist. We give an answer & provide reliable next steps. + +User Journeys • Content + +### 4. Credible + +People may be seeking their introduction to the Ethereum ecosystem or they may be skeptics. Acknowledge that responsibility in how you communicate. Ensure that they both leave with greater confidence in the Ethereum ecosystem. + +- **Fresh:** Always up to date. +- **Social Proof:** Show the size, diversity and activity of the ecosystem. +- **Consistent:** Consistency in design and content communicates credibility. + +Visual Direction • Content + +### 5. Collaborative Improvement + +The website is the product of many contributors, just like the ecosystem as a whole. + +- **Open:** Celebrate transparency of source code, processes and projects across the ecosystem. +- **Extendable:** Modularity is a key focus behind everything we do, and so contributions should be modular too. The core design, component code & implementation of the site should enable it to be easily extended in the future. +- **Experimental:** We are constantly experimenting, testing and iterating. +- **Collaborative:** This project brings together all of us. +- **Sustainable:** Setting up for long-term maintenance by the community + +You can see our design principles in action [across our site](/). + +## Give feedback + +**Share your feedback on this document!** One of our proposed principles is “**Collaborative Improvement**” which means that we want the website to be the product of many contributors. So in the spirit of that principle, we want to share these design principles with the Ethereum community. + +While these principles are focused on the ethereum.org website, we hope that many of them are representative of the values of the Ethereum ecosystem overall (e.g. you can see influence from the [principles of the Ethereum Whitepaper](https://github.com/ethereum/wiki/wiki/White-Paper#philosophy)). Maybe you even want to incorporate some of them into your own project! + +Let us know your thoughts on [Discord server](https://discord.gg/ethereum-org) or by [creating an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=). + +--- + +## Contributing > Design > Adding Design Resources + +# Adding design resources + +Anybody can suggest new design materials to the [Design and UX in web3 page](/developers/docs/design-and-ux/). + +Be aware that the focus of this page is on providing user value to aspiring web3 designers. The design section is not there to advertise your services, products, or platforms. + +To ensure that we maintain a high standard of information and promote valuable insights, we have established a listing policy: + +## Research Studies and Dashboards + +1. Sound Methodology + +a. The methodology should clearly define how the data was collected. + +b. The number of participants involved in the research should be stated. + +c. The research methods employed should be described. + +2. Relevance to Web3 Designers and Common Design Use Cases + +a. The topic of the research should be relevant to web3 designers and address common design use cases. + +3. Focus on delivering insights + +a. The primary objective of the text should be sharing insights rather than promoting a specific project or company. + +## Articles + +1. Relevance to Web3 Designers/Researchers and Common Web3 Design Use Cases + +a. The topic of the article should be pertinent to web3 designers and researchers, focusing on common web3 design use cases. + +2. Basic Writing Quality + +a. The article should be free of grammar and spelling mistakes. + +b. Emphasis should be placed on delivering key insights and learnings. + +c. The writing should be concise and to the point. + +3. Goal of the Text + +a. The primary goal of the article should be sharing insights rather than promoting a particular project or company. + +## Communities / DAOs + +1. Website must clearly indicate how to join the DAO/Community + +2. Clear Benefits of Membership + +a. The benefits of becoming a member should be prominently displayed. + +**Examples**: receiving feedback on work, accessing job opportunities or bounties, sharing design and research insights. + +3. Active and Vibrant Communication on Discord + +a. The Discord community should exhibit lively and engaged communication. + +b. Moderators should be actively involved in maintaining the community and facilitating discussions. + +c. The community should demonstrate a track record of valuable and productive conversations within the last two weeks. + +By adhering to these criteria, we aim to foster a thriving and knowledge-sharing environment within our community. We believe that this white listing policy will ensure that our users have access to reliable, relevant, and insightful resources. Thank you for your understanding and cooperation in maintaining the quality of content within our platform. + +--- + +## Contributing > Design + +# Design contribution to ethereum.org + +Design is a critical component of any project, and by devoting your time and design skills to ethereum.org, you can help to improve the user experience for our visitors. Contributing to an open-source project provides an opportunity to gain relevant experience and develop your skills in a collaborative environment. You will have the chance to work with other designers, developers, and community members, all of whom will have their own unique perspectives and insights. + +Ultimately, this is a great way to build a diverse and impressive portfolio that showcases your design skills. + +## How to contribute? + +###  Provide feedback on early design prototypes + +We sometimes need a help testing our raw ideas. This is a great way how to contribute without any technical knowledge. + +1. The design team will share a mockup design on [Discord](https://discord.com/invite/ethereum-org) and on [GitHub](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8). +2. You will be guided through the designs to provide feedback via comments function. +3. The outcome will be shared in the GitHub issue and then closed by the team. + +###  Participate in survey research + +Provide feedback on our website by: + +1. Visiting ethereum.org and reading through pages. +2. Clicking on the feedback widget at the bottom right corner and answering design and content-related questions. +3. Focus on the free format questions. + +###  Find design related issues on the website and report them + +ethereum.org is a fast growing website with many features and content. Some of the UI can easily become obsolete or could be improved. If you encounter any such instance, please report it so that it gets our attention. + +1. Go through the website and pay attention to its design. +2. Take screenshots and notes if you see any visual or UX issues. +3. Report the found issues using a [bug report](https://github.com/ethereum/ethereum-org-website/issues/new/choose). + +###  Propose design changes + +If you feel comfortable taking on design challenges, you can visit our GitHub issues board and filter for [design-related issues](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8). + +1. Go through our website and pay attention to its design or go to our GitHub repository and review issues flagged with the [“Design required” tag](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8). +2. Ideate on the solution and design it. (ideally using our [design system](https://www.figma.com/community/file/1134414495420383395)). +3. Propose the solution in the corresponding GitHub issue or [create a new one.](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A&template=feature_request.yaml&title=Feature+request) +4. Wait for the design team to review. + +###  Build Design System together + +Our design system makes designing ethereum.org fun and easy. If you are an experienced designer, you can help us prepare many components for the website. + +1. Select an issue to work on from [design system board](https://github.com/ethereum/ethereum-org-website/labels/design%20system) on GitHub or create a new one. +2. Request the selected issue to be assigned to you. +3. Start designing the requested component in Figma. +4. Share it with the design team on GitHub once you need review or guidance. +5. The design team will review. +6. The design team will incorporate the changes in the main file and publish the file to the community. + +###  Write design-related content on the website + +The Ethereum developer community is strong, but the design community is falling slightly behind. If you are a designer with web3 knowledge, please consider sharing your learnings with the larger community so that we can all grow and improve together; we have [a page on designing for Ethereum](/developers/docs/design-and-ux/) you can contribute to. You can also check our [listing policies](/contributing/design/adding-design-resources). + +1. Ideate on design topics that should be covered on ethereum.org and would be beneficial for the designers in the space. +2. Go to our GitHub repository and [raise an issue](https://github.com/ethereum/ethereum-org-website/issues/new) proposing a topic (do not write the content yet). +3. Wait for the design team to approve. +4. Once approved, write the content. +5. Submit it in the corresponding GitHub issue. + +###  Draw new illustrations + +Visualisations are one of the most powerful tools to explain abstract topics. There is an enormous potential by adding diagrams and infographics. After all, one image can say thousand words. + +1. Go to our website and see pages where some new infographics could be added. +2. Make sure that the illustration style corresponds to our [assets](/assets/). +3. Go to our GitHub repository and [raise an issue](https://github.com/ethereum/ethereum-org-website/issues/new) proposing the illustration. +4. The design team will review it. +5. We create a new issue to ask a developer to implement the new image. + +--- + +## Contributing + +# Contributing to ethereum.org 🦄 + +Ethereum.org is an open-source run project with **12 000+** contributors that help translate, write, design and maintain the website. + +We are a welcoming community that will help you grow and educate in the Ethereum ecosystem while also meaningfully contribute and get relevant practical experience! + +## Ways to contribute + +**Translations** +- [Join the translation program](/contributing/translation-program/) – Help us bring ethereum.org to new languages + +**Development** +- [Work on an open issue](https://github.com/ethereum/ethereum-org-website/issues) – Work we've identified that needs doing + +**Design** +- [Help design the website](/contributing/design/) – Designers of all levels can contribute to improve the website + +**Content** +- [Create/edit content](/contributing/#how-to-update-content) – Suggest new pages or make tweaks to what's here already +- [Add community resources](/contributing/content-resources/) – Add a helpful article or resource to a relevant page +- [Suggest a design resource](/contributing/design/adding-design-resources/) – Add, update, and delete helpful design resources +- [Quizzes](/contributing/quizzes/) – Add, update, and delete quiz question banks for a relevant page + +**Feature ideas** +- [Request a feature](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) – Let us know about any ideas you have for a new feature or design + +**Product listings** +- [Add an exchange](/contributing/adding-exchanges/) – Add an exchange to our [exchange finder](/get-eth/#country-picker) +- [Add a product](/contributing/adding-products/) – Add a dapp or wallet to a relevant page +- [Add developer tools](/contributing/adding-developer-tools/) – Add a developer tool to a relevant page +- [Add a layer 2](/contributing/adding-layer-2s/) – Add a layer 2 to a relevant page +- [Add a staking product or service](/contributing/adding-staking-products/) – Add a project that helps facilitate solo staking, pooled staking, or staking as a service +- [Add a wallet](/contributing/adding-wallets/) – Add a wallet for the [find wallets page](/wallets/find-wallet/) +- [Suggest a project for our DeSci page](/contributing/adding-desci-projects/) – Add a project built on Ethereum that contributes to decentralized science + +Any questions? 🤔 Join our [Discord server](https://discord.gg/ethereum-org) + +## Good first tasks to start contributing + +These are few current tasks that you could help us solve and take responsibility for. For most you will need GitHub account as most changes to the website are made through GitHub. + + + +See all tasks + +## How to work on ethereum.org + +If you wish to contribute in the [Translation Program](/contributing/translation-program/), we ask you to create an account on [Crowdin](https://crowdin.com/project/ethereum-org). For everything else – adding or editing content or visuals to the website, fixing bugs, working on open tasks – you will need a [GitHub](https://github.com/) account. + +All updates are made via the GitHub PR process. This means you create a local copy of the website, make your changes and request to merge your changes. If you've never done this before, follow the instructions at the bottom of our [GitHub repository](https://github.com/ethereum/ethereum-org-website). + +You don't need permission to work on anything, but it's always best to let us know what you're planning to do. You can do this by: + +- Commenting on an issue or PR in [GitHub](https://github.com/ethereum/ethereum-org-website) +- Messaging on our [Discord server](https://discord.gg/ethereum-org) + +Before contributing, make sure you're familiar with: + +- the evolving [vision of ethereum.org](/about/) +- our [design principles](/contributing/design-principles/) +- our [style guide](/contributing/style-guide/) +- our [code of conduct](/community/code-of-conduct) + + + +## How decisions about the site are made + +Decisions about individual PRs, design evolution and major upgrades are made by a team from across the Ethereum ecosystem. This team includes project managers, developers, designers, marketing and communications, and subject matter experts. Community input informs every decision: so please raise questions in issues, submit PRs, or contact the team: + +- [website@ethereum.org](mailto:website@ethereum.org) +- [@ethdotorg](https://twitter.com/ethdotorg) +- [Discord server](https://discord.gg/ethereum-org) + +### A note on plagiarism + +Only use your original work or content that you have permission to use when contributing any content or artifact to ethereum.org. Many projects within the Ethereum ecosystem use open-source licensing that allows for the free sharing of information. However, if you cannot find this information, do not attempt to add it to ethereum.org. Any pull requests deemed as plagiarism will get rejected. + +## New to open-source? + +We have low barrier to entry issues on our GitHub repository specifically designed for developers who are new to open-source labelled [good first issue](https://github.com/ethereum/ethereum-org-website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). + +## Claim your Onchain Achievement Token (OAT) + +If your contribution gets merged into ethereum.org, you will have a chance to claim a special badge on [Galxe](https://app.galxe.com/quest/ethereumorg). An Onchain Achievement Token (OAT) is a proof that you helped make the ecosystem a little more awesome. + +[More on OATs](https://help.galxe.com/en/articles/9645630-create-quest-rewards#h_1c5d63ba03) + +### How to claim +1. Join our [Discord server](https://discord.gg/ethereum-org). +2. Paste a link to your contribution in the `#🥇 | proof-of-contribution` channel. +3. Wait for a member of our team to send you a link to your OAT. +4. Claim your OAT! + +You should only use self-custody wallets to claim OATs. Do not use exchange accounts or other accounts you do not hold the private keys to, as these will not allow you to access and manage your OATs. + +## Claim your GitPOAP + +GitPOAP will also automatically recognize your merged contribution and let you mint a separate unique contributors POAP on their platform itself! + + +### How to claim + +1. Visit [GitPOAP](https://www.gitpoap.io). +2. Connect with your wallet or even with your email through sign in option. +3. Search for your GitHub username, ETH address, ENS names or any GitPOAP to check if you're eligible. +4. If your GitHub account is eligible, then you would be able to mint a GitPOAP! + +## Contributors + +--- + +## Contributing > Quizzes + +# Quizzes + +Quizzes are an opportunity for users to test themselves to see if they understood the content on the page they just read. The questions should only be based on the content provided on the page and should not ask about information that is not mentioned on the page. + +Questions are structured as follows. The question prompt, 1 correct answer with an explanation of why it is correct, 3 incorrect answers with an explanation of why they are incorrect. + +Some examples of current quizzes can be found here: + +- [Layer 2](/layer-2) +- [NFT](/nft/) +- [What is Ethereum?](/what-is-ethereum/) +- [What is ETH?](/eth/) + +## Adding a learn quiz + +If there is a page that hasn't had a learn quiz created for it, please [open an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) for it. + +Please provide the following information: + +- The page you want to add a quiz on +- 5 questions with the following information: + - The section of the page the question is based on + - Question prompt + - 1 correct answer with an explanation for why it is correct + - 3 incorrect answers, each with an explanation for why they are incorrect + +## Adding a quiz question + +If there is a question you want to add to the question bank for a quiz, please [open an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) and provide the following information: + +- The page you want to add a quiz question on +- For each question provide the following information: + - The section of the page the question is based on + - Question prompt + - 1 correct answer with an explanation for why it is correct + - 3 incorrect answers, each with an explanation for why they are incorrect + +## Updating a quiz question + +If there is a question you want to update in a question bank for a quiz, please [open an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) and provide the following information: + +- The page you want to update a quiz question on +- For each question being updated, provide the following information: + - The section of the page the question is based on + - Question prompt of the question you want to update + - Updated question prompt + - 1 correct answer with an explanation for why it is correct + - 3 incorrect answers, each with an explanation for why they are incorrect + +## Removing a quiz question + +If the content no longer exists on the page for a question and it needs to be removed, please [open an issue](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) to remove the question and provide the following information: + +- The page you want to delete a quiz question on +- The question that you want to delete +- Explanation if necessary for why the question should be removed + +--- + +## Contributing > Style Guide > Content Standardization + +# Content standardization + +This style guide aims to standardize certain aspects of writing content to make the contribution process smoother. + +## Use American English + +For words that have multiple spellings, use American English over British English. + +**For example:** + +- "decentralized" over "decentralised" +- "color" over "colour" +- "analyze" over "analyse" + +## Terminology + +### Ethereum + +Ethereum is a proper noun and should always be capitalized. + +- "Ethereum" not "ethereum" + +### Ether + +Ether is a common noun and should not be capitalized unless at the beginning of a sentence. ETH, on the other hand, is a currency abbreviation (and ticker symbol) and should always be capitalized. + +- "ether" not "Ether" +- "ETH" not "eth or Eth" + +### Mainnet + +When referring to the Ethereum Mainnet (i.e. not referring to a testnet) use the proper noun. Proper nouns help avoid confusion and build greater understanding. + +**Correct usage:** + +- Mainnet +- Ethereum Mainnet + +**Incorrect usage:** + +- main net +- mainnet +- Main net +- Ethereum mainnet + +### Proof-of-work / Proof-of-stake + +Proof-of-work should be capitalized only when at the beginning of a sentence. In any other instance, all letters should be lower case. In either case, proof-of-work should be hyphenated between each word. + +**Correct usage:** + +- Proof-of-work +- proof-of-work + +**Incorrect usage:** + +- Proof-of-Work +- Proof of work +- proof of work + +The same rules we apply to proof-of-work are applicable to proof-of-stake, proof-of-authority, proof-of-humanity, proof-of-individuality, etc. + +### Smart contract + +Smart contract is a common noun and should only be capitalized at the beginning of a sentence. In any other instance, all letters should be lowercase. + +**Correct usage:** + +- Smart contract +- smart contract + +** Incorrect usage:** + +- Smart Contract + +### The Merge + +When referring to The Merge, treat it as a proper noun. Always capitalize the first letter in each word. + +**Correct usage:** + +- The Merge + +**Incorrect usage:** + +- The merge +- the Merge + +### Zero-knowledge + +Zero-knowledge is a common noun and should only be capitalized at the beginning of a sentence. In any other instance, all letters should be lowercase. In either case, zero-knowledge should be hyphenated between each word. + +**Correct usage:** + +- Zero-knowledge +- zero-knowledge + +**Incorrect usage:** + +- Zero-Knowledge +- Zero knowledge +- zero knowledge + +### ZK-proof + +When using the abbreviated form of zero-knowledge proof you should shorten zero-knowledge to ZK, and hyphenate the abbreviation. + +**Correct usage:** + +- ZK-proof + +**Incorrect usage:** + +- Zk-proof +- zK-proof +- zk-proof +- Zk proof +- zK proof +- zk proof + +### ZK-rollup + +When using the abbreviated form of zero-knowledge rollup you should shorten zero-knowledge to ZK, and hyphenate the abbreviation. + +**Correct usage:** + +- ZK-rollup + +**Incorrect usage:** + +- Zk-rollup +- zK-rollup +- zk-rollup +- Zk rollup +- zK rollup +- zk rollup + +### Use active voice + +Sentences using active voice are more concise and efficient, making your writing more engaging and easier to comprehend. + +**Active voice sentence:** an actor acts on a target + +> _"The man bought a car."_ + +**Passive voice sentence:** a target acts on an actor + +> _"The car was bought by a man."_ + +[Read more on active voice](https://www.grammarly.com/blog/active-vs-passive-voice/) + +_This isn't an easy one, especially for non-native English speakers. If you aren't sure, don't worry. We'll help with any of these._ + +### Date Format + +When including dates in markdown content across Ethereum documentation, it is essential to maintain a consistent and clear presentation. In order to achieve this, we recommend the following guidelines: + +**Format:** + +Use the "D-Mon-YYYY" format for dates. This format eliminates ambiguity between the month and day, providing a standardized and easily understandable representation. + +**Examples:** + +- Preferred: 2-Nov-2023, 11-Feb-2023 +- Avoid: Nov-2-2023, 2/11/2023, 11/2/2023 + +By adhering to these guidelines, we create a unified approach to presenting dates, fostering clarity and comprehension throughout Ethereum documentation. + +### Linking to internal pages + +When linking to another page on Ethereum.org, use the relative path over the absolute path. Do not hard-code the language path (i.e. `/en/`) in any links. This maintains consistent functionality across different language versions of the site. + +```md + + +Read more about [smart contracts](/docs/developers/smart-contracts/) + + + +Read more about [smart contracts](/en/docs/developers/smart-contracts) +Read more about [smart contracts](https://ethereum.org/en/docs/developers/smart-contracts) +``` + +Please also add a trailing slash to all links. This keeps links consistent and avoids redirects, which hurts site performance. + +```md + + +Read more about [smart contracts](/docs/developers/smart-contracts/) + + + +Read more about [smart contracts](/docs/developers/smart-contracts) +``` + +### Linking to images + +When adding an image to a page, the image should be downloaded and placed in the same folder as the markdown file. You can reference the image like this: + +`![alt text for image](./image.png)` + +```md + + +![How to mint your NFT](./mintYourNFT.gif) + + + +![How to mint your NFT](https://cdn-images-1.medium.com/max/2000/0342fj_fsdfs.gif) +``` + +This helps us ensure the image will be available. + +### Using emojis + +Everyone loves emojis To standardize the appearance of all Emojis across browsers, ethereum.org uses an `` React component. + +```md + + +The London Upgrade is live + +The London Upgrade is live + + + +The London Upgrade is live 🎉 +``` + +### Header casing + +This site uses **sentence casing** for header names as a convention. Only the first word and proper nouns are capitalized. This applies to all markdown files on lines that begin with hashes (#). + +```md + + +## Minting your NFT + +### Setting up your wallet + +### Get enough ether + + + +## Minting Your NFT + +### Setting Up Your Wallet + +### Getting Enough ether +``` + +### Article authors + +When citing articles from a specific author or organization, use the article's name as a link, followed by a dash, then the author's name italicized. + +```md + + +- [A rollup-centric ethereum roadmap](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698) — _Vitalik Buterin_ +- [The History of Ethereum Testnets](https://consensys.net/blog/news/the-history-of-ethereum-testnets/) – _ConsenSys_ + + + +- [A rollup-centric ethereum roadmap by Vitalik Buterin](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698) +- [ConsenSys on The History of Ethereum Testnets](https://consensys.net/blog/news/the-history-of-ethereum-testnets/) – _ConsenSys_ +``` + +### Onchain and offchain + +Similar to "online" or "offline", the terms "onchain" and "offchain" should be written as one word, without a space or hyphenation. + +```md + +Discussion was held in an offchain forum, and the vote was performed onchain. + + +Discussion was held in an off-chain forum, and the vote was performed on-chain. +``` + +--- + +## Contributing > Style Guide + +# Ethereum.org style guide + +Content on [ethereum.org](/) is crowdsourced and primarily written by our incredible contributors. + +Our primary objective is to educate and inform visitors about Ethereum in a manner that is accessible to a diverse range of readers, from technical experts to casual visitors. Since we deal with complex and abstract topics, clear content writing is crucial to effectively convey the information and avoid confusion or misinterpretation. + +You should read this style guide before you [contribute to ethereum.org](/contributing/). + +## Who can submit content to ethereum.org + +Anyone! Ethereum.org is entirely open source, and many of its best pages are submitted by curious learners who expanded their notes into documentation pages now living on the site. + +## Audience + +- 60% of our website visitors do not own any ether according to our survey responses +- 50% of visitors identify themselves as newcomers to the crypto space + +**Common reading-related problems:** + +- Articles are hard to digest due to + - too much text per page / paragraph + - usage of complex sentences + - technical jargon +- Content is too abstract and detached from reality, therefore users are unable to relate to it +- Too many links inside articles result in readers feeling overloaded and leaving the website + +**Takeaways**: + +- Operate with a mindset that people are curious about crypto, but not invested enough to spend hours exploring the topics +- Users want to understand how the topic relates to them and how they can take a part in it rather than going deep into the theory + +Loosely we can categorize the site audiences as: + + + +**Example user journeys:** + +- "I want to learn more about Ethereum, to know if I think it’s credible or not. Once I’ve answered a few basic questions, I want to try using Ethereum" +- "I know I need an Ethereum wallet, and want a good recommendation" +- "I want to learn how to run an Ethereum node" +- "I want to get a sense of the size and activity of the Ethereum community, to decide if it's active enough, so I can get help if needed" +- "I’m excited about Ethereum and want to get involved, but I don’t know what to do next" + + + + + +**Example user journeys**: + +- "I'm a developer but I have no background in crypto and want to understand the Ethereum tech stack at a high level" +- "I want to get a sample Ethereum project up and running fast, to get a sense of how difficult or easy it is to build a real project on Ethereum" +- "I want to learn about Ethereum's technical roadmap" +- "I’ve started work on an Ethereum project, and want to try out a few smart contract testing libraries" + + + + + +**Example user journeys**: + +- "I want to understand what use cases Ethereum can help with, and how it compares to other chains or other technologies" +- "I work at a business that is beginning an Ethereum related project, and want to learn more" +- "I want to understand the differences between private Ethereum chains, consortium chains, and the public Ethereum Mainnet" +- "I want to know the current status of Ethereum - how long has it been in production, how much usage it has, what's the direction of new development - to decide if I am confident to build my project on top of it" + + + +## Best practices + +**Style** + +- Focus on the advantages for the user instead of explaining technical details about the system +- Use active voice and clear, concise sentences that are easy to follow +- Break up longer chunks of text into smaller sections or paragraphs +- Consider using tables, bullet points or numbered lists instead of paragraphs +- Highlight (bold) key phrases to support scanning and skimming through the article + +**Content ideas:** + +- Use examples or real-life scenarios of the application of the technology to help illustrate complex concepts or ideas +- Explain how the idea can positively affect people now or in the future +- Create before Ethereum / after Ethereum comparison +- Add step-by-step how to take action +- Include relevant statistics or graphs to strengthen the arguments +- Add calls to action +- Provide visual aids to explain the topic better + +**Other**: + +- Limit the length of the article up to 1000 words (1500 max) +- Reduce the number of hyperlinks to approximately 5 per 1000 words (excluding further reading section at the bottom of the page or product listings) + +### Objectivity + +Ethereum.org documentation (and content at large) aims to maintain a credibly neutral source of truth to inform readers about Ethereum and its ecosystem. Some examples of things that we don't want in the content on ethereum.org: + +**Grand, unverifiable claims about Ethereum or adjacent technologies** + +> e.g. _"Ethereum will take over the world because..."_ + +**Hostile or confrontational language aimed at any organization or person** + +> e.g. _"Company X is bad because they are centralized!"_ + +**Politically charged rhetoric** + +> e.g. _"This political party is better for decentralization because..."_ + +### Acronyms + +When introducing an unfamiliar acronym, spell out the full term, and put the acronym in parentheses. Put both the full term and acronym in bold. + +**For example:** + +"Ethereum, like Bitcoin, currently uses a consensus protocol called **proof-of-work (PoW)**." + +### Consistency + +Many of the topics covered on ethereum.org are technically complex. To reduce confusion to the reader, terms should be used consistently. For example, don't cycle back-and-forth between proof-of-work and PoW at random. + +[Content standardization](/contributing/style-guide/content-standardization/) - Read more about proper usage of terminology and other aspects such as how to properly add an image, attribute etc. + +## Anything else? + +Like all content on ethereum.org, this style guide is an open-source work-in-progress with room for improvement. If there is anything you think should be added to improve this document please [suggest an edit on GitHub](https://github.com/ethereum/ethereum-org-website/blob/dev/public/content/contributing/style-guide/index.md). + +--- + +## Contributing > Translation Program > Content Buckets + +# Content buckets + +As mentioned in our [Translation Program overview](/contributing/translation-program/), we use 'content buckets' within Crowdin to get the highest priority content released first. When you check out a language to translate, for example, [German](https://crowdin.com/project/ethereum-org/de) you'll see folders for each content bucket. + +Below is a breakdown of the website pages each content bucket contains. + +## 1) Homepage + +- [Ethereum.org homepage](/) +- Main navbar +- Footer links +- Language support + +## 2) Essential pages + +- [What is Ethereum?](/what-is-ethereum/) +- [What is ether (ETH)?](/eth/) +- [Get ETH](/get-eth/) +- [Wallets](/wallets/) +- [Find wallets](/wallets/find-wallet/) +- [Network fees](/gas/) + +## 3) Exploring + +- [Non-fungible tokens (NFT)](/nft/) +- [Dapps](/dapps/) +- [Stablecoins](/stablecoins/) +- Template usecase + +## 4) Use Ethereum pages + +- [Decentralized autonomous organizations (DAOs)](/dao/) +- [Layer 2](/layer-2/) +- [Run a node](/run-a-node/) +- [Developers' Home](/developers/) +- [Developer learning tools](/developers/learning-tools/) +- [Developer local environment setup](/developers/local-environment/) + +## 5) Use case pages + +- [Decentralized finance (DeFi)](/defi/) +- [Introduction to smart contracts](/smart-contracts/) +- [Decentralized identity](/decentralized-identity/) +- [Decentralized social networks](/social-networks/) +- [Decentralized science (DeSci)](/desci/) +- [Regenerative finance (ReFi)](/refi/) + +## 6) Staking pages + +- [Staking](/staking/) +- [Solo staking](/staking/solo/) +- [Pooled staking](/staking/pools/) +- [Staking as a service](/staking/saas/) +- [Staking deposit contract](/staking/deposit-contract/) +- [Staking withdrawals](/staking/withdrawals/) +- [Distributed validator technology](/dvt/) + +## 7) Learn pages + +- [Energy consumption](/energy-consumption/) +- [Governance](/governance/) +- [Ethereum security and scam prevention](/security/) +- [Blockchain bridges](/bridges/) +- [Web3](/web3/) +- [Zero-knowledge proofs](/zero-knowledge-proofs/) + +## 8) Learn hub & guides + +- [Learn hub](/learn/) +- [Ethereum guides](/guides/) +- [How to "create" an Ethereum account](/guides/how-to-create-an-ethereum-account/) +- [How to use a wallet](/guides/how-to-use-a-wallet/) +- [How to revoke smart contract access to your crypto funds](/guides/how-to-revoke-token-access/) +- [How to bridge tokens to layer 2](/guides/how-to-use-a-bridge/) +- [How to swap tokens](/guides/how-to-swap-tokens/) +- [How to identify scam tokens](/guides/how-to-id-scam-tokens/) +- [Learning quizzes](/quizzes/) + +## 9) Upgrades + +- [Ethereum roadmap](/roadmap/) +- [Ethereum vision](/roadmap/vision/) +- [The Beacon Chain](/roadmap/beacon-chain/) +- [The Merge](/roadmap/merge/) +- [How The Merge impacted ETH supply](/roadmap/merge/issuance/) +- [Ethereum Improvement Proposals (EIPs)](/eips/) +- [Scaling Ethereum](/roadmap/scaling/) +- [A more secure Ethereum](/roadmap/security/) +- [Improving user experience](/roadmap/user-experience/) +- [Future-proofing Ethereum](/roadmap/future-proofing/) +- [Danksharding](/roadmap/danksharding/) +- [Single slot finality](/roadmap/single-slot-finality/) +- [Proposer-builder separation](/roadmap/pbs/) +- [Secret leader election](/roadmap/secret-leader-election/) +- [Account abstraction](/roadmap/account-abstraction/) +- [Verkle trees](/roadmap/verkle-trees/) +- [Statelessness, state expiry and history expiry](/roadmap/statelessness/) + +## 10) Community pages + +- [Ethereum events](/community/events/) +- [How can I get involved?](/community/get-involved/) +- [Ethereum grants](/community/grants/) +- [Language resources](/community/language-resources/) +- [Online communities](/community/online/) +- [Ethereum support](/community/support/) +- [Community hub](/community/) +- [Code of conduct](/community/code-of-conduct/#code-of-conduct) + +## 11) Foundational developer docs + +- [Overview](/developers/docs/) +- [Intro to Ethereum](/developers/docs/intro-to-ethereum/) +- [Intro to ether](/developers/docs/intro-to-ether/) +- [Intro to dapps](/developers/docs/dapps) +- [Web2 vs Web3](/developers/docs/web2-vs-web3/) +- [Accounts](/developers/docs/accounts/) +- [Transactions](/developers/docs/transactions/) +- [Blocks](/developers/docs/blocks/) +- [Ethereum virtual machine (EVM)](/developers/docs/evm/) +- [Opcodes for the EVM](/developers/docs/evm/opcodes/) +- [Gas](/developers/docs/gas/) +- [Networks](/developers/docs/networks/) +- Developer docs sidebar + +## 12) Foundational docs - Nodes and clients + +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [Nodes as a service](/developers/docs/nodes-and-clients/nodes-as-a-service/) +- [Ethereum archive node](/developers/docs/nodes-and-clients/archive-nodes/) +- [Introduction to Ethereum bootnodes](/developers/docs/nodes-and-clients/bootnodes/) +- [Light clients](/developers/docs/nodes-and-clients/light-clients/) +- [Node architecture](/developers/docs/nodes-and-clients/node-architecture/) +- [Client diversity](/developers/docs/nodes-and-clients/client-diversity/) +- [Spin up your own Ethereum node](/developers/docs/nodes-and-clients/run-a-node/) + +## 13) Foundational docs - Proof-of-Stake + +- [Consensus mechanisms](/developers/docs/consensus-mechanisms/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Ethereum proof-of-stake attack and defense](/developers/docs/consensus-mechanisms/pos/attack-and-defense/) +- [Attestations](/developers/docs/consensus-mechanisms/pos/attestations/) +- [Block proposal](/developers/docs/consensus-mechanisms/pos/block-proposal/) +- [Proof-of-stake FAQs](/developers/docs/consensus-mechanisms/pos/faqs/) +- [Keys in proof-of-stake Ethereum](/developers/docs/consensus-mechanisms/pos/keys/) +- [Proof-of-stake rewards and penalties](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/) +- [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) +- [Weak subjectivity](/developers/docs/consensus-mechanisms/pos/weak-subjectivity/) +- [Proof-of-stake vs. proof-of-work](/developers/docs/consensus-mechanisms/pos/pos-vs-pow/) + +## 14) Foundational docs - Proof-of-Work + +- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) +- [Mining](/developers/docs/consensus-mechanisms/pow/mining/) +- [Mining algorithms](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/) +- [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/) +- [Ethash](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/) + +## 15) Ethereum stack developer docs + +- [Introduction to the Ethereum stack](/developers/docs/ethereum-stack/) +- [Deployment networks](/developers/docs/development-networks/) +- [Development frameworks](/developers/docs/frameworks/) +- [JavaScript APIs](/developers/docs/apis/javascript/) +- [Backend APIs](/developers/docs/apis/backend/) +- [JSON-RPC](/developers/docs/apis/json-rpc/) +- [Data and analytics](/developers/docs/data-and-analytics/) +- [Block explorers](/developers/docs/data-and-analytics/block-explorers/) +- [Storage](/developers/docs/storage/) +- [Integrated Development Environments (IDEs)](/developers/docs/ides/) +- [Programming languages](/developers/docs/programming-languages/) +- [Delphi](/developers/docs/programming-languages/delphi/) +- [.NET](/developers/docs/programming-languages/dot-net/) +- [Elixir](/developers/docs/programming-languages/elixir/) +- [Golang](/developers/docs/programming-languages/golang/) +- [Java](/developers/docs/programming-languages/java/) +- [JavaScript](/developers/docs/programming-languages/javascript/) +- [Python](/developers/docs/programming-languages/python/) +- [Rust](/developers/docs/programming-languages/rust/) +- [Ruby](/developers/docs/programming-languages/ruby/) +- [Dart](/developers/docs/programming-languages/dart/) + +## 16) Smart contracts - Basics + +- [Smart contracts](/developers/docs/smart-contracts/) +- [Smart contract languages](/developers/docs/smart-contracts/languages/) +- [Smart contract anatomy](/developers/docs/smart-contracts/anatomy/) +- [Smart contract libraries](/developers/docs/smart-contracts/libraries) +- [Compiling smart contracts](/developers/docs/smart-contracts/compiling) +- [Deploying smart contracts](/developers/docs/smart-contracts/deploying) +- [Smart contract security](/developers/docs/smart-contracts/security/) + +## 17) Smart contracts - Advanced + +- [Testing smart contracts](/developers/docs/smart-contracts/testing) +- [Composability](/developers/docs/smart-contracts/composability/) +- [Formal verification of smart contracts](/developers/docs/smart-contracts/formal-verification/) +- [Verifying smart contracts](/developers/docs/smart-contracts/verifying/) +- [Upgrading smart contracts](/developers/docs/smart-contracts/upgrading/) + +## 18) Whitepaper + +- [Whitepaper](/whitepaper/) + +## 19) Additional Learn pages + +- [History](/history/) +- [Glossary](/glossary/) +- [Zero-knowledge proofs](/zero-knowledge-proofs/) + +## 20) Advanced developer docs + +- [Standards](/developers/docs/standards/) +- [Token standards](/developers/docs/standards/tokens/) +- [ERC-20](/developers/docs/standards/tokens/erc-20/) +- [ERC-721](/developers/docs/standards/tokens/erc-721/) +- [ERC-777](/developers/docs/standards/tokens/erc-777/) +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) +- [ERC-4626](/developers/docs/standards/tokens/erc-4626/) +- [Maximal extractable value (MEV)](/developers/docs/mev/) +- [Oracles](/developers/docs/oracles/) +- [Bridges](/developers/docs/bridges/) +- [Data availability](/developers/docs/data-availability/) +- [Design and UX in Web3](/developers/docs/design-and-ux/) + +## 21) Advanced developer docs - Scaling + +- [Scaling](/developers/docs/scaling/) +- [Optimistic rollups](/developers/docs/scaling/optimistic-rollups/) +- [Zero-knowledge rollups](/developers/docs/scaling/zk-rollups/) +- [State channels](/developers/docs/scaling/state-channels) +- [Sidechains](/developers/docs/scaling/sidechains) +- [Plasma](/developers/docs/scaling/plasma) +- [Validium](/developers/docs/scaling/validium/) + +## 22) Research documentation + +- [Networking layer](/developers/docs/networking-layer/) +- [Patricia Merkle Trees](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) +- [Data structures and encoding](/developers/docs/data-structures-and-encoding/) +- [Recursive-length prefix (RLP) serialization](/developers/docs/data-structures-and-encoding/rlp/) +- [Network addresses](/developers/docs/networking-layer/network-addresses/) +- [Simple serialize](/developers/docs/data-structures-and-encoding/ssz/) +- [Web3 secret storage definition](/developers/docs/data-structures-and-encoding/web3-secret-storage/) +- [The Portal network](/developers/docs/networking-layer/portal-network/) + +## 23) Miscellaneous + +- [About ethereum.org](/about/) +- [Enterprise Ethereum](/enterprise/) +- [Brand assets](/assets/) +- [About the Ethereum Foundation](/foundation/) +- [Bug bounty program](/bug-bounty/) + +## 24) Contributing + +- [Contributing to ethereum.org](/contributing/) +- [Adding developer tools](/contributing/adding-developer-tools/) +- [Adding exchanges](/contributing/adding-exchanges/) +- [Adding glossary terms](/contributing/adding-glossary-terms/) +- [Adding layer 2s](/contributing/adding-layer-2s/) +- [Adding products](/contributing/adding-products/) +- [Adding staking products](/contributing/adding-staking-products/) +- [Adding content resources](/contributing/content-resources/) +- [Adding DeSci projects](/contributing/adding-desci-projects/) +- [Adding wallets](/contributing/adding-wallets/) +- [Adding a quiz](/contributing/quizzes/) +- [Adding design resources](/contributing/design/adding-design-resources/) +- [Design contribution to ethereum.org](/contributing/design/) +- [Design principles](/contributing/design-principles/) +- [Translation Program](/contributing/translation-program/) +- [Translation guide](/contributing/translation-program/translation-guide/) +- [Translator acknowledgements](/contributing/translation-program/) +- [Our translators](/contributing/translation-program/contributors/) +- [Translation FAQ](/contributing/translation-program/faq/) +- [How to translate](/contributing/translation-program/how-to-translate/) +- [Translation Program mission and vision](/contributing/translation-program/mission-and-vision/) +- [Translator resources](/contributing/translation-program/resources/) + +## 25) Developer tutorials 1 + +- [Calling a smart contract from JavaScript](/developers/tutorials/calling-a-smart-contract-from-javascript/) +- [How to write & deploy an NFT (Part 1/3 of NFT tutorial series)](/developers/tutorials/how-to-write-and-deploy-an-nft/) +- [How to mint an NFT (Part 2/3 of NFT tutorial series)](/developers/tutorials/how-to-mint-an-nft/) +- [How to view your NFT in your wallet (Part 3/3 of NFT tutorial series)](/developers/tutorials/how-to-view-nft-in-metamask/) +- [Understand the ERC-20 token smart contract](/developers/tutorials/understand-the-erc-20-token-smart-contract/) +- [Uniswap-v2 contract walkthrough](/developers/tutorials/uniswap-v2-annotated-code/) +- Submit a tutorial + +## 26) Developer tutorials 2 + +- [A Python developer's introduction to Ethereum](/developers/tutorials/a-developers-guide-to-ethereum-part-one/) +- [Downsizing contracts to fight the contract size limit](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) +- [Hello world smart contract for beginners](/developers/tutorials/hello-world-smart-contract/) +- [How to turn your Raspberry Pi 4 into a node just by flashing the MicroSD card](/developers/tutorials/run-node-raspberry-pi/) +- [Interact with other contracts from Solidity](/developers/tutorials/interact-with-other-contracts-from-solidity/) +- [NFT Minter tutorial](/developers/tutorials/nft-minter/) +- [Reverse engineering a contract](/developers/tutorials/reverse-engineering-a-contract/) +- [Sending tokens using ethers.js](/developers/tutorials/send-token-ethersjs/) +- [The Graph: Fixing Web3 data querying](/developers/tutorials/the-graph-fixing-web3-data-querying/) +- [Transfers and approval of ERC-20 tokens from a Solidity smart contract](/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/) +- [Understanding the Yellowpaper's EVM specifications](/developers/tutorials/yellow-paper-evm/) + +## 27) Developer tutorials 3 + +- [A guide to smart contract security tools](/developers/tutorials/guide-to-smart-contract-security-tools/) +- [All you can cache](/developers/tutorials/all-you-can-cache/) +- [EIP-1271: Signing and verifying smart contract signatures](/developers/tutorials/eip-1271-smart-contract-signatures/) +- [ERC-20 contract walkthrough](/developers/tutorials/erc20-annotated-code/) +- [ERC-20 with safety rails](/developers/tutorials/erc20-with-safety-rails/) +- [Getting Started with Ethereum Development](/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/) +- [How to mock Solidity smart contracts for testing](/developers/tutorials/how-to-mock-solidity-contracts-for-testing/) +- [Kickstart your dapp frontend development with create-eth-app](/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/) +- [Logging data from smart contracts with events](/developers/tutorials/logging-events-smart-contracts/) +- [Merkle proofs for offline data integrity](/developers/tutorials/merkle-proofs-for-offline-data-integrity/) +- [Sending transactions using Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) +- [Smart contract security checklist](/developers/tutorials/secure-development-workflow/) +- [Testing simple smart contract with Waffle library](/developers/tutorials/waffle-test-simple-smart-contract/) +- [Vyper ERC-721 contract walkthrough](/developers/tutorials/erc-721-vyper-annotated-code/) + +## 28) Developer tutorials 4 + +- [Create and deploy a DeFi app](/developers/tutorials/create-and-deploy-a-defi-app/) +- [Deploying your first smart contract](/developers/tutorials/deploying-your-first-smart-contract/) +- [How to implement an ERC-721 market](/developers/tutorials/how-to-implement-an-erc721-market/) +- [How to set up Tellor as your oracle](/developers/tutorials/how-to-use-tellor-as-your-oracle/) +- [How to use Echidna to test smart contracts](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) +- [How to use Manticore to find bugs in smart contracts](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) +- [How to use Slither to find smart contract bugs](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) +- [Learn foundational Ethereum topics with SQL](/developers/tutorials/learn-foundational-ethereum-topics-with-sql/) +- [Monitoring Geth with InfluxDB and Grafana](/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/) +- [Optimism standard bridge contract walkthrough](/developers/tutorials/optimism-std-bridge-annotated-code/) +- [Set up web3.js to use the Ethereum blockchain in JavaScript](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) +- [Short ABIs for calldata optimization](/developers/tutorials/short-abi/) +- [Smart contract security guidelines](/developers/tutorials/smart-contract-security-guidelines/) +- [Testing ERC-20 tokens with Waffle](/developers/tutorials/testing-erc-20-tokens-with-waffle/) +- [Token integration checklist](/developers/tutorials/token-integration-checklist/) +- [Using WebSockets](/developers/tutorials/using-websockets/) +- [Waffle: Dynamic mocking and testing contract calls](/developers/tutorials/waffle-dynamic-mocking-and-testing-calls/) +- [Waffle say hello world tutorial with Hardhat and ethers](/developers/tutorials/waffle-say-hello-world-with-hardhat-and-ethers/) + +--- + +## Contributing > Translation Program > Faq + +# Translating ethereum.org guide + +If you're new to the Translation Program and are hesitant to jump in, here are some FAQs that can help you begin. Use this guide to find answers to the most common queries. + +## Can I get compensated for translating ethereum.org? + +Ethereum.org is an open-source website, which means that anyone can get involved and contribute. + +The ethereum.org Translation Program is an extension of that and is organized with a similar philosophy in mind. + +The goal of the Translation Program is to make Ethereum content accessible to everyone, regardless of the languages they speak. It also allows any bilingual person to get involved with the Ethereum ecosystem and contribute in an accessible way. + +For this reason, the Translation Program is open and voluntary, and participation is not subject to compensation. If we were to compensate translators for the number of words they translate, we could only invite those with sufficient translation experience (professional translators) to join the Translation Program. This would make the Translation Program exclusionary and prevent us from reaching the outlined goals, specifically: allowing everyone to participate and get involved with the ecosystem. + +We make every effort to enable our contributors to succeed in the Ethereum ecosystem; many non-monetary incentives are in place such as: [offering POAPs](/contributing/translation-program/acknowledgements/#poap) and a [translator certificate](/contributing/translation-program/acknowledgements/#certificate), as well as organizing the [Translation Leaderboards](/contributing/translation-program/acknowledgements/) and [listing all of our translators on the site](/contributing/translation-program/contributors/). + +## How do I translate strings with ``? + +Not every string is written in pure text form. There are some strings that consist of mixed scripts like HTML tags (``, ``).This is usually for hyperlinks or alternative styling in the middle of a sentence. + +- Translate the text inside the tags but not the tags themselves. Anything in the `` must not be translated or removed. +- To keep the string safe, we recommend that you click the "Copy Source" button on the bottom left. This will copy the original string and paste it into the text box. This lets you clarify where the tags are and helps you avoid mistakes. + +![Crowdin interface with copy source button highlighted](./html-tag-strings.png) + +You can move the position of the tags within the string to make it more natural in your language – just be sure to move the whole tag. + +For more in-depth information on dealing with tags and code snippets, please refer to the [ethereum.org Translation Style Guide](/contributing/translation-program/translators-guide/#dealing-with-tags). + +## Where do the strings live? + +Often the source strings alone might not be enough for you to provide an accurate translation. + +- Take a look at "screenshots" and "context" for more information. In the source string section, you will see the screenshot image attached which will show you how we're using the string in context. +- If you are still unsure, raise a flag in the "comment section". [Not sure how to leave a comment?](#comment) + +![Showing how context can be provided for a string with a screenshot](./source-string.png) + +![An example screenshot added for context](./source-string-2.png) + +## How can I leave comments or ask questions? I would like to flag an issue or typos... + +If you want to raise a flag on a particular string that needs attention, feel free to submit a comment. + +- Click the second button of the top-right bar. The hidden tab will appear on your right. Leave a new comment and click the "Issue" checkbox on the bottom. You can specify the type of issue by choosing one of the options from the drop-down menu. +- Once submitted, it will be reported to our team. We will fix the issue and let you know by replying to your comment and closing the issue. +- If you report an incorrect translation, the translation and your suggested alternative will be reviewed by a native speaker during the next review. + +![Showing how to make comments and issues](./comment-issue.png) + +## What is Translation Memory (TM)? + +Translation Memory (TM) is a feature of Crowdin that stores all the previously translated strings across [ethereum.org](http://ethereum.org/). When a string is translated, it is automatically saved into our project TM. This could be a useful tool to help you save your time! + +- Look at the "TM and MT Suggestions" section and you will see how other translators translated the same or similar string. If you find a suggestion with a high matching rate, feel free to refer to the translation by clicking it. +- If there is nothing on the list, you can search the TM for previously made translations and reuse them for consistency. + +![A screenshot of the translation memory](./translation-memory.png) + +## How do I use the Crowdin glossary? + +Ethereum terminology is another crucial part of our translation work as often new tech terms will not be localized in many languages yet. Also, there are terms that have different meanings in different contexts. [More on translating Ethereum terminology](#terminology) + +The Crowdin glossary is the best place for clarification of terms and definitions. There are two ways to refer to the glossary. + +- First, when you find an underlined term on the source string, you can mouse over and see a brief definition of it. + +![An example glossary definition](./glossary-definition.png) + +- Second, If you see a term that is not familiar to you but not underlined, you can search in the glossary tab (the third button of the right column). You will find explanations of specific terms and ones frequently used in the project. + +![A screenshot showing where to find the glossary tab in Crowdin](./glossary-tab.png) + +- If you still can't find it, it's your chance to add a new term! We encourage you to look it up on a search engine and add the description to the glossary. It will be of great help to other translators to better understand the term. + +![A screenshot showing how to add a glossary term to Crowdin](./add-glossary-term.png) + +### Terminology translation policy + +_For names (brands, companies, people) and new tech terms (Beacon Chain, shard chains, etc.)_ + +Ethereum presents a lot of new terms that have been coined recently. Some terms will vary from translator to translator as there is no official translation in their respective language. Such inconsistencies can cause misunderstanding and decrease readability. + +Due to the linguistic diversity and different standardizations in each language, it has been nearly impossible to come up with a unified terminology translation policy that can be adapted in all supported languages. + +After careful consideration, we have reached the decision to leave the most frequently used terminology up to you, the translators. + +Here is what we suggest, when you find a term that's unfamiliar to you: + +- Refer to the [Glossary of terms](#glossary), you may find how other translators have previously translated it. If you think the previously translated term is not appropriate, feel free to restore your translation by adding a new term to Crowdin Glossary. +- If such a previous translation doesn't exist in the Glossary, we encourage you to look it up on a search engine or media article that shows how the term is actually used in your community. +- If you don't find any references at all, feel free to trust your intuition and suggest a new translation to your language! +- If you feel less confident to do so, leave the term untranslated. Sometimes, English terms are more than adequate in delivering accurate definitions. + +We recommend you leave names of brands, companies, and personnel untranslated as a translation might cause unnecessary confusion and SEO difficulties. + +## How does the review process work? + +To ensure a certain level of quality and consistency in our translations, we work with [Acolad](https://www.acolad.com/), one of the largest language service providers globally. Acolad has 20,000 professional linguists, which means that they can provide professional reviewers for every language and type of content we need. + +The review process is straightforward; once a certain [content bucket](/contributing/translation-program/content-buckets) is 100% translated, we order a review for that content bucket. The review process takes place directly in Crowdin. Once the review is complete, we update the website with the translated content. + +## How do I add content in my language? + +Currently, all non-English content is translated directly from the English source content, and any content that does not exist in English cannot be added to other languages. + +To suggest new content for ethereum.org, you can [create an issue](https://github.com/ethereum/ethereum-org-website/issues) on GitHub. If added, the content will be written in English and translated to other languages using Crowdin. + +We plan to add support for non-English content additions in the near future. + +## Get in touch + +Thank you for reading through all of these. We hope this helps you to onboard our program. Feel free to join our [Discord translation channel](https://discord.gg/ethereum-org) to ask questions and collaborate with other translators, or reach out to us at translations@ethereum.org! + +--- + +## Contributing > Translation Program > How To Translate + +# How to translate + +## Visual guide + +For more visual learners, watch Luka walk through getting set up with Crowdin. Alternatively, you can find the same steps in a written format in the next section. + + + +## Written guide + +### Join our project in Crowdin + +You will need to log in to your Crowdin account or sign up if you don’t already have one. All that is required to sign up is an e-mail account and password. + + + Join project + + +### Open your language + +After logging in to Crowdin, you will see a project description and list of all available languages. +Each language also contains information on the total amount of translatable words and an overview of how much content has been translated and approved in a specific language. + +Open the language you want to translate into to see the list of files, available for translation. + +![List of languages in Crowdin](./list-of-languages.png) + +### Find a document to work on + +The website content is divided into a number of documents and content buckets. You can check the progress of each document on the right – if translation progress is below 100%, please contribute! + +Don't see your language listed? [Open an issue](https://github.com/ethereum/ethereum-org-website/issues/new/choose) or ask in our [Discord](/discord/) + +![Translated and untranslated files in Crowdin](./crowdin-files.png) + +A note on content buckets: we use 'content buckets' within Crowdin to get the highest priority content released first. When you check out a language, for example, [Filipino](https://crowdin.com/project/ethereum-org/fil#) you'll see folders for content bucket ("1. Homepage", "2. Essentials", "3. Exploring", etc.). + +We encourage you to translate in this numerical order (1 → 2 → 3 → ⋯) to ensure the highest impact pages are translated first. + +[Learn more about ethereum.org content buckets](/contributing/translation-program/content-buckets/) + +### Translate + +After selecting the file you want to translate, it will open in the online editor. If you have never used Crowdin before, you can use this quick guide to go over the basics. + +![Crowdin online editor](./online-editor.png) + +**_1 – Left sidebar_** + +- Untranslated (red) – text that has not been worked on yet. These are the strings that you should be translating. +- Translated (green) – text that has already been translated, but not yet reviewed. You are welcome to suggest alternate translations, or vote on existing ones using the ‘’+’’ and ‘’-‘‘ buttons in the editor. +- Approved (check mark) – text that has already been reviewed and is currently live on the website. + +You can also use the buttons on top to search for specific strings, filter them by status or change the view. + +**_2 – Editor area_** + +The main translation area – source text is displayed on top, with additional context and screenshots, if available. +To suggest a new translation, enter your translation in the ‘’Enter translation here’’ field and click Save. + +You can also find existing translations of the string and translations into other languages in this section, as well as translation memory matches and machine translation suggestions. + +**_3 – Right sidebar_** + +This is where you can find comments, translation memory entries and glossary entries. The default view shows the comments and allows translators to communicate, raise issues or report incorrect translations. + +By using the buttons on top, you can also switch to the Translation Memory, where you can search for existing translations, or to the Glossary, which contains descriptions and standard translations of key terms. + +Want to learn more? Feel free to check out the [documentation on using the Crowdin online editor](https://support.crowdin.com/online-editor/) + +### Review process + +Once you've completed the translation (i.e. all files for a content bucket display 100%), our professional translation service will review (and potentially edit) the content. Once the review is complete (i.e. review progress is 100%), we will add it to the website. + + + Please do not use machine translation to translate the project. All the translations will be reviewed before being added to the website. If your suggested translations are found to be machine translated, they will be dismissed and contributors who use machine translation often will be removed from the project. + + +### Get in touch + +Do you have any questions? Or want to collaborate with our team and other translators? Please post in the #translations channel of our [ethereum.org Discord server](/discord/) + +You can also reach out to us at translations@ethereum.org + +Thank you for your participation in the ethereum.org Translation Program! + +--- + +## Contributing > Translation Program + +# Translation Program + +The Translation Program is a collaborative effort to translate ethereum.org into different languages in order to make the website more accessible to billions of non-English speakers around the world. + +![](./enterprise-eth.png) + +## Help us translate + +The ethereum.org Translation Program is open and anyone can contribute! + +1. You will need to log in to your Crowdin account or sign up. +2. Select the language you want to contribute to. +3. Before starting, please check out the [How to translate](/contributing/translation-program/how-to-translate/) guide to learn how to use Crowdin, and the [Translation Style Guide](/contributing/translation-program/translators-guide/) for tips and best practices. +4. Machine translations will not be approved. +5. All translations are reviewed before being added to the site, so there will be a short delay before your translations go live. + +_Join the [ethereum.org Discord](/discord/) to collaborate on translations, ask questions, share feedback and ideas, or join a translation group._ + + + Start translating + + +## About the Translation Program + +The Ethereum community aims to be global and inclusive, yet much of its content only caters to English speakers, leaving out the world's 6 billion non-English speakers. For ethereum.org to act as the portal into Ethereum for the worldwide community, we believe providing non-English speakers with Ethereum content in their native languages is essential. + +The ethereum.org Translation Program aims to make Ethereum accessible to everyone by translating ethereum.org and other Ethereum content into as many languages as possible. + +Read more about the ethereum.org Translation Program [mission and vision](/contributing/translation-program/mission-and-vision). + +### Our progress so far + +- [**6,900 +** translators](/contributing/translation-program/contributors/) +- **68** languages live on site +- [**2.89 million** words translated in 2024](/contributing/translation-program/acknowledgements/) + + + +### Acknowledgements + +Ethereum.org is translated by thousands of community members and they are the key part of the Translation Program. +We want to acknowledge our translators and support them on their career paths. Here are some of our translator acknowledgements: + +#### Certificate + +If you have contributed to the Translation Program and at least 5,000 of your translated words have been approved, you are eligible for an ethereum.org translator certificate. [More on certificates](/contributing/translation-program/acknowledgements/#certificate) + +#### OATs + +Contributors to the Translation Program are eligible for different OATs (onchain achievement tokens) based on their number of translated words in 2024. OATs are NFTs that prove your contribution to the ethereum.org Translation Program. [More on OATs](/contributing/translation-program/acknowledgements/#oats) + +#### Translator acknowledgements + +Public acknowledgements of our top translators using [leaderboards](/contributing/translation-program/acknowledgements/) and a [list of all contributors to the Translation Program](/contributing/translation-program/contributors/). + +#### Rewards + +In the past, we have retroactively rewarded our most active contributors with tickets to Ethereum conferences like [Devcon](https://devcon.org/en/) and [Devconnect](https://devconnect.org/), as well as exclusive ethereum.org merch. + +We're constantly thinking of new and innovative ways to reward our contributors, so stay tuned! + +### Guides and resources + +If you are contributing to the Translation Program or thinking about getting involved, you should check out the translation guides below: + +- [Translation Style Guide](/contributing/translation-program/translators-guide/) _– instructions and tips for ethereum.org translators_ +- [Translation FAQs](/contributing/translation-program/faq/) _– frequently asked questions and answers about the ethereum.org Translation Program_ +- [Crowdin online editor guide](https://support.crowdin.com/online-editor/) _– an in-depth guide to using the Crowdin online editor and some of Crowdin's advanced features_ +- [Content buckets](/contributing/translation-program/content-buckets/) _– which pages are included in each content bucket of ethereum.org_ + +For other useful translation tools, translator communities and Translation Program blog posts, please visit the [Resources page](/contributing/translation-program/resources/). + +## Get in touch + +Do you have any questions? Or want to collaborate with our team and other translators? Please post in the #translations channel of our [ethereum.org Discord server](https://discord.gg/ethereum-org) + +You can also reach out to us at translations@ethereum.org + +## Starting your own translation program + +We are dedicated to translating Ethereum content into as many languages as possible and making educational content available to everyone. +In line with our focus on translations, we want to help other Ethereum projects organize, manage, and improve their own translation efforts. + +For this reason, we have created a [Translation Program playbook](/contributing/translation-program/playbook/) that contains some tips and best practices we have picked up in the process of translating ethereum.org. + +Want to collaborate further or use some of our translation resources? Have any feedback on the playbook? We would love to hear from you at translations@ethereum.org. + +--- + +## Contributing > Translation Program > Mission And Vision + +# Mission and vision + +The Ethereum community aims to be global and inclusive, yet much of its content only caters to English speakers, leaving out the world's 6 billion non-English speakers. For ethereum.org to act as the portal into Ethereum for the worldwide community, we believe providing non-English speakers with Ethereum content in their native languages is essential. + +The ethereum.org Translation Program aims to make Ethereum accessible to everyone by translating ethereum.org and other Ethereum content into as many languages as possible. + +## Our mission + +- Provide translated versions of the website to empower visitors worldwide to learn about Ethereum in their native language +- Facilitate the onboarding of more members to the global Ethereum community +- Allow for more accessible and more inclusive sharing of Ethereum information and knowledge +- Empower community members to contribute translations to Ethereum and make their mark on the ecosystem +- Identify, connect with, and provide guidance to passionate contributors looking to get involved in the ecosystem + +## Our vision + +- Translate essential content for members of the Ethereum community from as many countries and parts of the world as possible +- Support knowledge sharing across languages to create a better informed and educated Ethereum community +- Increase Ethereum's inclusivity and accessibility by removing the language barriers preventing non-English speakers from joining the ecosystem + +--- + +## Contributing > Translation Program > Playbook + +# Translation Program Playbook + +English is one of the most spoken languages in the world and is by far the world’s most studied language. As English is the most common language used on the internet – especially on social media – and multilingual programming languages are scarce, the majority of content in the blockchain space is natively written in English. + +However, as over 6 billion people in the world (more than 75% of the population) do not speak English at all, this presents a massive barrier for entry to Ethereum for the vast majority of the world’s population. + +For this reason, an increasing number of projects in the space are looking to get their content translated into different languages and localized for global communities. + +Providing multilingual content is a simple and effective way of growing your global community, providing education to non-English speakers, making sure your content and communications reach a wider audience, and onboarding more people to the space. + +This guide aims to address the common challenges and misconceptions about content localization. It provides a step-by-step guide to managing content, the translation and review process, quality assurance, translator outreach, and other vital aspects of the localization process. + +## Content Management + +Translation content management refers to the process of automating the translation workflow, which removes the need for repetitive manual work, improves efficiency and quality, allows for better control, and enables collaboration. + +There are many different approaches to content management in the localization process, depending on the content and your needs. + +The fundamental way of managing content is to create bilingual files, containing the source and target text. This is rarely used in translation, since it offers no significant advantages, apart from simplicity. + +Translation agencies usually approach translation management by using translation management software or localization tools, which provide project management capabilities and allow for much greater control over the files, content, and linguists. + +Read more about content management: + +[Trados on what is translation management](https://www.trados.com/solutions/translation-management/) + +[Phrase on multilingual content management](https://phrase.com/blog/posts/multilingual-content-management/) + +### Translation Management Software + +There are many translation management systems and localization tools, and the choice of software depends mainly on your needs. + +While some projects decide against using translation management systems and prefer to handle translations manually – either directly in bilingual files or on hosting services, such as GitHub – this dramatically reduces control, productivity, quality, scalability, and collaboration capabilities. Such an approach might be most beneficial for small-scale or one-off translation projects. + +A quick look at some of the most powerful and widely used translation management tools: + +**Best for crowdsourcing and collaboration** + +[Crowdin](https://crowdin.com/) + +- Free for open-source projects (unlimited number of strings and projects) +- TM and glossary available with all plans +- 60+ supported file formats, 70+ API integrations + +[Lokalise](https://lokalise.com/) + +- Free for 2 team members, paid plans for more contributors (limited number of strings for most plans) +- TM and glossary available with some paid plans +- 30+ supported file formats, 40+ API integrations + +[Transifex](https://www.transifex.com/) + +- Only paid plans (limited number of strings for most plans) +- TM and glossary available with all paid plans +- 30+ supported file formats, 20+ API integrations + +[Phrase](https://phrase.com/) + +- Only paid plans (unlimited number of strings for all plans, limited number of projects and team members) +- TM and glossary available with some paid plans +- 40+ supported file formats, 20+ API integrations + +[Smartcat](https://www.smartcat.com/) + +- Basic free plan with payable advanced features (unlimited number of strings and projects for all plans) +- TM and glossary available with all plans +- 60+ supported file formats, 20+ API integrations + +[POEditor](https://poeditor.com/) + +- Free for open-source projects (limited number of strings for all projects, unlimited for open-source projects) +- TM and glossary available for paid plans +- 20+ supported file formats, 10+ API integrations + +and many others... + +**Professional translation tools** + +[SDL Trados Studio](https://www.trados.com/products/trados-studio/) + +- Paid plans for freelance translators and teams +- Very powerful computer-assisted translation (CAT) tool and translator productivity software + +[MemoQ](https://www.memoq.com/) + +- Limited free version available with several paid plans for advanced features +- Translation management software for companies, language service providers and translators + +[Memsource](https://www.memsource.com/) + +- Free for individual translators with several paid plans for teams +- Cloud-based computer-assisted translation and translation management system + +and many others... + +Read more about translation management software: + +[Wikipedia definition of translation management systems](https://en.wikipedia.org/wiki/Translation_management_system) + +[Phrase on 7 things every translation management software should have](https://phrase.com/blog/posts/7-things-every-translation-management-software-should-have/) + +[MemoQ on what is a translation management system](https://www.memoq.com/tools/what-is-a-translation-management-system) + +[Gengo’s list of 16 best translation management systems](https://gengo.com/translator-product-updates/16-best-translation-management-systems/) + +## Workflow + +In the translation space, translation workflow can mean a couple of different things, both somewhat interrelated, and important considerations for your project. + +We will explore both of them below. + +**Meaning 1** + +This is probably the most common way of thinking about translation workflows and something that usually comes to mind when hearing the word workflow. + +In its essence, it is the ‘flow of work’ from starting to think about translations to using the translated content in your product. + +An example workflow in this case would be: + +1. **Preparing the files for translation** – It sounds simple; however, you need to consider a couple of important things. At this step, you should have a clear plan on how the entire process should work. + +- _Which file types will you be using? What format do you want to receive your translated files in?_ + - If your content is available in DOCX or MD format, the approach will be much more straightforward than if you are translating a PDF version of your Whitepaper or other documents. +- _Which localization tools support this file type? Can the file be translated in a way that retains the original formatting?_ + - Not all file types support direct localization (e.g., PDF files, image files), and not all localization tools support all file types. +- _Who will be translating the content? Will you be ordering professional translations or relying on volunteers?_ + - This affects a number of other decisions you need to make. For example, professional translators are more comfortable working with advanced localization tools than volunteers. +- _What are your expectations for the linguists? If you are using a language service provider, what do they expect from you?_ + - This is the step to make sure your goals, expectations, and timelines are aligned. +- _Is all the content for translation equally important? Should some content be translated first?_ + - There are some ways to prioritize certain content, which should be translated and implemented first. For example, if you have a lot of content for translation, you can use version control to make sure the translators are aware of which they should prioritize. + +2. **Sharing the files for translation** – This step also requires some long-term thinking and is not as straightforward as sending the source files to a language service provider. + +- _Who will be translating the content? How many people will be involved in this process?_ + - If you plan to use a localization tool, this step is simplified since you can upload the source files to the tool directly. This is also true if the translation process takes place on the hosting service since the source files don’t need to be exported anywhere. +- _Will the source files be handled manually, or can this process be automated?_ + - Most localization tools allow for some type of integration or automation of the file management process. On the other hand, if you are working with individual translators and not using a localization tool, manually sending source files to hundreds or thousands of translators is not a scalable process. +- _Which tools will be used for the localization?_ + - The answer to this question will determine how you approach everything else. Selecting the proper tool can help you automate content management, managing the Translation Memory and Glossary, managing translators, keeping track of the translation/review progress, etc., so take some time and do some research on which tool you want to use. If you are not planning on using a localization tool, all of the above will need to be done manually. +- _How long will the translation process take? How much will it cost?_ + - At this point, you should be ready to share the source files with the language service provider or pool of translators. The language service provider can help you analyze the word count and provide a quote, including the rates and timeline for the translation process. +- _Are you planning on making changes/updating the source content during this process?_ + - If your content is dynamic and changes often, any changes or updates can disrupt the translation progress. Using a Translation Memory can help mitigate this significantly, though it is still important to think about how the process will work and how you can prevent setting back the progress the translators are making. + +3. **Managing the translation process** – Your work isn’t done once the source content is handed off to the language service provider or the translators. To ensure optimal quality of the translations, content creators should be as involved with the translation process as possible. + +- _How are you planning on communicating with the translators?_ + - If you are planning on using a localization tool, the communication can take place directly in the tool. Setting up an alternative communication channel with the translators is also recommended since they might be less hesitant to reach out, and messaging tools allow for more free-flowing communication. +- _How to handle questions from translators? Who should be answering these questions?_ + - Translators (both professional and non-professional) will often reach out with questions and requests for clarification or additional context, as well as feedback and ideas for improvements. Replying to these inquiries can often lead to better engagement and quality of translated content. It is also valuable to provide them with as many resources as possible (e.g., guides, tips, terminology guidelines, FAQs, etc.). +- _How to handle the review process? Do you want to outsource it, or do you have the capacity to perform reviews internally?_ + - While not always necessary, reviews are an integral part of an optimal translation process. Usually, it is easiest to outsource the review process to professional reviewers. However, if you have a large international team, the reviews or QA can also be handled internally. + +4. **Implementing the translated content** – The last part of the workflow, though still important to consider ahead of time. + +- _Will all the translations be completed at the same time?_ + - If not, you should think about which translations should be prioritized, how to keep track of the translations in progress, and how the implementation is handled while the translations are done. +- _How will the translated content be delivered to you? What format will it be in?_ + - This is an important consideration, regardless of which approach you use. Localization tools allow you to maintain control over the target file format and export process and usually support automation, e.g., by enabling integration with the hosting service. +- _How will you be implementing the translations in your project?_ + - In some cases, this could be as simple as uploading the translated file or adding it to your docs. However, with more complex projects, like website or app translations, you should make sure the code supports internationalization and establish how the implementation process will be handled ahead of time. +- _What happens if the formatting is different to the source?_ + - Similar to the above, if you are translating simple text files, the formatting probably isn’t crucially important. However, with more complex files, like content for a website or application, the formatting and code need to be identical to the source in order to be implemented in your project. If not, the target files will need to be edited, either by the translators or your developers. + +**Meaning 2** + +An alternative translation workflow, which does not account for internal decisions and approaches. The main consideration here is the flow of the content itself. + +An example workflow in this case would be: + +1. _Translation → Implementation_ + +- The simplest workflow, where the translation will likely be human translation, since there is no review or QA process to evaluate the quality and edit the translations before implementation. +- With this workflow, it is important that the translators can maintain a certain level of quality, which will require appropriate resources and communication between the project managers and translators. + +2. _Translation → Review → Implementation_ + +- A more advanced workflow, which includes a review and editing process, to ensure the quality of the translations is acceptable and consistent. +- There are a number of approaches to this workflow, where the translations could be performed by professional translators or volunteers, while the review process will likely be handled by professional reviewers, who are familiar with all the grammar and orthography rules that need to be observed in the target language. + +3. _Translation → Review → QA → Implementation_ + +- The optimal workflow to ensure the highest level of quality. While QA is not always necessary, it could be useful to give you a better sense of the quality of the translated text after translation and review. +- With this workflow, translations could be performed exclusively by volunteers or even machine translation. The review process should be performed by professional translators, while the QA can be performed by a language service provider or internally, if you have employees who are native speakers of the target languages. + +Read more about translation workflows: + +[Content rules on the five phases of the translation workflow](https://contentrules.com/creating-translation-workflow/) + +[Smartling on what is translation workflow management](https://www.smartling.com/resources/101/what-is-translation-workflow-management/) + +[RixTrans on the translation workflow](https://www.rixtrans.com/translation-workflow) + +## Terminology Management + +Establishing a clear plan on how to handle terminology is one of the most important steps to ensure the quality and consistency of your translations and save your translators time. + +In the translation space, this is known as terminology management and is one of the key services language service providers offer their clients, in addition to access to their pool of linguists and content management. + +Terminology management refers to the process of identifying, gathering, and managing terminology that is important for your project and should always be translated correctly and consistently. + +There are a couple of steps to follow when starting to think about terminology management: + +- Identify key terms that should be included in the termbase. +- Create a glossary of terms and their definitions. +- Translate the terms and add them to the glossary. +- Check and approve the translations. +- Maintain the glossary and update it with new terms, as they become important. + +Read more about terminology management: + +[Trados on what is terminology management](https://www.trados.com/solutions/terminology-management/translation-101-what-is-terminology-management.html) + +[Language Scientific on why terminology management matters](https://www.languagescientific.com/terminology-management-why-it-matters/#:~:text=Terminology%20management%20is%20the%20process,are%20related%20to%20each%20other.) + +[Clear Words Translation on what is terminology management and why it matters](http://clearwordstranslations.com/language/en/what-is-terminology-management/) + +### Translation Memory and Glossary + +The Translation Memory and Glossary are important tools in the translation industry and something most language service providers rely on. + +Let’s look at what these terms mean and how they are different to each other: + +**Translation memory (TM)** – A database that automatically stores segments or strings, including longer blocks of text, complete sentences, paragraphs, and individual terms, as well as their current and previous translations in every language. + +Most localization tools, translation management systems, and computer-assisted translation tools have built-in translation memories, which can usually be exported and used in other similar tools as well. + +The benefits of using a translation memory include faster translations, better translation quality, the ability to retain certain translations when updating or changing source content, and cheaper translation costs for repetitive content. + +Translation memories work based on a percentage match between different segments and are usually most useful when two segments contain over 50% of the same content. They are also used to automatically translate repetitive segments, which are 100% matches, thus removing the need to ever translate repetitive content more than once. + +Read more about translation memories: + +[Memsource on translation memories](https://www.memsource.com/translation-memory/) + +[Smartling on what is a translation memory](https://www.smartling.com/resources/101/what-is-translation-memory/) + +**Glossary –** A list of important or sensitive terms, their definitions, functions, and established translations. The main difference between a glossary and a translation memory is that a glossary is not created automatically, and that it does not contain translations of full sentences. + +Most localization tools, translation management systems, and computer-assisted translation tools have built-in glossaries that you can maintain to ensure they contain terminology important for your project. Like the TM, the glossary can usually be exported and used in other localization tools. + +Before starting your translation project, it is highly recommended to take some time and create a glossary for your translators and reviewers. Using a glossary ensures that important terms are translated correctly, provides translators with much-needed context, and guarantees consistency in translations. + +While glossaries most often contain established translations in the target languages, they are also useful without this. Even without established translations, a glossary can have definitions of technical terms, highlight terms that should not get translated, and inform translators whether a specific term is used as a noun, verb, proper noun, or any other part of speech. + +Read more about glossaries: + +[Lionbridge on what is a translation glossary](http://info.lionbridge.com/rs/lionbridge/images/Lionbridge%20FAQ_Glossary_2013.pdf) + +[Transifex on glossaries](https://docs.transifex.com/glossary/glossary) + +If you are not planning on using a localization tool for your project, you will likely not be able to use a translation memory and glossary (you could create a glossary or termbase in an excel file, however, automated glossaries remove the need for translators to manually look for terms and their definitions). + +This means that all repetitive and similar content would have to be manually translated every time. Additionally, translators would have to reach out with questions on whether a certain term needs to be translated or not, how it is used in the text, and whether a term already has an established translation. + +_Do you want to use the ethereum.org translation memory and glossary in your project? Reach out to us at translations@ethereum.org._ + +## Translator Outreach + +**Working with a language service provider** + +If you are working with a language service provider and their professional translators, this section might not be too relevant for you. + +In this case, it is important to select a language service provider with the capacity to provide all the services you need (e.g., translation, review, QA) in many languages. + +While it might be tempting to select a language service provider solely based on their offered rates, it is important to note that the largest language service providers have higher rates for a reason. + +- They have tens of thousands of linguists in their database, which means that they will be able to assign translators with sufficient experience and knowledge of your particular sector to your project (i.e., technical translators). +- They have significant experience working on different projects and meeting their clients’ diverse needs. This means they will be more likely to adapt to your particular workflow, offer valuable suggestions and potential improvements for your translation process, and meet your needs, requirements, and deadlines. +- Most of the largest language service providers also have their own localization tools, translation memories, and glossaries that you can use. If not, they at least have enough linguists in their pool to make sure that their translators will be familiar with and able to work with any localization tool you want to use. + +You can find an in-depth comparison of the largest language service providers in the world, some details about each of them and breakdowns by the services they provide, geographical data, etc. in the [2021 Nimdzi 100 report](https://www.nimdzi.com/nimdzi-100-top-lsp/). + +**Working with non-professional translators** + +You might be working with non-professional translators and looking for volunteers to help you translate. + +There are several ways to reach people and invite them to join your project. This will largely depend on your product and how big of a community you already have. + +Some ways of onboarding volunteers are outlined below: + +**Outreach –** While this is somewhat covered in the points below, reaching out to potential volunteers and making sure they are aware of your translation initiative can be effective in itself. + +A lot of people want to get involved and contribute to their favorite projects, but often don’t see a clear way of doing that without being a developer or having special technical skills. If you can spread awareness about your project, a lot of bilinguals will likely be keen to get involved. + +**Looking within your community –** Most projects in the space already have large and active communities. A lot of your community members would probably appreciate the chance to contribute to the project in a simple way. + +While contributing to open-source projects is often based on intrinsic motivation, it is also a fantastic learning experience. Anyone interested in learning more about your project would likely be happy to get involved with a translation program as a volunteer, since it would allow them to combine the fact that they have contributed to something they care about with an intensive hands-on learning experience. + +**Mentioning the initiative in your product –** If your product is popular and used by a large number of people, highlighting your translation program and calling users to action while using the product can be extremely effective. + +This could be as simple as adding a banner or pop-up with a CTA to your product for applications and websites. This is effective because your target audience is your community - the people who are most likely to get involved in the first place. + +**Social media –** Social media can be an effective way of spreading awareness about your translation program and reaching out to your community members, as well as other people who aren’t members of your community yet. + +If you have a Discord server or Telegram channel, it is easy to use that for outreach, communication with your translators, and acknowledging your contributors. + +Platforms like Twitter can also be helpful for onboarding new community members and publicly acknowledging your contributors. + +The Linux Foundation has created an extensive report on the [2020 FOSS open-source contributor survey](https://www.linuxfoundation.org/wp-content/uploads/2020FOSSContributorSurveyReport_121020.pdf), analyzing open-source contributors and their motivations. + +## Conclusion + +This document contains some key considerations every translation program should be aware of. It is by no means an exhaustive guide, though it can help anyone with no experience in the translation industry organize a translation program for their project. + +If you are looking for more detailed instructions and breakdowns of different tools, processes, and critical aspects of managing a translation program, some of the largest language service providers maintain blogs and often publish articles on different aspects of the localization process. These are the best resources if you want to dive deeper into any of the topics above and understand how the localization process works professionally. + +Some relevant links are included at the end of each section; however, you can find many other resources online. + +For proposals for cooperation or additional information, learnings, and best practices we’ve picked up by maintaining the ethereum.org Translation Program, feel free to reach out to us at translations@ethereum.org. + +--- + +## Contributing > Translation Program > Resources + +# Resources + +You can find some useful guides and tools for ethereum.org translators, as well as translation communities and updates below. + +## Guides + +- [Translation style guide](/contributing/translation-program/translators-guide/) _– instructions and tips for ethereum.org translators_ +- [Translation FAQs](/contributing/translation-program/faq/) _– frequently asked questions and answers about the ethereum.org Translation Program_ +- [Crowdin online editor guide](https://support.crowdin.com/online-editor/) _– an in-depth guide to using the Crowdin online editor and some of Crowdin's advanced features_ +- [Content buckets](/contributing/translation-program/content-buckets/) _– which pages are included in each content bucket of ethereum.org_ + +## Tools + +- [Microsoft Language Portal](https://www.microsoft.com/en-us/language) + _– useful for finding and checking the standard translations of technical terms_ +- [Linguee](https://www.linguee.com/) + _– search engine for translations and dictionary that enables searching by word or phrase_ +- [Proz term search](https://www.proz.com/search/) + _– database of translation dictionaries and glossaries for specialized terms_ +- [Eurotermbank](https://www.eurotermbank.com/) + _– collections of European terminology in 42 languages_ + +## Communities + +- [Language-specific Discord translation groups](/discord/) + _– an initiative to connect ethereum.org translators to Translation Groups_ +- [Chinese translators group](https://www.notion.so/Ethereum-org-05375fe0a94c4214acaf90f42ba40171) + _– Notion page for easier coordination between Chinese translators_ + +## Latest updates + +To keep up-to-date with the latest Translation Program progress, you can follow the [Ethereum Foundation blog](https://blog.ethereum.org/): + +- [October 2021 milestones update](https://blog.ethereum.org/2021/10/04/translation-program-update/) +- [December 2020 milestones update](https://blog.ethereum.org/2020/12/21/translation-program-milestones-updates-20/) +- [July 2020 milestones update](https://blog.ethereum.org/2020/07/29/ethdotorg-translation-milestone/) +- [August 2019 Translation Program launch](https://blog.ethereum.org/2019/08/20/translating-ethereum-for-our-global-community/) + +## Office hours for translators + +We have office hours for translators on the second Wednesday of every month. These are held in the #office-hours voice channel on the [ethereum.org Discord](/discord/), where you can also find the exact times and additional details. + +Office hours allow our translators to ask questions about the translation process, provide feedback on the program, share their ideas, or just chat with the core ethereum.org team. +Finally, we want to use these calls to communicate recent developments with the Translation Program and share key tips and instructions with our contributors. + +If you are an ethereum.org translator or would like to become one, feel free to join us during one of these sessions. + +--- + +## Contributing > Translation Program > Translatathon > Details + +![](./participate.png) + +The Translatathon is open and anyone can participate by filling out the application form and joining the project in Crowdin. + +Translators collect points by suggesting translations for untranslated strings in their language in the Crowdin editor during the translation period (August 9th - August 18th). + +Each participants final score is determined by the number of words they have translated during the translation period and any potential multipliers they’ve collected. + +### Getting started + +The translation process takes place in the ethereum.org project in Crowdin and translators suggest their translations for untranslated strings, made up of almost all of content from the ethereum.org website. + +Translations are suggested directly in the online editor so there is no need to download or upload any files or deliverables. Each translated word is tracked and counted. + +**1) Join the project** + +- To start contributing, you will need to join the [ethereum.org project in Crowdin](https://crowdin.com/project/ethereum-org) +- You will need to sign in or create an account - all that is required is an email address and password + +**2) Select your language** + +- Find your language on the list of target languages and open it by clicking on its name or flag +- If you would like to translate into a language that isn’t available, reach out to [Ethereum.org Team](https://crowdin.com/profile/ethdotorg) on crowdin or send us an email to translations@ethereum.org and we will add new additional target languages per request + +**3) Open an untranslated file** + +- Find the first untranslated file to start translating. The folders containing the source files are based on priority - 1) Homepage, 2) Essential learning, 3) Essentials, 4) Exploring, etc. so you should start translating the first folder that contains untranslated files +- Each file has a progress indicator showing how much of the translatable content in the file has been translated and approved… if translation progress for any file is below 100%, please translate it + +**4) Translate the untranslated strings** + +- When you open a file to translate, make sure you are only translating untranslated strings! +- Each string has a status indicator that shows whether it’s _Translated_, _Untranslated_, or _Approved_. If a source string already has a suggested translation in your language, there is no need to translate it +- You can also filter strings in the editor to show _Untranslated first_ or _Untranslated only_ + +For a detailed guide to navigating and using the Crowdin online editor, we recommend all Translatathon participants to read our [How to translate](/contributing/translation-program/how-to-translate/) guide. + +To learn more about the conventions and best practices for translating ethereum.org content, you can also check out our [translation style guide](/contributing/translation-program/translators-guide/). + +### Prizes + + + +**How points work** + +Every Translatathon participant will earn points towards their final score by translating content in the ethereum.org Crowdin project and other eligible projects (the full list of eligible projects is available in the next section). + +The scoring is simple: **1 translated word = 1 point** + +Please note that in order to receive your final points allocation, your suggested translations will need to pass the evaluation process, where professional reviewers will check each participant's translations to ensure they meet the minimum quality threshold and no machine or AI translations were used in the process. + +**Bonus points** + +This year, Translatathon participants also have several options to earn bonus points. + +Bonus points breakdown: +- ETHglossary contributors: 100-1,000 bonus points +- Ethereum.org contributors: 1,000 bonus points +- Previous Translatathon participants: 1,000 bonus points + +1) ETHglossary translators +[ETHglossary](https://ethglossaryproject.vercel.app/) is an open-source glossary of key Ethereum terms, and an initiative to create and maintain a glossary of Ethereum terms and their translations in 60+ languages that anyone can use and contribute to. +Translatathon participants can suggest translations for these terms and vote or discuss existing translations to earn bonus points in the Translatathon. +Each 10 translated terms will earn you 100 bonus points, with a bonus for completing all 70 terms currently available in the glossary app. The bonus points will be automatically added to your final score once the Translatathon ends and the final scores are calculated. + +Participants can earn a maximum of 1,000 bonus points by translating all of the terms in their native language, but translating multiple languages will not result in any additional points! + +ETHglossary points breakdown: +- 10 translated terms = 100 bonus points +- 20 translated terms = 200 bonus points +- 30 translated terms = 300 bonus points +- 40 translated terms = 400 bonus points +- 50 translated terms = 500 bonus points +- 60 translated terms = 600 bonus points +- 70 translated terms = 1,000 bonus points + +2) Ethereum.org contributors +To reward our existing contributors, each past ethereum.org contributor is eligible for 1,000 bonus points. +Contributors are individuals that have received any ethereum.org contributor POAP, OAT or GitPOAP in the past. +You can check out the full list of eligible contributor POAPs, OATs and GitPOAPs [here](https://efdn.notion.site/Ethereum-org-contributor-credentials-1c23938dfd7f44d0bda3992c58897d63) + +3) Previous Translatathon participants +Previous Translatathon participants will also receive 1,000 bonus points. +Anyone who participated in the 2023 edition of the ethereum.org Translatathon and scored at least 100 points, will automatically receive their bonus points once the Translatathon ends and the final scores are calculated. + +**In order to claim their bonus points, participants must score at least 100 points in the 2024 Translatathon!** + +### Ecosystem content + +Since the ethereum.org Translation program is active throughout the year, the translation progress in some target languages on the website is significantly higher than others. + +In order to ensure that all Translatathon participants have an equal opportunity to translate as much content as they can and compete for the top prizes, the source content that is part of the Translatathon is not only limited to ethereum.org website content. + +Participants translating any of the eligible projects will earn an equal amounts of points, 1 translated word in any project = 1 point. + +Here is a list of all the eligible projects that are part of the 2024 Translatathon: + +Ethereum.org +- https://crowdin.com/project/ethereum-org + +Ethereum.org developer tutorials +- https://crowdin.com/project/33388446abbe9d7aa21e42e49bba7f97 + +Remix +- https://crowdin.com/project/remix-translation +- https://crowdin.com/project/remix-ui +- https://crowdin.com/project/remix-learneth +- https://crowdin.com/project/361d7e8c3b07220fa22e9d5a901b0021 + +Privacy + Scaling explorations +- https://crowdin.com/project/privacy-scaling-explorations + +Speed Run Ethereum +- https://crowdin.com/project/speed-run-ethereum + +EthStaker +- https://crowdin.com/project/ethstaker-website +- https://crowdin.com/project/ethstaker-knowledge-base + +Solidity Language Docs +- https://crowdin.com/project/solidity-language-docs + +### Evaluation process + +All translations will be subject to QA and feedback, where professional linguists will evaluate submissions based on quality and accuracy. + +We will also be running **anti-machine translation measures**, with Crowdin providing some tools that automatically detect machine translations. + +While translation quality will not play a critical role in the scoring, any **participants found using machine translation** or suggesting low-quality and inaccurate translations **will be disqualified** and not eligible to compete for prizes! + +The evaluation period will take place between August 19th-28th and the results will be announced on the ethereum.org community call on August 29th. + +All translations will also be subject to a thorough review before being added to the website. + +### FAQ - Frequently asked questions + + + + In Crowdin, you can send a direct message to Ethereum.org Team + On the ethereum.org Discord, you can send a message in the #translatathon & #translate channels + You can send an email to translations@ethereum.org + + + + + No. This year, the Translatathon will only have one main individual track and there will be no team competition. + You can still team up with your friends and translate together, however everyone will be competing in the Translatathon as an individual and only the number of your individual translated words will count towards your final score. + + + + You can translate into any language! It is recommended to only translate into your native language to ensure sufficient quality, but in short, all languages available in Crowdin are in scope for the Translatathon. + If you want to translate into a language that isn't available in Crowdin, reach out to us and we will add any language per request. + +--- + +## Contributing > Translation Program > Translatathon + +## Introduction + +The ethereum.org Translation Program is an ongoing effort to translate the website into as many languages as possible. We believe that Ethereum content and onboarding resources should be accessible to everyone, regardless of the language they speak. + +As part of the Translation Program, we are organizing the second edition of the Translatathon with the aim of incentivizing translation contributions in less-active languages, increasing the number of languages and amount of content available on the site, onboard new contributors and reward our existing ones. + +If you are bilingual and want to help make Ethereum content more accessible while competing for prizes, read on to learn more! + +[Learn more about the ethereum.org Translation Program](/contributing/translation-program/) + +## Timeline + +Here are the important dates for the 2024 Translatathon: + + + + + +## Participate + +![Image of community and globe](./participate.png) + + + + Who can join? + Be older than 18 years and fluent in at least one language in addition to English. + + + Do I need to be a translator? + No. You simply have to be bilingual and suggest human translations (using machine translation is forbidden!) to the best of your ability, no professional experience required. + + + + + + How much time do I have to commit? + As much as you want. The minimum threshold to be eligible for participatory prizes is 100 translated words, which takes about 10-20 minutes to complete, while competing for the top prizes will require a larger time commitment. + + + Do I need to be familiar with Ethereum? + No. While being familiar with Ethereum can help with your productivity and quality, the Translatathon is as much a learning experience as it is a competition, and everyone is invited to join and learn more about Ethereum while participating. + + + + + + What do I need to participate? + We recommend using a computer to translate since our translation platform, Crowdin, is optimized for desktop. + + + +For more details, [see the full Terms & conditions](/contributing/translation-program/translatathon/terms-and-conditions) + +### Step by step instructions + + + +## Prizes + + + +## Stay up to date + + + Translatathon hubs + + This year we bring IRL community hubs to join local communities and help translate. These hubs are located all over the world, find out if there is one close to you and join the community! + +--- + +## Contributing > Translation Program > Translatathon > Terms And Conditions + +The Ethereum.org Translation Competition, also referred to as the “Translatathon”, is an experimental initiative by the ethereum.org team to incentivise and reward contributions to the ethereum.org Translation Program. + +## Modification and Termination. + +We reserve the right to modify the rules or to terminate the Translatathon at any time, without prior notice. All changes will be effective immediately upon announcement. + +## Eligibility, Judging, and Prizes + +The determination of eligibility, scoring and judging methodology, and prize distribution fall solely and irrevocably under our discretion. + +## Data Privacy + +By submitting the application form, applicants and participants confirm that they have read and agree to our Privacy Policy and consent to share with us the requested information, which may include information that constitutes personal data. We will keep all information provided confidential, except for the participants’ provided Crowdin usernames and profile images which may be used in public announcements related to competition results and winners. + +## Translation Standards + +The use of machine translation tools, as determined by us in our sole discretion, may result in disqualification from the competition. In addition, the submission of incorrect and/or inaccurate translations, as determined by us in our sole discretion, may result in ineligibility for prize consideration. Further, any contributions towards strings that have already been translated or reviewed, as determined by us in our sole discretion, will not be included in the participants’ final score. We reserve the right to make such determinations, which shall be final and binding. + +## Intellectual Property + +Participants agree that by submitting a translation work during the Translatathon, they grant the Ethereum Foundation an irrevocable, non-exclusive, royalty-free licence to use, reproduce, distribute, display, modify, adapt, create derivative works from, and otherwise alter their translation work. Further, participants agree that their translation works may be made publicly available on the ethereum.org website under an open-source licence, including a Creative Commons licence, which allows others to use, share, and build upon the work. + +## Taxes + +Any tax implications arising from the receipt of prizes are the sole responsibility of the prize recipient. + +## Comprehensively Sanctioned Countries + +Participants from regions or countries that are subject to comprehensive international sanctions (including, but not limited to Iran, Cuba, Syria, North Korea, and the Crimea, Donetsk People's Republic and Luhansk People's Republic regions of Ukraine) will not be eligible for participation. + +## Waiver of Liability + +Participants agree that the Ethereum Foundation, its affiliates, and all of their respective officers, directors, employees, and agents will have no liability whatsoever for any injuries, losses, or damages of any kind arising from or in connection with their participation in the Translatathon. + +## Governing Law + +Any dispute or claim arising out of or relating to the Translatathon (in each case, including non-contractual disputes or claims), shall be governed by and construed in accordance with the laws of Switzerland without giving effect to any choice or conflict of law provision or rule (whether of Switzerland or any other jurisdiction). + +--- + +## Contributing > Translation Program > Translatathon > Translatathon Hubs + +![](./local-communities.png) + +## Overview + +The Translatathon brings together people from different expertise and cultures to collaborate on one goal: making Ethereum knowledge accessible in as many languages as possible. This year, with the support of local communities, we are bringing Translatathon Hubs to several cities worldwide, where people can get together, meet fellow Ethereum enthusiasts, and participate in the Translatathon. + + + + Why do we do it + Translating is often a lonely task, but it doesn't have to be. By gathering participants in one place, they can enjoy the solitude of crafting the perfect translation while still taking breaks to socialize, have a coffee, and share the most challenging or funny terms they've encountered while translating. + + + How does it work + Check the list of Translatathon Hubs to see if there's one happening in your city! Remember, the Translatathon is an online competition, so you can always participate from the comfort of your couch. + + + +## List of Translatathon Hubs + +--- + +## Contributing > Translation Program > Translators Guide + +# Ethereum.org Translation Style Guide + +The ethereum.org translation style guide contains some of the most important guidelines, instructions, and tips for translators, helping us localize the website. + +This document serves as a general guide and is not specific to any one language. + +If you have any questions, suggestions or feedback, feel free to reach out to us at translations@ethereum.org, send a message to @ethdotorg on Crowdin, or [join our Discord](https://discord.gg/ethereum-org), where you can message us in the #translations channel or reach out to any of the team members. + +## Using Crowdin + +You can find basic instructions on how to join the project in Crowdin and how to use the Crowdin online editor on the [Translation Program page](/contributing/translation-program/#how-to-translate). + +If you would like to learn more about Crowdin and using some of its advanced feature, the [Crowdin knowledge base](https://support.crowdin.com/online-editor/) contains a lot of in-depth guides and overviews of all Crowdin functionality. + +## Capturing the essence of the message + +When translating ethereum.org content, avoid literal translations. + +It is important that the translations capture the essence of the message. This could mean rephrasing certain phrases, or using descriptive translations instead of translating the content word for word. + +Different languages have different grammar rules, conventions and word order. When translating, please be mindful of how sentences are structured in the target languages, and avoid literally translating the English source, as this can lead to poor sentence structure and readability. + +Instead of translating the source text word for word, it is recommended you read the entire sentence and adapt it to fit the conventions of the target language. + +## Formal vs. informal + +We use the formal form of address, which is always polite and appropriate for all visitors. + +Using the formal address allows us to avoid sounding unofficial or offensive, and works regardless of the visitor’s age and gender. + +Most Indo-European and Afro-Asiatic languages use gender-specific second-person personal pronouns, which distinguish between male and female. When addressing the user or using possessive pronouns, we can avoid assuming the visitor’s gender, as the formal form of address is generally applicable and consistent, regardless of how they identify. + +## Simple and clear vocabulary and meaning + +Our goal is to make content on the website understandable to as many people as possible. + +In most cases, this can be easily achieved by using short and simple words that are easily understandable. If there are multiple possible translations for a certain word in your language with the same meaning, the best option is most often the shortest word that clearly reflects the meaning. + +## Writing system + +Ethereum.org is available in a number of languages, using alternative writing systems (or writing scripts) to Latin. + +All of the content should be translated using the correct writing system for your language, and should not include any words, written using Latin characters. + +When translating the content, you should ensure that the translations are consistent and do not include any Latin characters. + +A common misconception is that Ethereum should always be written in Latin. This is mostly incorrect, please use the spelling of Ethereum, native to your language (e.g. 以太坊 in Chinese, إيثيريوم in Arabic, etc.). + +**The above doesn’t apply to languages, where proper names shouldn’t be translated as a rule.** + +## Translating page metadata + +Some pages contain metadata on the page, like 'title', 'lang', 'description', 'sidebar', etc. + +We hide the content that translators should never translate when uploading new pages to Crowdin, meaning that all the metadata visible to translators in Crowdin should get translated. + +Please be especially mindful when translating any strings where the source text is 'en'. This represents the language that the page is available in and should be translated to the [ISO language code for your language](https://www.andiamo.co.uk/resources/iso-language-codes/). These strings should always be translated using Latin characters, not the writing script, native to the target language. + +If you are unsure which language code to use, you can check the translation memory in Crowdin or find the language code for your language in the URL of the page in the Crowdin online editor. + +Some examples of language codes for the most widely spoken languages: + +- Arabic - ar +- Chinese Simplified - zh +- French - fr +- Hindi - hi +- Spanish - es + +## Titles of external articles + +Some strings contain titles of external articles. Most of our developer documentation pages contain links to external articles for further reading. The strings containing titles of articles need to be translated, regardless of the article's language, to ensure a more consistent user experience for the visitors viewing the page in their language. + +You can find some examples of what these strings look like for translators and how to identify them below (links to articles can be found mostly at the bottom of these pages, in the 'Further reading' section): + +![Article titles in sidebar.png](./article-titles-in-sidebar.png) +![Article titles in editor.png](./article-titles-in-editor.png) + +## Crowdin warnings + +Crowdin has a built-in feature that warns translators when they are about to make a mistake. Crowdin will automatically warn you of this before saving your translation if you forget to include a tag from the source, translate elements that should not be translated, add several consecutive spaces, forget end punctuation, etc. +If you see a warning like this, please go back and double-check the suggested translation. + +**Never ignore these warnings, as they usually mean that something is wrong, or that the translation is missing a key part of the source text.** + +An example of a Crowdin warning when you forget to add a tag to your translation: +![Example of a Crowdin warning](./crowdin-warning-example.png) + +## Dealing with tags and code snippets + +A lot of the source content contains tags and variables, which are highlighted in yellow in the Crowdin editor. These serve different functions and should be approached correctly. + +**Crowdin settings** + +To make it easier to manage tags and copy them directly from the source, we recommend changing your settings in the Crowdin editor. + +1. Open settings + ![How to open settings in the editor](./editor-settings.png) + +2. Scroll down to the 'HTML tags displaying' section + +3. Select 'Hide' + ![Please select 'Hide'](./hide-tags.png) + +4. Click 'Save' + +By selecting this option, the full tag text will no longer be shown, and will be replaced by a number. +When translating, clicking on this tag will automatically copy the exact tag to the translation field. + +**Links** + +You may notice full links to pages on ethereum.org or other websites. + +These should be identical to the source and not changed or translated. If you translate a link or change it in any way, even just removing a part of it, like a slash (/), this will lead to broken and unusable links. + +The best way to handle links is to copy them directly from the source, either by clicking on them or using the ‘Copy Source’ button (Alt+C). + +![Example of link.png](./example-of-link.png) + +Links also appear in the source text in the form of tags (i.e. `` ``). If you hover over the tag, the editor will show its full content - sometimes these tags will represent links. + +It is very important to copy the links from the source and not change their order. + +If the order of the tags is changed, the link they represent will be broken. + +![Example of links inside tags.png](./example-of-links-inside-tags.png) + +**Tags and variables** + +The source text contains many different types of tags, which should always be copied from the source and never changed. Similarly to above, the order of these tags in the translation should also remain the same as the source. + +Tags always contain an opening and closing tag. In most cases, the text between opening and closing tags should be translated. + +Example: ``Decentralized`` + +`` - _Opening tag that makes the text bold_ + +Decentralized - _Translatable text_ + +`` - _Closing tag_ + +![Example of 'strong' tags.png](./example-of-strong-tags.png) + +Code snippets should be approached slightly differently to the other tags, since they contain code that should not be translated. + +Example: ``nonce`` + +`` - _Opening tag, which contains a code snippet_ + +nonce - _Non-translatable text_ + +`` - _Closing tag_ + +![Example of code snippets.png](./example-of-code-snippets.png) + +The source text also contains shortened tags, which only contain numbers, meaning that their function is not immediately obvious. You can hover over these tags to see exactly which function they serve. + +In the example below, you can see that hovering over the `` tag shows that it represents `` and contains a code snippet, therefore the content inside these tags should not be translated. + +![Example of ambiguous tags.png](./example-of-ambiguous-tags.png) + +## Short vs. full forms/abbreviations + +There are a lot of abbreviations used on the website, e.g. dapps, NFT, DAO, DeFi, etc. These abbreviations are commonly used in English and most visitors to the website are familiar with them. + +Since they usually don’t have established translations in other languages, the best way to approach these and similar terms is to provide a descriptive translation of the full form, and add the English abbreviation in brackets. + +Do not translate these abbreviations, since most people wouldn’t be familiar with them, and the localized versions would not make much sense to most visitors. + +Example of how to translate dapps: + +- Decentralized applications (dapps) → _Translated full form (English abbreviation in brackets)_ + +## Terms without established translations + +Some terms might not have established translations in other languages, and are widely known by the original English term. Such terms mostly include newer concepts, like proof-of-work, proof-of-stake, Beacon Chain, staking, etc. + +While translating these terms can sound unnatural, since the English version is commonly used in other languages as well, it is highly recommended that they are translated. + +When translating them, feel free to get creative, use descriptive translations, or simply translate them literally. + +**The reason why most terms should be translated, instead of leaving some in English, is the fact that this new terminology will become more widespread in the future, as more people start using Ethereum and related technologies. If we want to onboard more people from all over the world to this space, we need to provide understandable terminology in as many languages as possible, even if we need to create it ourselves.** + +## Buttons & CTAs + +The website contains numerous buttons, which should be translated differently than other content. + +Button text can be identified by viewing the context screenshots, connected with most strings, or by checking the context in the editor, which includes the phrase ‘’button’’. + +The translations for buttons should be as short as possible, to prevent formatting mismatches. Additionally, button translations should be imperative, i.e. present a command or request. + +![How to find a button.png](./how-to-find-a-button.png) + +## Translating for inclusivity + +Ethereum.org visitors come from all over the world and from different backgrounds. The language on the website should therefore be neutral, welcoming to everyone and not exclusive. + +An important aspect of this is gender neutrality. This can be easily achieved by using the formal form of address, and avoiding any gender-specific words in the translations. + +Another form of inclusivity is trying to translate for a global audience, not specific to any country, race or region. + +Finally, the language should be suitable for all audiences and ages. + +## Language-specific translations + +When translating, it is important to follow the grammar rules, conventions and formatting, used in your language, as opposed to copying from the source. The source text follows English grammar rules and conventions, which is not applicable to many other languages. + +You should be aware of the rules for your language and translate accordingly. If you need help, reach out to us and we will help you find some resources on how these elements should be used in your language. + +Some examples of what to be particularly mindful of: + +### Punctuation, formatting + +**Capitalization** + +- There are vast differences in capitalization in different languages. +- In English, it is common to capitalize all words in titles and names, months and days, language names, holidays, etc. In many other languages, this is grammatically incorrect, as they have different capitalization rules. +- Some languages also have rules about capitalizing personal pronouns, nouns, and certain adjectives, which are not capitalized in English. + +**Spacing** + +- Orthography rules define the use of spaces for each language. Because spaces are used everywhere, these rules are some of the most distinct, and spaces are some of the most mistranslated elements. +- Some common differences in spacing between English and other languages: + - Space before units of measure and currencies (e.g. USD, EUR, kB, MB) + - Space before degree signs (e.g. °C, ℉) + - Space before some punctuation marks, especially the ellipsis (…) + - Space before and after slashes (/) + +**Lists** + +- Every language has a diverse and complex set of rules for writing lists. These can be significantly different to English. +- In some languages, the first word of each new line needs to be capitalized, while in others, new lines should start with lower-case letters. Many languages also have different rules about capitalization in lists, depending on the length of each line. +- The same applies to punctuation of line items. The end punctuation in lists can be a period (**.**), comma (**,**), or semicolon (**;**), depending on the language. + +**Quotation marks** + +- Languages use many different quotation marks. Simply copying the English quotation marks from the source is often incorrect. +- Some of the most common types of quotation marks include: + - „example text“ + - ‚example text’ + - »example text« + - “example text” + - ‘example text’ + - «example text» + +**Hyphens and dashes** + +- In English, a hyphen (-) is used to join words or different parts of a word, while a dash (–) is used to indicate a range or a pause. +- Many languages have different rules for using hyphens and dashes that should be observed. + +### Formats + +**Numbers** + +- The main difference in writing numbers in different languages is the separator used for decimals and thousands. For thousands, this can be a period, comma or space. Similarly, some languages use a decimal point, while others use a decimal comma. + - Some examples of large numbers: + - English – **1,000.50** + - Spanish – **1.000,50** + - French – **1 000,50** +- Another important consideration when translating numbers is the percent sign. It can be written in different ways: **100%**, **100 %** or **%100**. +- Finally, negative numbers can be displayed differently, depending on the language: -100, 100-, (100) or [100]. + +**Dates** + +- When translating dates, there are a number of considerations and differences based on the language. These include the date format, separator, capitalization and leading zeros. There are also differences between full-length and numerical dates. + - Some examples of different date formats: + - English UK (dd/mm/yyyy) – 1st January, 2022 + - English US (mm/dd/yyyy) – January 1st, 2022 + - Chinese (yyyy-mm-dd) – 2022 年 1 月 1 日 + - French (dd/mm/yyyy) – 1er janvier 2022 + - Italian (dd/mm/yyyy) – 1º gennaio 2022 + - German (dd/mm/yyyy) – 1. Januar 2022 + +**Currencies** + +- Translating currencies can be challenging, due to the different formats, conventions and conversions. As a general rule, please keep currencies the same as the source. You can add your local currency and conversion in brackets, for the benefit of the reader. +- The main differences in writing currencies in different languages include symbol placement, decimal commas vs. decimal points, spacing, and abbreviations vs. symbols. + - Symbol placement: $100 or 100$ + - Decimal commas vs. decimal points: 100,50$ or 100.50$ + - Spacing: 100$ or 100 $ + - Abbreviations vs. symbols: 100 $ or 100 USD + +**Units of measure** + +- As a general rule, please keep the units of measure as per the source. If your country uses a different system, you can include the conversion in brackets. +- Aside from the localization of units of measure, it is also important to note the differences in how languages approach these units. The main difference is the spacing between the number and unit, which can be different, based on the language. Examples of this include 100kB vs. 100 kB or 50ºF vs. 50 ºF. + +## Conclusion + +Translating ethereum.org is a great opportunity to learn about the different aspects of Ethereum. + +When translating, try not to rush. Take it easy and have fun! + +Thank you for being involved with the Translation Program and helping us make the website accessible to a wider audience. The Ethereum community is global, and we are happy you are a part of it! + +--- + +# Cookie Policy + +## Cookie Policy + +# Cookie Policy + +Our Websites may use cookies to distinguish you from other users of our Websites. This may help us to provide you with a good experience when you browse our Websites and may also allow us to improve our Websites. By continuing to browse the Websites, you are agreeing to our use of cookies as well as the terms of this policy (the “Cookie Policy”). A cookie is a small file of letters and numbers that we may store on your browser or the hard drive of your computer if you agree. Cookies contain information that is transferred to your computer's hard drive. We may use the following cookies: + +- **Strictly necessary cookies.** These are cookies that are required for the operation of our websites. They include, for example, cookies that enable you to log into secure areas of our websites, use a shopping cart or make use of e-commerce payment processing services. +- **Analytical/performance cookies.** They allow us to recognise and count the number of visitors and to see how visitors move around our websites when they are using them. This may help us to improve the way our websites work, for example, by ensuring that users are finding what they are looking for easily. +- **Functionality cookies.** These cookies are used to recognise you when you return to our websites. They may enable us to personalise our content for you, greet you by name, or remember your preferences (for example, your choice of language or region). +- **Targeting cookies.** These cookies record your visit to our websites, the pages you have visited and the links you have followed. + + + +You can find more information about the individual cookies we may use and the purposes for which we may use them in the table below: + +| Cookie | Name | Purpose | +| ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Matomo | \_pk_id | Used to distinguish users. Enables us to identify which pages are popular, estimate our audience size and usage pattern, and better understand how the website is used. | +| Matomo | \_pk_ses | Used to store temporary session data. This a short-lived cookie, only lasting for a few minutes. | + +You can block cookies by activating the setting on your browser that allows you to refuse the setting of all or some cookies. However, if you use your browser settings to block all cookies (including essential cookies), you may not be able to access all or parts of our sites. + +Except for essential cookies, all cookies will expire after two years. + +--- + +# Dao + +## Dao + +## What are DAOs? + +A DAO is a collectively-owned organization working towards a shared mission. + +DAOs allow us to work with like-minded folks around the globe without trusting a benevolent leader to manage the funds or operations. There is no CEO who can spend funds on a whim or CFO who can manipulate the books. Instead, blockchain-based rules baked into the code define how the organization works and how funds are spent. + +They have built-in treasuries that no one has the authority to access without the approval of the group. Decisions are governed by proposals and voting to ensure everyone in the organization has a voice, and everything happens transparently [onchain](/glossary/#onchain). + +## Why do we need DAOs? + +Starting an organization with someone that involves funding and money requires a lot of trust in the people you're working with. But it’s hard to trust someone you’ve only ever interacted with on the internet. With DAOs you don’t need to trust anyone else in the group, just the DAO’s code, which is 100% transparent and verifiable by anyone. + +This opens up so many new opportunities for global collaboration and coordination. + +### A comparison + +| DAO | A traditional organization | +| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| Usually flat, and fully democratized. | Usually hierarchical. | +| Voting required by members for any changes to be implemented. | Depending on structure, changes can be demanded from a sole party, or voting may be offered. | +| Votes tallied, and outcome implemented automatically without trusted intermediary. | If voting allowed, votes are tallied internally, and outcome of voting must be handled manually. | +| Services offered are handled automatically in a decentralized manner (for example distribution of philanthropic funds). | Requires human handling, or centrally controlled automation, prone to manipulation. | +| All activity is transparent and fully public. | Activity is typically private, and limited to the public. | + +### DAO examples + +To help this make more sense, here's a few examples of how you could use a DAO: + +- **A charity** – you could accept donations from anyone in the world and vote on which causes to fund. +- **Collective ownership** – you could purchase physical or digital assets and members can vote on how to use them. +- **Ventures and grants** – you could create a venture fund that pools investment capital and votes on ventures to back. Repaid money could later be redistributed amongst DAO-members. + + + +## How do DAOs work? + +The backbone of a DAO is its [smart contract](/glossary/#smart-contract), which defines the rules of the organization and holds the group's treasury. Once the contract is live on Ethereum, no one can change the rules except by a vote. If anyone tries to do something that's not covered by the rules and logic in the code, it will fail. And because the treasury is defined by the smart contract too that means no one can spend the money without the group's approval either. This means that DAOs don't need a central authority. Instead, the group makes decisions collectively, and payments are automatically authorized when votes pass. + +This is possible because smart contracts are tamper-proof once they go live on Ethereum. You can't just edit the code (the DAOs rules) without people noticing because everything is public. + +## Ethereum and DAOs + +Ethereum is the perfect foundation for DAOs for a number of reasons: + +- Ethereum’s own consensus is decentralized and established enough for organizations to trust the network. +- Smart contract code can’t be modified once live, even by its owners. This allows the DAO to run by the rules it was programmed with. +- Smart contracts can send/receive funds. Without this you'd need a trusted intermediary to manage group funds. +- The Ethereum community has proven to be more collaborative than competitive, allowing for best practices and support systems to emerge quickly. + +## DAO governance + +There are many considerations when governing a DAO, such as how voting and proposals work. + +### Delegation + +Delegation is like the DAO version of representative democracy. Token holders delegate votes to users who nominate themselves and commit to stewarding the protocol and staying informed. + +#### A famous example + +[ENS](https://claim.ens.domains/delegate-ranking) – ENS holders can delegate their votes to engaged community members to represent them. + +### Automatic transaction governance + +In many DAOs, transactions will be automatically executed if a quorum of members votes affirmative. + +#### A famous example + +[Nouns](https://nouns.wtf) – In Nouns DAO, a transaction is automatically executed if a quorum of votes is met and a majority votes affirmative, as long as it is not vetoed by the founders. + +### Multisig governance + +While DAOs may have thousands of voting members, funds can live in a [wallet](/glossary/#wallet) shared by 5-20 active community members who are trusted and usually doxxed (public identities known to the community). After a vote, the [multisig](/glossary/#multisig) signers execute the will of the community. + +## DAO laws + +In 1977, Wyoming invented the LLC, which protects entrepreneurs and limits their liability. More recently, they pioneered the DAO law that establishes legal status for DAOs. Currently Wyoming, Vermont, and the Virgin Islands have DAO laws in some form. + +### A famous example + +[CityDAO](https://citizen.citydao.io/) – CityDAO used Wyoming's DAO law to buy 40 acres of land near Yellowstone National Park. + +## DAO membership + +There are different models for DAO membership. Membership can determine how voting works and other key parts of the DAO. + +### Token-based membership + +Usually fully [permissionless](/glossary/#permissionless), depending on the token used. Mostly these governance tokens can be traded permissionlessly on a [decentralized exchange](/glossary/#dex). Others must be earned through providing liquidity or some other ‘proof-of-work’. Either way, simply holding the token grants access to voting. + +_Typically used to govern broad decentralized protocols and/or tokens themselves._ + +#### A famous example + +[MakerDAO](https://makerdao.com) – MakerDAO's token MKR is widely available on decentralized exchanges and anyone can buy into having voting power on Maker protocol's future. + +### Share-based membership + +Share-based DAOs are more permissioned, but still quite open. Any prospective members can submit a proposal to join the DAO, usually offering a tribute of some value in the form of tokens or work. Shares represent direct voting power and ownership. Members can exit at any time with their proportionate share of the treasury. + +_Typically used for more closer-knit, human-centric organizations like charities, worker collectives, and investment clubs. Can also govern protocols and tokens as well._ + +#### A famous example + +[MolochDAO](http://molochdao.com/) – MolochDAO is focused on funding Ethereum projects. They require a proposal for membership so the group can assess whether you have the necessary expertise and capital to make informed judgments about potential grantees. You can't just buy access to the DAO on the open market. + +### Reputation-based membership + +Reputation represents proof of participation and grants voting power in the DAO. Unlike token or share-based membership, reputation-based DAOs don't transfer ownership to contributors. Reputation cannot be bought, transferred or delegated; DAO members must earn reputation through participation. Onchain voting is permissionless and prospective members can freely submit proposals to join the DAO and request to receive reputation and tokens as a reward in exchange for their contributions. + +_Typically used for decentralized development and governance of protocols and [dapps](/glossary/#dapp), but also well suited to a diverse set of organizations like charities, worker collectives, investment clubs, etc._ + +#### A famous example + +[DXdao](https://DXdao.eth.limo) – DXdao was a global sovereign collective building and governing decentralized protocols and applications since 2019. It leveraged reputation-based governance and [holographic consensus](/glossary/#holographic-consensus) to coordinate and manage funds, meaning no one could buy their way into influencing its future or governance. + +## Join / start a DAO + +### Join a DAO + +- [Ethereum community DAOs](/community/get-involved/#decentralized-autonomous-organizations-daos) +- [DAOHaus's list of DAOs](https://app.daohaus.club/explore) +- [Tally.xyz list of DAOs](https://www.tally.xyz) + +### Start a DAO + +- [Summon a DAO with DAOHaus](https://app.daohaus.club/summon) +- [Start a Governor DAO with Tally](https://www.tally.xyz/add-a-dao) +- [Create an Aragon-powered DAO](https://aragon.org/product) +- [Start a colony](https://colony.io/) +- [Create a DAO with DAOstack's holographic consensus](https://alchemy.daostack.io/daos/create) + +## Further reading + +### DAO Articles + +- [What's a DAO?](https://aragon.org/dao) – [Aragon](https://aragon.org/) +- [House of DAOs](https://wiki.metagame.wtf/docs/great-houses/house-of-daos) – [Metagame](https://wiki.metagame.wtf/) +- [What is a DAO and what is it for?](https://daohaus.substack.com/p/-what-is-a-dao-and-what-is-it-for) – [DAOhaus](https://daohaus.club/) +- [How to Start a DAO-Powered Digital Community](https://daohaus.substack.com/p/four-and-a-half-steps-to-start-a) – [DAOhaus](https://daohaus.club/) +- [What is a DAO?](https://coinmarketcap.com/alexandria/article/what-is-a-dao) – [Coinmarketcap](https://coinmarketcap.com) +- [What is Holographic Consensus?](https://medium.com/daostack/holographic-consensus-part-1-116a73ba1e1c) - [DAOstack](https://daostack.io/) +- [DAOs are not corporations: where decentralization in autonomous organizations matters by Vitalik](https://vitalik.eth.limo/general/2022/09/20/daos.html) +- [DAOs, DACs, DAs and More: An Incomplete Terminology Guide](https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide) - [Ethereum Blog](https://blog.ethereum.org) + +### Videos + +- [What is a DAO in crypto?](https://youtu.be/KHm0uUPqmVE) +- [Can a DAO Build a City?](https://www.ted.com/talks/scott_fitsimones_could_a_dao_build_the_next_great_city) – [TED](https://www.ted.com/) + +--- + +# Decentralized Identity + +## Decentralized Identity + +Identity underpins virtually every aspect of your life today. Using online services, opening a bank account, voting in elections, buying property, securing employment—all of these things require proving your identity. + +However, traditional identity management systems have long relied on centralized intermediaries who issue, hold, and control your identifiers and [attestations](/glossary/#attestation). This means you cannot control your identity-related information or decide who has access to personally identifiable information (PII) and how much access these parties have. + +To solve these problems, we have decentralized identity systems built on public blockchains like Ethereum. Decentralized identity allows individuals to manage their identity-related information. With decentralized identity solutions, _you_ can create identifiers and claim and hold your attestations without relying on central authorities, like service providers or governments. + +## What is identity? + +Identity means an individual's sense of self, defined by unique characteristics. Identity refers to being an _individual_, i.e., a distinct human entity. Identity could also refer to other non-human entities, such as an organization or authority. + + + +## What are identifiers? + +An identifier is a piece of information that acts as a pointer to a particular identity or identities. Common identifiers include: + +- Name +- Social security number/tax ID number +- Mobile number +- Date and place of birth +- Digital identification credentials, e.g., email addresses, usernames, avatars + +These traditional examples of identifiers are issued, held and controlled by central entities. You need permission from your government to change your name or from a social media platform to change your handle. + +## Benefits of decentralized identity + +1. Decentralized identity increases individual control of identifying information. Decentralized identifiers and attestations can be verified without relying on centralized authorities and third-party services. + +2. Decentralized identity solutions facilitate a trustless, seamless, and privacy-protecting method for verifying and managing user identity. + +3. Decentralized identity harnesses blockchain technology, which creates trust between different parties and provides cryptographic guarantees to prove the validity of attestations. + +4. Decentralized identity makes identity data portable. Users store attestations and identifiers in a mobile wallet and can share with any party of their choice. Decentralized identifiers and attestations are not locked into the database of the issuing organization. + +5. Decentralized identity should work well with emerging [zero-knowledge](/glossary/#zk-proof) technologies that will enable individuals to prove they own or have done something without revealing what that thing is. This could become a powerful way to combine trust and privacy for applications such as voting. + +6. Decentralized identity enables [anti-Sybil](/glossary/#anti-sybil) mechanisms to identify when one individual human is pretending to be multiple humans to game or spam some system. + +## Decentralized identity use-cases + +Decentralized identity has many potential use-cases: + +### 1. Universal logins + +Decentralized identity can help replace password-based logins with decentralized authentication. Service providers can issue attestations to users, which can be stored in an Ethereum wallet. An example attestation would be an [NFT](/glossary/#nft) granting the holder access to an online community. + +A [Sign-In with Ethereum](https://login.xyz/) function would then enable servers to confirm the user's Ethereum account and fetch the required attestation from their account address. This means users can access platforms and websites without having to memorize long passwords and improves the online experience for users. + +### 2. KYC authentication + +Using many online services requires individuals to provide attestations and credentials, such as a driving license or national passport. But this approach is problematic because private user information can be compromised and service providers cannot verify the authenticity of the attestation. + +Decentralized identity allows companies to skip on conventional [Know-Your-Customer (KYC)](https://en.wikipedia.org/wiki/Know_your_customer) processes and authenticate user identities via Verifiable Credentials. This reduces the cost of identity management and prevents the use of fake documentation. + +### 3. Voting and online communities + +Online voting and social media are two novel applications for decentralized identity. Online voting schemes are susceptible to manipulation, especially if malicious actors create false identities to vote. Asking individuals to present onchain attestations can improve the integrity of online voting processes. + +Decentralized identity can help create online communities that are free of fake accounts. For example, each user might have to authenticate their identity using an onchain identity system, like the Ethereum Name Service, reducing the possibility of bots. + +### 4. Anti-Sybil protection + +Grant-giving applications that use [quadratic voting](/glossary/#quadratic-voting) are vulnerable to [Sybil attacks](/glossary/#sybil-attack) because the value of a grant is increased when more individuals vote for it, incentivizing users to split their contributions across many identities. Decentralized identities help to prevent this by raising the burden on each participant to prove that they are really human, although often without having to reveal specific private information. + +## What are attestations? + +An attestation is a claim made by one entity about another entity. If you live in the United States, the driver's license issued to you by the Department of Motor Vehicles (one entity) attests that you (another entity) are legally allowed to drive a car. + +Attestations are different from identifiers. An attestation _contains_ identifiers to reference a particular identity, and makes a claim about an attribute related to this identity. So, your driver's license has identifiers (name, date of birth, address) but is also the attestation about your legal right to drive. + +### What are decentralized identifiers? + +Traditional identifiers like your legal name or email address rely on third parties—governments and email providers. Decentralized identifiers (DIDs) are different—they aren't issued, managed, or controlled by any central entity. + +Decentralized identifiers are issued, held, and controlled by individuals. An [Ethereum account](/glossary/#account) is an example of a decentralized identifier. You can create as many accounts as you want without permission from anyone and without the need to store them in a central registry. + +Decentralized identifiers are stored on distributed ledgers ([blockchains](/glossary/#blockchain)) or [peer-to-peer networks](/glossary/#peer-to-peer-network). This makes DIDs [globally unique, resolvable with high availability, and cryptographically verifiable](https://w3c-ccg.github.io/did-primer/). A decentralized identifier can be associated with different entities, including people, organizations, or government institutions. + +## What makes decentralized identifiers possible? + +### 1. Public Key Cryptography + +Public-key cryptography is an information security measure that generates a [public key](/glossary/#public-key) and [private key](/glossary/#private-key) for an entity. Public-key [cryptography](/glossary/#cryptography) is used in blockchain networks to authenticate user identities and prove ownership of digital assets. + +Some decentralized identifiers, such as an Ethereum account, have public and private keys. The public key identifies the account's controller, while the private keys can sign and decrypt messages for this account. Public key cryptography provides proofs needed to authenticate entities and prevent impersonation and use of fake identities, using [cryptographic signatures](https://andersbrownworth.com/blockchain/public-private-keys/) to verify all claims. + +### 2. Decentralized datastores + +A blockchain serves as a verifiable data registry: an open, trustless, and decentralized repository of information. The existence of public blockchains eliminates the need to store identifiers in centralized registries. + +If anyone needs to confirm the validity of a decentralized identifier, they can look up the associated public key on the blockchain. This is different from traditional identifiers that require third parties to authenticate. + +## How do decentralized identifiers and attestations enable decentralized identity? + +Decentralized identity is the idea that identity-related information should be self-controlled, private, and portable, with decentralized identifiers and attestations being the primary building blocks. + +In the context of decentralized identity, attestations (also known as [Verifiable Credentials](https://www.w3.org/TR/vc-data-model/)) are tamper-proof, cryptographically verifiable claims made by the issuer. Every attestation or Verifiable Credential an entity (e.g., an organization) issues is associated with their DID. + +Because DIDs are stored on the blockchain, anyone can verify the validity of an attestation by cross-checking the issuer's DID on Ethereum. Essentially, the Ethereum blockchain acts like a global directory that enables the verification of DIDs associated with certain entities. + +Decentralized identifiers are the reason attestations are self-controlled and verifiable. Even if the issuer doesn't exist anymore, the holder always has proof of the attestation's provenance and validity. + +Decentralized identifiers are also crucial to protecting the privacy of personal information through decentralized identity. For instance, if an individual submits proof of an attestation (a driver's license), the verifying party doesn't need to check the validity of information in the proof. Instead, the verifier only needs cryptographic guarantees of the attestation's authenticity and the identity of the issuing organization to determine if the proof is valid. + +## Types of attestations in decentralized identity + +How attestation information is stored and retrieved in an Ethereum-based identity ecosystem is different from traditional identity management. Here is an overview of the various approaches to issuing, storing, and verifying attestations in decentralized identity systems: + +### Offchain attestations + +One concern with storing attestations onchain is that they might contain information individuals want to keep private. The public nature of the Ethereum blockchain makes it unattractive to store such attestations. + +The solution is to issue attestations, held by users offchain in digital wallets, but signed with the issuer's DID stored onchain. These attestations are encoded as [JSON Web Tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) and contain the issuer's digital signature—which allows for easy verification of offchain claims. + +Here's an hypothetical scenario to explain offchain attestations: + +1. A university (the issuer) generates an attestation (a digital academic certificate), signs with its keys, and issues it to Bob (the identity owner). + +2. Bob applies for a job and wants to prove his academic qualifications to an employer, so he shares the attestation from his mobile wallet. The company (the verifier) can then confirm the validity of the attestation by checking the issuer's DID (i.e., its public key on Ethereum). + +### Offchain attestations with persistent access + +Under this arrangement attestations are transformed into JSON files and stored offchain (ideally on a [decentralized cloud storage](/developers/docs/storage/) platform, such as IPFS or Swarm). However, a [hash](/glossary/#hash) of the JSON file is stored onchain and linked to a DID via an onchain registry. The associated DID could either be that of the issuer of the attestation or the recipient. + +This approach enables attestations to gain blockchain-based persistence, while keeping claims information encrypted and verifiable. It also allows for selective disclosure since the holder of the private key can decrypt the information. + +### Onchain attestations + +Onchain attestations are held in [smart contracts](/glossary/#smart-contract) on the Ethereum blockchain. The smart contract (acting as a registry) will map an attestation to a corresponding onchain decentralized identifier (a public key). + +Here's an example to show how onchain attestations might work in practice: + +1. A company (XYZ Corp) plans to sell ownership shares using a smart contract but only wants buyers that have completed a background check. + +2. XYZ Corp can have the company performing background checks to issue onchain attestations on Ethereum. This attestation certifies that an individual has passed the background check without exposing any personal information. + +3. The smart contract selling shares can check the registry contract for the identities of screened buyers, making it possible for the smart contract to determine who is permitted to buy shares or not. + +### Soulbound tokens and identity + +[Soulbound tokens](https://vitalik.eth.limo/general/2022/01/26/soulbound.html) ([non-transferable NFTs](/glossary/#nft)) could be used to collect information unique to a specific wallet. This effectively creates a unique onchain identity bound to a particular Ethereum address that could include tokens representing achievements (e.g. finishing some specific online course or passing a threshold score in a game) or community participation. + +## Use decentralized identity + +There are many ambitious projects using Ethereum as a foundation for decentralized identity solutions: + +- **[Ethereum Name Service (ENS)](https://ens.domains/)** - _A decentralized naming system for onchain, machine-readable identifiers, like, Ethereum wallet addresses, content hashes, and metadata._ +- **[SpruceID](https://www.spruceid.com/)** - _A decentralized identity project which allows users to control digital identity with Ethereum accounts and ENS profiles instead of relying on third-party services._ +- **[Ethereum Attestation Service (EAS)](https://attest.sh/)** - _A decentralized ledger/protocol for making onchain or offchain attestations about anything._ +- **[Proof of Humanity](https://www.proofofhumanity.id)** - _Proof of Humanity (or PoH) is a social identity verification system built on Ethereum._ +- **[BrightID](https://www.brightid.org/)** - _A decentralized, open-source social identity network seeking to reform identity verification through the creation and analysis of a social graph._ +- **[walt.id](https://walt.id)** — _Open source decentralized identity and wallet infrastructure that enables developers and organizations to leverage self-sovereign identity and NFTs/SBTs._ +- **[Veramo](https://veramo.io/)** - _A JavaScript framework that makes it easy for anyone to use cryptographically verifiable data in their applications._ + +## Further reading + +### Articles + +- [Blockchain Use Cases: Blockchain in Digital Identity](https://consensys.net/blockchain-use-cases/digital-identity/) — _ConsenSys_ +- [What is Ethereum ERC725? Self-Sovereign Identity Management on the Blockchain](https://cryptoslate.com/what-is-erc725-self-sovereign-identity-management-on-the-blockchain/) — _Sam Town_ +- [How Blockchain Could Solve the Problem of Digital Identity](https://time.com/6142810/proof-of-humanity/) — _Andrew R. Chow_ +- [What Is Decentralized Identity And Why Should You Care?](https://web3.hashnode.com/what-is-decentralized-identity) — _Emmanuel Awosika_ +- [Introduction to Decentralized Identity](https://walt.id/white-paper/digital-identity) — _Dominik Beron_ + +### Videos + +- [Decentralized Identity (Bonus Livestream Session)](https://www.youtube.com/watch?v=ySHNB1za_SE&t=539s) — _A great explainer video on decentralized identity by Andreas Antonopolous_ +- [Sign In with Ethereum and Decentralized Identity with Ceramic, IDX, React, and 3ID Connect](https://www.youtube.com/watch?v=t9gWZYJxk7c) — _YouTube tutorial on building out an identity management system for creating, reading, and updating a user's profile using their Ethereum wallet by Nader Dabit_ +- [BrightID - Decentralized Identity on Ethereum](https://www.youtube.com/watch?v=D3DbMFYGRoM) — _Bankless podcast episode discussing BrightID, a decentralized identity solution for Ethereum_ +- [The Offchain Internet: Decentralized Identity & Verifiable Credentials](https://www.youtube.com/watch?v=EZ_Bb6j87mg) — EthDenver 2022 presentation by Evin McMullen +- [Verifiable Credentials Explained](https://www.youtube.com/watch?v=ce1IdSr-Kig) - YouTube explainer video with demo by Tamino Baumann + +### Communities + +- [ERC-725 Alliance on GitHub](https://github.com/erc725alliance) — _Supporters of the ERC725 standard for managing identity on the Ethereum blockchain_ +- [SpruceID Discord server](https://discord.com/invite/Sf9tSFzrnt) — _Community for enthusiasts and developers working on Sign-in with Ethereum_ +- [Veramo Labs](https://discord.gg/sYBUXpACh4) — _A community of developers contributing to building a framework for verifiable data for applications_ +- [walt.id](https://discord.com/invite/AW8AgqJthZ) — _A community of developers and builders working on decentralized identity use cases across various industries_ + +--- + +# Defi + +## Defi + +DeFi is an open and global financial system built for the internet age – an alternative to a system that's opaque, tightly controlled, and held together by decades-old infrastructure and processes. It gives you control and visibility over your money. It gives you exposure to global markets and alternatives to your local currency or banking options. DeFi products open up financial services to anyone with an internet connection and they're largely owned and maintained by their users. So far tens of billions of dollars worth of crypto has flowed through DeFi applications and it's growing every day. + +## What's DeFi? + +DeFi is a collective term for financial products and services that are accessible to anyone who can use Ethereum – anyone with an internet connection. With DeFi, the markets are always open and there are no centralized authorities who can block payments or deny you access to anything. Services that were previously slow and at risk of human error are automatic and safer now that they're handled by code that anyone can inspect and scrutinize. + +There's a booming crypto economy out there, where you can lend, borrow, long/short, earn interest, and more. Crypto-savvy Argentinians have used DeFi to escape crippling inflation. Companies have started streaming their employees their wages in real time. Some folks have even taken out and paid off loans worth millions of dollars without the need for any personal identification. + + + +## DeFi vs traditional finance + +One of the best ways to see the potential of DeFi is to understand the problems that exist today. + +- Some people aren't granted access to set up a bank account or use financial services. +- Lack of access to financial services can prevent people from being employable. +- Financial services can block you from getting paid. +- A hidden charge of financial services is your personal data. +- Governments and centralized institutions can close down markets at will. +- Trading hours are often limited to business hours of a specific time zone. +- Money transfers can take days due to internal human processes. +- There's a premium to financial services because intermediary institutions need their cut. + +### A comparison + +| DeFi | Traditional finance | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| You hold your money. | Your money is held by companies. | +| You control where your money goes and how it's spent. | You have to trust companies not to mismanage your money, like lending to risky borrowers. | +| Transfers of funds happen in minutes. | Payments can take days due to manual processes. | +| Transaction activity is pseudonymous. | Financial activity is tightly coupled with your identity. | +| DeFi is open to anyone. | You must apply to use financial services. | +| The markets are always open. | Markets close because employees need breaks. | +| It's built on transparency – anyone can look at a product's data and inspect how the system works. | Financial institutions are closed books: you can't ask to see their loan history, a record of their managed assets, and so on. | + + + Explore DeFi apps + + +## It started with Bitcoin... + +Bitcoin in many ways was the first DeFi application. Bitcoin lets you really own and control value and send it anywhere around the world. It does this by providing a way for a large number of people, who don't trust each other, to agree on a ledger of accounts without the need for a trusted intermediary. Bitcoin is open to anyone and no one has the authority to change its rules. Bitcoin's rules, like its scarcity and its openness, are written into the technology. It's not like traditional finance where governments can print money that devalues your savings and companies can shut down markets. + +Ethereum builds on this. Like Bitcoin, the rules can't change on you and everyone has access. But it also makes this digital money programmable, using [smart contracts](/glossary/#smart-contract), so you can go beyond storing and sending value. + + + +## Programmable money + +This sounds odd... "why would I want to program my money"? However, this is more just a default feature of tokens on Ethereum. Anyone can program logic into payments. So you can get the control and security of Bitcoin mixed with the services provided by financial institutions. This lets you do things with cryptocurrencies that you can't do with Bitcoin like lending and borrowing, scheduling payments, investing in index funds and more. + + + Explore our suggestions for DeFi applications to try out if you're new to Ethereum. + + Explore DeFi apps + + + +## What can you do with DeFi? + +There's a decentralized alternative to most financial services. But Ethereum also creates opportunities for creating financial products that are completely new. This is an ever-growing list. + +- [Send money around the globe](#send-money) +- [Stream money around the globe](#stream-money) +- [Access stable currencies](#stablecoins) +- [Borrow funds with collateral](#lending) +- [Borrow without collateral](#flash-loans) +- [Start crypto savings](#saving) +- [Trade tokens](#swaps) +- [Grow your portfolio](#investing) +- [Fund your ideas](#crowdfunding) +- [Buy insurance](#insurance) +- [Manage your portfolio](#aggregators) + + + +### Send money around the globe quickly + +As a blockchain, Ethereum is designed for sending transactions in a secure and global way. Like Bitcoin, Ethereum makes sending money around the world as easy as sending an email. Just enter your recipient's [ENS name](/glossary/#ens) (like bob.eth) or their account address from your wallet and your payment will go directly to them in minutes (usually). To send or receive payments, you will need a [wallet](/wallets/). + + + See payment dapps + + +#### Stream money around the globe... + +You can also stream money over Ethereum. This lets you pay someone their salary by the second, giving them access to their money whenever they need it. Or rent something by the second like a storage locker or electric scooter. + +And if you don't want to send or stream [ETH](/glossary/#ether) because of how much its value can change, there are alternative currencies on Ethereum: [stablecoins](/glossary/#stablecoin). + + + +### Access stable currencies + +Cryptocurrency volatility is a problem for lots of financial products and general spending. The DeFi community has solved this with stablecoins. Their value stays pegged to an another asset, usually a popular currency like dollars. + +Coins like Dai or USDC have a value that stays within a few cents of a dollar. This makes them perfect for earning or retail. Many people in Latin America have used stablecoins as a way of protecting their savings in a time of great uncertainty with their government-issued currencies. + + + More on stablecoins + + + + +### Borrowing + +Borrowing money from decentralized providers comes in two main varieties. + +- Peer-to-peer, meaning a borrower will borrow directly from a specific lender. +- Pool-based where lenders provide funds (liquidity) to a pool that borrowers can borrow from. + + + See borrowing dapps + + +There are many advantages to using a decentralized lender... + +#### Borrowing with privacy + +Today, lending and borrowing money all revolves around the individuals involved. Banks need to know whether you're likely to repay a loan before lending. + +Decentralized lending works without either party having to identify themselves. Instead, the borrower must put up collateral that the lender will automatically receive if their loan is not repaid. Some lenders even accept [NFTs](/glossary/#nft) as collateral. NFTs are a deed to a unique asset, like a painting. [More on NFTs](/nft/) + +This allows you to borrow money without credit checks or handing over private information. + +#### Access to global funds + +When you use a decentralized lender you have access to funds deposited from all over the globe, not just the funds in the custody of your chosen bank or institution. This makes loans more accessible and improves the interest rates. + +#### Tax-efficiencies + +Borrowing can give you access to the funds you need without needing to sell your ETH (a taxable event). Instead, you can use ETH as collateral for a stablecoin loan. This gives you the cash-flow you need and lets you keep your ETH. Stablecoins are tokens that are much better for when you need cash as they don't fluctuate in value like ETH. [More on stablecoins](#stablecoins) + +#### Flash loans + +Flash loans are a more experimental form of decentralized lending that let you borrow without collateral or providing any personal information. + +They're not widely accessible to non-technical folks right now but they hint at what might be possible to everyone in the future. + +It works on the basis that the loan is taken out and paid back within the same transaction. If it can't be paid back, the transaction reverts as if nothing ever happened. + +The funds that are often used are held in liquidity pools (big pools of funds used for borrowing). If they are not being used at a given moment, this creates an opportunity for someone to borrow these funds, conduct business with them, and repay them in-full quite literally at the same time they're borrowed. + +This means a lot of logic must be included in a very bespoke transaction. A simple example might be someone using a flash loan to borrow as much of an asset at one price so they can sell it on a different exchange where the price is higher. + +So in a single transaction, the following happens: + +- You borrow X amount of $asset at $1.00 from exchange A +- You sell X $asset on exchange B for $1.10 +- You pay back loan to exchange A +- You keep the profit minus the transaction fee + +If exchange B's supply dropped suddenly and the user wasn't able to buy enough to cover the original loan, the transaction would simply fail. + +To be able to do the above example in the traditional finance world, you'd need an enormous amount of money. These money-making strategies are only accessible to those with existing wealth. Flash loans are an example of a future where having money is not necessarily a prerequisite for making money. + + + More on flash loans + + + + +### Start saving with crypto + +#### Lending + +You can earn interest on your crypto by lending it and see your funds grow in real time. Right now interest rates are much higher than what you're likely to get at your local bank (if you're lucky enough to be able to access one). Here's an example: + +- You lend your 100 Dai, a [stablecoin](/stablecoins/), to a product like Aave. +- You receive 100 Aave Dai (aDai) which is a token that represents your loaned Dai. +- Your aDai will increase based on the interest rates and you can see your balance growing in your wallet. Dependent on the [APR](/glossary/#apr), your wallet balance will read something like 100.1234 after a few days or even hours! +- You can withdraw an amount of regular Dai that's equal to your aDai balance at any time. + + + See lending dapps + + +#### No-loss lotteries + +No-loss lotteries like PoolTogether are a fun and innovative new way to save money. + +- You buy 100 tickets using 100 Dai tokens. +- You receive 100 plDai representing your 100 tickets. +- If one of your tickets is picked as the winner, your plDai balance will increase by the amount of the prize pool. +- If you don't win, your 100 plDai rolls over to next week's draw. +- You can withdraw an amount of regular Dai that's equal to your plDai balance at any time. + +The prize pool is generated by all the interest generated by lending the ticket deposits like in the lending example above. + + + Try PoolTogether + + + + +### Exchange tokens + +There are thousands of tokens on Ethereum. Decentralized exchanges (DEXs) let you trade different tokens whenever you want. You never give up control of your assets. This is like using a currency exchange when visiting a different country. But the DeFi version never closes. The markets are 24/7, 365 days a year and the technology guarantees there will always be someone to accept a trade. + +For example, if you want to use the no-loss lottery PoolTogether (described above), you'll need a token like Dai or USDC. These DEXs allow you to swap your ETH for those tokens and back again when you're finished. + + + See token exchanges + + + + +### Advanced trading + +There are more advanced options for traders who like a little more control. Limit orders, perpetuals, margin trading and more are all possible. With Decentralized trading you get access to global liquidity, the market never closes, and you're always in control of your assets. + +When you use a centralized exchange you have to deposit your assets before the trade and trust them to look after them. While your assets are deposited, they're at risk as centralized exchanges are attractive targets for hackers. + + + See trading dapps + + + + +### Grow your portfolio + +There are fund management products on Ethereum that will try to grow your portfolio based on a strategy of your choice. This is automatic, open to everyone, and doesn't need a human manager taking a cut of your profits. + +A good example is the [DeFi Pulse Index fund (DPI)](https://defipulse.com/blog/defi-pulse-index/). This is a fund that rebalances automatically to ensure your portfolio always includes the top DeFi tokens by market capitalization. You never have to manage any of the details and you can withdraw from the fund whenever you like. + + + See investment dapps + + + + +### Fund your ideas + +Ethereum is an ideal platform for crowdfunding: + +- Potential funders can come from anywhere – Ethereum and its tokens are open to anybody, anywhere in the world. +- It's transparent so fundraisers can prove how much money has been raised. You can even trace how funds are being spent later down the line. +- Fundraisers can set up automatic refunds if, for example, there is a specific deadline and minimum amount that isn't met. + + + See crowdfunding dapps + + +#### Quadratic funding + +Ethereum is open source software and a lot of the work so far has been funded by the community. This has led to the growth of an interesting new fundraising model: quadratic funding. This has the potential to improve the way we fund all types of public goods in the future. + +Quadratic funding makes sure that the projects that receive the most funding are those with the most unique demand. In other words, projects that stand to improve the lives of the most people. Here's how it works: + +1. There is a matching pool of funds donated. +2. A round of public funding starts. +3. People can signal their demand for a project by donating some money. +4. Once the round is over, the matching pool is distributed to projects. Those with the most unique demand get the highest amount from the matching pool. + +This means Project A with its 100 donations of 1 dollar could end up with more funding than Project B with a single donation of 10,000 dollars (dependent on the size of the matching pool). + + + More on quadratic funding + + + + +### Insurance + +Decentralized insurance aims to make insurance cheaper, faster to pay out, and more transparent. With more automation, coverage is more affordable and pay-outs are a lot quicker. The data used to decide on your claim is completely transparent. + +Ethereum products, like any software, can suffer from bugs and exploits. So right now a lot of insurance products in the space focus on protecting their users against loss of funds. However, there are projects starting to build out coverage for everything life can throw at us. A good example of this is Etherisc's Crop cover which aims to [protect smallholder farmers in Kenya against droughts and flooding](https://blog.etherisc.com/etherisc-teams-up-with-chainlink-to-deliver-crop-insurance-in-kenya-137e433c29dc). Decentralized insurance can provide cheaper cover for farmers who are often priced out of traditional insurance. + + + See insurance dapps + + + + +### Aggregators and portfolio managers + +With so much going on, you'll need a way to keep track of all your investments, loans, and trades. There are a host of products that let you coordinate all your DeFi activity from one place. This is the beauty of DeFi's open architecture. Teams can build out interfaces where you can't just see your balances across products, you can use their features too. You might find this useful as you explore more of DeFi. + + + See portfolio dapps + + + + +## How does DeFi work? + +DeFi uses cryptocurrencies and smart contracts to provide services that don't need intermediaries. In today's financial world, financial institutions act as guarantors of transactions. This gives these institutions immense power because your money flows through them. Plus billions of people around the world can't even access a bank account. + +In DeFi, a smart contract replaces the financial institution in the transaction. A smart contract is a type of Ethereum account that can hold funds and can send/refund them based on certain conditions. No one can alter that smart contract when it's live – it will always run as programmed. + +A contract that's designed to hand out an allowance or pocket money could be programmed to send money from Account A to Account B every Friday. And it will only ever do that as long as Account A has the required funds. No one can change the contract and add Account C as a recipient to steal funds. + +Contracts are also public for anyone to inspect and audit. This means bad contracts will often come under community scrutiny pretty quickly. + +This does mean there's currently a need to trust the more technical members of the Ethereum community who can read code. The open-source based community helps keep developers in check, but this need will diminish over time as smart contracts become easier to read and other ways to prove trustworthiness of code are developed. + +## Ethereum and DeFi + +Ethereum is the perfect foundation for DeFi for a number of reasons: + +- No one owns Ethereum or the smart contracts that live on it – this gives everyone an opportunity to use DeFi. This also means no one can change the rules on you. +- DeFi products all speak the same language behind the scenes: Ethereum. This means many of the products work together seamlessly. You can lend tokens on one platform and exchange the interest-bearing token in a different market on an entirely different application. This is like being able to cash loyalty points in at your bank. +- Tokens and cryptocurrency are built into Ethereum, a shared ledger – keeping track of transactions and ownership is kinda Ethereum's thing. +- Ethereum allows complete financial freedom – most products will never take custody of your funds, leaving you in control. + +You can think of DeFi in layers: + +1. The blockchain – Ethereum contains the transaction history and state of accounts. +2. The assets – [ETH](/eth/) and the other tokens (currencies). +3. The protocols – [smart contracts](/glossary/#smart-contract) that provide the functionality, for example, a service that allows for decentralized lending of assets. +4. [The applications](/dapps/) – the products we use to manage and access the protocols. + +Note: much of DeFi uses the [ERC-20 standard](/glossary/#erc-20). Applications in DeFi use a wrapper for ETH called Wrapped ether (WETH). [Learn more about wrapped ether](/wrapped-eth). + +## Build DeFi + +DeFi is an open-source movement. The DeFi protocols and applications are all open for you to inspect, fork, and innovate on. Because of this layered stack (they all share the same base blockchain and assets), protocols can be mixed and matched to unlock unique combo opportunities. + + + More on building dapps + + +## Further reading + +### DeFi data + +- [DeFi Prime](https://defiprime.com/) +- [DeFi Llama](https://defillama.com/) + +### DeFi articles + +- [A beginner's guide to DeFi](https://blog.coinbase.com/a-beginners-guide-to-decentralized-finance-defi-574c68ff43c4) – _Sid Coelho-Prabhu, January 6, 2020_ + +### Videos + +- [Finematics - decentralized finance education](https://finematics.com/) – _Videos on DeFi_ +- [The Defiant](https://www.youtube.com/playlist?list=PLaDcID4s1KronHMKojfjwiHL0DdQEPDcq) - _DeFi basics: Everything you need to know to get started in this occasionally baffling space._ +- [Whiteboard Crypto](https://youtu.be/17QRFlml4pA) _What is DeFi?_ + +### Communities + +- [DeFi Llama Discord server](https://discord.defillama.com/) +- [DeFi Pulse Discord server](https://discord.gg/Gx4TCTk) + +--- + +# Desci + +## Desci + +## What is decentralized science (DeSci)? + +Decentralized science (DeSci) is a movement that aims to build public infrastructure for funding, creating, reviewing, crediting, storing, and disseminating scientific knowledge fairly and equitably using the [Web3](/glossary/#web3) stack. + +DeSci aims to create an ecosystem where scientists are incentivized to openly share their research and receive credit for their work while allowing anyone to access and contribute to the research easily. DeSci works off the idea that scientific knowledge should be accessible to everyone and that the process of scientific research should be transparent. DeSci is creating a more decentralized and distributed scientific research model, making it more resistant to censorship and control by central authorities. DeSci hopes to create an environment where new and unconventional ideas can flourish by decentralizing access to funding, scientific tools, and communication channels. + +Decentralized science allows for more diverse funding sources (from [DAOs](/glossary/#dao), [quadratic donations](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531) to crowdfunding and more), more accessible data and methods, and by providing incentives for reproducibility. + +### Juan Benet - The DeSci Movement + + + +## How DeSci improves science + +An incomplete list of key problems in science and how decentralized science can help to address these issues + +| **Decentralized science** | **Traditional science** | +| ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| Distribution of funds is **determined by the public** using mechanisms such as quadratic donations or DAOs. | Small, closed, **centralized groups** control the distribution of funds. | +| You collaborate with peers from **all over the globe** in dynamic teams. | Funding organizations and home institutions **limit** your collaborations. | +| Funding decisions are made online and **transparently**. New funding mechanisms are explored. | Funding decisions are made with a long turnaround time and **limited transparency**. Few funding mechanisms exist. | +| Sharing laboratory services is made easier and more transparent using [Web3](/glossary/#web3) technology. | Sharing laboratory resources is often **slow and opaque**. | +| **New models for publishing** can be developed that use Web3 primitives for trust, transparency and universal access. | You publish through established pathways frequently acknowledged as **inefficient, biased and exploitative**. | +| You can **earn tokens and reputation for peer-reviewing** work. | Your **peer-review work is unpaid**, benefiting for-profit publishers. | +| **You own the intellectual property (IP)** you generate and distribute it according to transparent terms. | **Your home institution owns the IP** you generate. Access to the IP is not transparent. | +| **Sharing all of the research**, including the data from unsuccessful efforts, by having all steps onchain. | **Publication bias** means that researchers are more likely to share experiments that had successful results. | + +## Ethereum and DeSci + +A decentralized science system will require robust security, minimal monetary and transaction costs, and a rich ecosystem for application development. Ethereum provides everything needed for building a decentralized science technology. + +## DeSci use cases + +DeSci is building the scientific toolset to onboard traditional academia into the digital world. Below is a sampling of use cases that Web3 can offer to the scientific community. + +### Publishing + +Science publishing is famously problematic because it is managed by publishing houses that rely upon free labor from scientists, reviewers, and editors to generate the papers but then charge exorbitant publishing fees. The public, who have usually indirectly paid for the work and the publication costs through taxation, can often not access that same work without paying the publisher again. The total fees for publishing individual science papers are often five figures ($USD), undermining the whole concept of scientific knowledge as a [public good](/glossary/#public-goods) while generating enormous profits for a small group of publishers. + +Free and open-access platforms exist in the form of pre-print servers, [such as ArXiv](https://arxiv.org/). However, these platforms lack quality control, [anti-sybil mechanisms](/glossary/#anti-sybil), and do not generally track article-level metrics, meaning they are usually only used to publicize work before submission to a traditional publisher. SciHub also makes published papers free to access, but not legally, and only after the publishers have already taken their payment and wrapped the work in strict copyright legislation. This leaves a critical gap for accessible science papers and data with an embedded legitimacy mechanism and incentive model. The tools for building such a system exist in Web3. + +### Reproducibility and replicability + +Reproducibility and replicability are the foundations of quality scientific discovery. + +- Reproducible results can be achieved multiple times in a row by the same team using the same methodology. +- Replicable results can be achieved by a different group using the same experimental setup. + +New Web3-native tools can ensure that reproducibility and replicability are the basis of discovery. We can weave quality science into the technological fabric of academia. Web3 offers the ability to create [attestations](/glossary/#attestation) for each analysis component: the raw data, the computational engine, and the application result. The beauty of consensus systems is that when a trusted network is created for maintaining these components, each network participant can be responsible for reproducing the calculation and validating each result. + +### Funding + +The current standard model for funding science is that individuals or groups of scientists make written applications to a funding agency. A small panel of trusted individuals score the applications and then interview candidates before awarding funds to a small portion of applicants. Aside from creating bottlenecks that lead to sometimes **years of waiting** time between applying for and receiving a grant, this model is known to be highly **vulnerable to the biases, self-interests and politics** of the review panel. + +Studies have shown that grant review panels do a poor job of selecting high-quality proposals as the same proposals given to different panels have wildly different outcomes. As funding has become more scarce, it has concentrated into a smaller pool of more senior researchers with more intellectually conservative projects. The effect has created a hyper-competitive funding landscape, entrenching perverse incentives and stifling innovation. + +Web3 has the potential to disrupt this broken funding model by experimenting with different incentive models developed by DAOs and Web3 broadly. [Retroactive public goods funding](https://medium.com/ethereum-optimism/retroactive-public-goods-funding-33c9b7d00f0c), [quadratic funding](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531), [DAO governance](https://www.antler.co/blog/daos-and-web3-governance-the-promise-implications-and-challenges-ahead) and [tokenized incentive structures](https://cdixon.org/2017/05/27/crypto-tokens-a-breakthrough-in-open-network-design) are some of the Web3 tools that could revolutionize science funding. + +### IP ownership and development + +Intellectual property (IP) is a big problem in traditional science: from being stuck in universities or unused in biotechs, to being notoriously hard to value. However, ownership of digital assets (such as scientific data or articles) is something Web3 does exceptionally well using [non-fungible tokens (NFTs)](/glossary/#nft). + +In the same way that NFTs can pass revenue for future transactions back to the original creator, you can establish transparent value attribution chains to reward researchers, governing bodies (like DAOs), or even the subjects whose data is collected. + +[IP-NFTs](https://medium.com/molecule-blog/ip-nfts-for-researchers-a-new-biomedical-funding-paradigm-91312d8d92e6) can also function as a key to a decentralized data repository of the research experiments being undertaken, and plug into NFT and [DeFi](/glossary/#defi) financialization (from fractionalization to lending pools and value appraisal). It also allows natively onchain entities such as DAOs like [VitaDAO](https://www.vitadao.com/) to conduct research directly onchain. +The advent of non-transferable ["soulbound" tokens](https://vitalik.eth.limo/general/2022/01/26/soulbound.html) may also play an important role in DeSci by allowing individuals to prove their experience and credentials linked to their Ethereum address. + +### Data storage, access and architecture + +Scientific data can be made vastly more accessible using Web3 patterns, and distributed storage enables research to survive cataclysmic events. + +The starting point must be a system accessible by any decentralized identity holding the proper verifiable credentials. This allows sensitive data to be securely replicated by trusted parties, enabling redundancy and censorship resistance, reproduction of results, and even the ability for multiple parties to collaborate and add new data to the dataset. Confidential computing methods like [compute-to-data](https://7wdata.be/predictive-analytics/compute-to-data-using-blockchain-to-decentralize-data-science-and-ai-with-the-ocean-protocol) provide alternative access mechanisms to raw data replication, creating Trusted Research Environments for the most sensitive data. Trusted Research Environments have been [cited by the NHS](https://medium.com/weavechain/whats-in-store-for-the-future-of-healthcare-data-b6398745fbbb) as a future-facing solution to data privacy and collaboration by creating an ecosystem where researchers can securely work with data on-site using standardized environments for sharing code and practices. + +Flexible Web3 data solutions support the scenarios above and provide the foundation for truly Open Science, where researchers can create public goods without access permissions or fees. Web3 public data solutions such as IPFS, Arweave and Filecoin are optimized for decentralization. dClimate, for example, provides universal access to climate and weather data, including from weather stations and predictive climate models. + +## Get involved + +Explore projects and join the DeSci community. + +- [DeSci.Global: global events and meetup calendar](https://desci.global) +- [Blockchain for Science Telegram](https://t.me/BlockchainForScience) +- [Molecule: Fund and get funded for your research projects](https://www.molecule.xyz/) +- [VitaDAO: receive funding through sponsored research agreements for longevity research](https://www.vitadao.com/) +- [ResearchHub: post a scientific result and engage in a conversation with peers](https://www.researchhub.com/) +- [LabDAO: fold a protein in-silico](https://alphafodl.vercel.app/) +- [dClimate API: query climate data collected by a decentralized community](https://www.dclimate.net/) +- [DeSci Foundation: DeSci publishing tool builder](https://descifoundation.org/) +- [DeSci.World: one-stop shop for users to view, engage with decentralized science](https://desci.world) +- [OceanDAO: DAO governed funding for data-related science](https://oceanprotocol.com/) +- [Opscientia: open decentralized science workflows](https://opsci.io/research/) +- [Bio.xyz: get funded for your biotech DAO or desci project](https://www.bio.xyz/) +- [Fleming Protocol: open-source data economy that fuels collaborative biomedical discovery](http://flemingprotocol.io/) +- [Active Inference Institute](https://www.activeinference.org/) +- [IdeaMarkets: enabling decentralized scientific credibility](https://ideamarket.io/) +- [DeSci Labs](https://www.desci.com/) +- [ValleyDAO: an open, global community offering funding and translational support for synthetic biology research](https://www.valleydao.bio) +- [Cerebrum DAO: sourcing and nurturing solutions to advance brain health and prevent neurodegeneration](https://www.cerebrumdao.com/) +- [CryoDAO: funding moonshot research in the field of cryopreservation](https://www.cryodao.org) + +We welcome suggestions for new projects to list - please look at our [listing policy](/contributing/adding-desci-projects/) to get started! + +## Further reading + +- [DeSci Wiki by Jocelynn Pearl and Ultrarare](https://docs.google.com/document/d/1aQC6zn-eXflSmpts0XGE7CawbUEHwnL6o-OFXO52PTc/edit#) +- [A guide to decentralized biotech by Jocelynn Pearl for a16z future](https://future.a16z.com/a-guide-to-decentralized-biotech/) +- [The case for DeSci](https://gitcoin.co/blog/desci-the-case-for-decentralised-science/) +- [Guide to DeSci](https://future.com/what-is-decentralized-science-aka-desci/) +- [Decentralized science resources](https://www.vincentweisser.com/desci) +- [Molecule’s Biopharma IP-NFTs - A Technical Description](https://www.molecule.xyz/blog/molecules-biopharma-ip-nfts-a-technical-description) +- [Building Trustless Systems of Science by Jon Starr](https://medium.com/@jringo/building-systems-of-trustless-science-1cd2d072f673) +- [Paul Kohlhaas - DeSci: The Future of Decentralized Science (podcast)](https://anchor.fm/andrew-steinwold/episodes/Paul-Kohlhaas---DeSci-The-Future-of-Decentralized-Science---Zima-Red-ep-117-e1h683a) +- [An Active Inference Ontology for Decentralized Science: from Situated Sensemaking to the Epistemic Commons](https://zenodo.org/record/6320575) +- [DeSci: The Future of Research by Samuel Akinosho](https://lucidsamuel.medium.com/desci-the-future-of-research-b76cfc88c8ec) +- [Science Funding (Epilogue: DeSci and new crypto primitives) by Nadia](https://nadia.xyz/science-funding) +- [Decentralisation is Disrupting Drug Development](https://medium.com/id-theory/decentralisation-is-disrupting-drug-development-28b5ba5d447f) +- [What Is DeSci – Decentralized Science?](https://usadailytimes.com/2022/09/12/what-is-desci-decentralized-science/) + +### Videos + +- [What's Decentralized Science?](https://www.youtube.com/watch?v=-DeMklVWNdA) +- [Conversation between Vitalik Buterin and the scientist Aubrey de Grey about the intersection of longevity research and crypto](https://www.youtube.com/watch?v=x9TSJK1widA) +- [Scientific Publishing Is Broken. Can Web3 Fix It?](https://www.youtube.com/watch?v=WkvzYgCvWj8) +- [Juan Benet - DeSci, Independent Labs, & Large Scale Data Science](https://www.youtube.com/watch?v=zkXM9H90g_E) +- [Sebastian Brunemeier - How DeSci Can Transform Biomedical Research & Venture Capital](https://www.youtube.com/watch?v=qB4Tc3FcVbM) +- [Paige Donner - Tooling Open Science with Web3 & The Blockchain](https://www.youtube.com/watch?v=nC-2QWQ-lgw&t=17s) + +--- + +# Developers + +## Developers > Docs > Accounts + +An Ethereum account is an entity with an ether (ETH) balance that can send messages on Ethereum. Accounts can be user-controlled or deployed as smart contracts. + +## Prerequisites + +To help you better understand this page, we recommend you first read through our [introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +## Account types + +Ethereum has two account types: + +- Externally-owned account (EOA) – controlled by anyone with the private keys +- Contract account – a smart contract deployed to the network, controlled by code. Learn about [smart contracts](/developers/docs/smart-contracts/) + +Both account types have the ability to: + +- Receive, hold and send ETH and tokens +- Interact with deployed smart contracts + +### Key differences + +**Externally-owned** + +- Creating an account costs nothing +- Can initiate transactions +- Transactions between externally-owned accounts can only be ETH/token transfers +- Made up of a cryptographic pair of keys: public and private keys that control account activities + +**Contract** + +- Creating a contract has a cost because you're using network storage +- Can only send messages in response to receiving a transaction +- Transactions from an external account to a contract account can trigger code which can execute many different actions, such as transferring tokens or even creating a new contract +- Contract accounts don't have private keys. Instead, they are controlled by the logic of the smart contract code + +## An account examined + +Ethereum accounts have four fields: + +- `nonce` – A counter that indicates the number of transactions sent from an externally-owned account or the number of contracts created by a contract account. Only one transaction with a given nonce can be executed for each account, protecting against replay attacks where signed transactions are repeatedly broadcast and re-executed. +- `balance` – The number of wei owned by this address. Wei is a denomination of ETH and there are 1e+18 wei per ETH. +- `codeHash` – This hash refers to the _code_ of an account on the Ethereum virtual machine (EVM). Contract accounts have code fragments programmed in that can perform different operations. This EVM code gets executed if the account gets a message call. It cannot be changed, unlike the other account fields. All such code fragments are contained in the state database under their corresponding hashes for later retrieval. This hash value is known as a codeHash. For externally owned accounts, the codeHash field is the hash of an empty string. +- `storageRoot` – Sometimes known as a storage hash. A 256-bit hash of the root node of a Merkle Patricia trie that encodes the storage contents of the account (a mapping between 256-bit integer values), encoded into the trie as a mapping from the Keccak 256-bit hash of the 256-bit integer keys to the RLP-encoded 256-bit integer values. This trie encodes the hash of the storage contents of this account, and is empty by default. + +![A diagram showing the make up of an account](./accounts.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +## Externally-owned accounts and key pairs + +An account is made up of a pair of cryptographic keys: public and private. They help prove that a transaction was actually signed by the sender and prevent forgeries. Your private key is what you use to sign transactions, so it grants you custody over the funds associated with your account. You never really hold cryptocurrency, you hold private keys – the funds are always on Ethereum's ledger. + +This prevents malicious actors from broadcasting fake transactions because you can always verify the sender of a transaction. + +If Alice wants to send ether from her own account to Bob’s account, Alice needs to create a transaction request and send it out to the network for verification. Ethereum’s usage of public-key cryptography ensures that Alice can prove that she originally initiated the transaction request. Without cryptographic mechanisms, a malicious adversary Eve could simply publicly broadcast a request that looks something like “send 5 ETH from Alice’s account to Eve’s account,” and no one would be able to verify that it didn’t come from Alice. + +## Account creation + +When you want to create an account, most libraries will generate you a random private key. + +A private key is made up of 64 hex characters and can be encrypted with a password. + +Example: + +`fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036415f` + +The public key is generated from the private key using the [Elliptic Curve Digital Signature Algorithm](https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm). You get a public address for your account by taking the last 20 bytes of the Keccak-256 hash of the public key and adding `0x` to the beginning. + +This means an Externally owned account (EOA) has a 42-character address (20-byte segment which is 40 hexadecimal characters plus the `0x` prefix). + +Example: + +`0x5e97870f263700f46aa00d967821199b9bc5a120` + +The following example shows how to use a signing tool called [Clef](https://geth.ethereum.org/docs/tools/clef/introduction) to generate a new account. Clef is an account management and signing tool that comes bundled with the Ethereum client, [Geth](https://geth.ethereum.org). The `clef newaccount` command creates a new key pair and saves them in an encrypted keystore. + +``` +> clef newaccount --keystore + +Please enter a password for the new account to be created: +> + +------------ +INFO [10-28|16:19:09.156] Your new key was generated address=0x5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] Please backup your key file path=/home/user/go-ethereum/data/keystore/UTC--2022-10-28T15-19-08.000825927Z--5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] Please remember your password! +Generated account 0x5e97870f263700f46aa00d967821199b9bc5a120 +``` + +[Geth documentation](https://geth.ethereum.org/docs) + +It is possible to derive new public keys from your private key, but you cannot derive a private key from public keys. It is vital to keep your private keys safe and, as the name suggests, **PRIVATE**. + +You need a private key to sign messages and transactions which output a signature. Others can then take the signature to derive your public key, proving the author of the message. In your application, you can use a JavaScript library to send transactions to the network. + +## Contract accounts + +Contract accounts also have a 42 character hexadecimal address: + +Example: + +`0x06012c8cf97bead5deae237070f9587f8e7a266d` + +The contract address is usually given when a contract is deployed to the Ethereum Blockchain. The address comes from the creator's address and the number of transactions sent from that address (the “nonce”). + +## Validator keys + +There is also another type of key in Ethereum, introduced when Ethereum switched from proof-of-work to proof-of-stake based consensus. These are 'BLS' keys and they are used to identify validators. These keys can be efficiently aggregated to reduce the bandwidth required for the network to come to consensus. Without this key aggregation the minimum stake for a validator would be much higher. + +[More on validator keys](/developers/docs/consensus-mechanisms/pos/keys/). + +## A note on wallets + +An account is not a wallet. A wallet is an interface or application that lets you interact with your Ethereum account, either an externally-owned account or a contract account. + +## A visual demo + +Watch Austin walk you through hash functions, and key pairs. + + + + + +## Further reading + +- [Understanding Ethereum Accounts](https://info.etherscan.com/understanding-ethereum-accounts/) - etherscan + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Smart contracts](/developers/docs/smart-contracts/) +- [Transactions](/developers/docs/transactions/) + +--- + +## Developers > Docs > Apis > Backend + +In order for a software application to interact with the Ethereum blockchain (i.e. read blockchain data and/or send transactions to the network), it must connect to an Ethereum node. + +For this purpose, every Ethereum client implements the [JSON-RPC](/developers/docs/apis/json-rpc/) specification, so there is a uniform set of [methods](/developers/docs/apis/json-rpc/#json-rpc-methods) that applications can rely on. + +If you want to use a specific programming language to connect with an Ethereum node, there are many convenience libraries within the ecosystem that make this much easier. With these libraries, developers can write intuitive, one-line methods to initialize JSON-RPC requests (under the hood) that interact with Ethereum. + +## Prerequisites + +It might be helpful to understand the [Ethereum stack](/developers/docs/ethereum-stack/) and [Ethereum clients](/developers/docs/nodes-and-clients/). + +## Why use a library? + +These libraries abstract away much of the complexity of interacting directly with an Ethereum node. They also provide utility functions (e.g. converting ETH to Gwei) so as a developer you can spend less time dealing with the intricacies of Ethereum clients and more time focused on the unique functionality of your application. + +## Available libraries + +### Infrastructure and node services + +**Alchemy -** **_Ethereum Development Platform._** + +- [alchemy.com](https://www.alchemy.com/) +- [Documentation](https://docs.alchemy.com/) +- [GitHub](https://github.com/alchemyplatform) +- [Discord](https://discord.com/invite/alchemyplatform) + +**All That Node -** **_Node-as-a-Service._** + +- [All That Node.com](https://www.allthatnode.com/) +- [Documentation](https://docs.allthatnode.com) +- [Discord](https://discord.gg/GmcdVEUbJM) + +**Blast by Bware Labs -** **_Decentralized APIs for Ethereum Mainnet and Testnets._** + +- [blastapi.io](https://blastapi.io/) +- [Documentation](https://docs.blastapi.io) +- [Discord](https://discord.gg/bwarelabs) + +**BlockPi -** **_Provide more efficient and fast RPC services_** + +- [blockpi.io](https://blockpi.io/) +- [Documentation](https://docs.blockpi.io/) +- [GitHub](https://github.com/BlockPILabs) +- [Discord](https://discord.com/invite/xTvGVrGVZv) + +**Cloudflare Ethereum Gateway.** + +- [cloudflare-eth.com](https://www.cloudflare.com/application-services/products/web3/) + +**Etherscan - Block Explorer and Transaction APIs** +- [Documentation](https://docs.etherscan.io/) + +**Blockscout - Open Source Block Explorer** +- [Documentation](https://docs.blockscout.com/) + +**GetBlock-** **_Blockchain-as-a-service for Web3 development_** + +- [GetBlock.io](https://getblock.io/) +- [Documentation](https://getblock.io/docs/) + +**Infura -** **_The Ethereum API as a service._** + +- [infura.io](https://infura.io) +- [Documentation](https://docs.infura.io/api) +- [GitHub](https://github.com/INFURA) + +**Node RPC - _Cost-effective EVM JSON-RPC provider_** + +- [noderpc.xyz](https://www.noderpc.xyz/) +- [Documentation](https://docs.noderpc.xyz/node-rpc) + +**NOWNodes - _Full Nodes and Block Explorers._** + +- [NOWNodes.io](https://nownodes.io/) +- [Documentation](https://documenter.getpostman.com/view/13630829/TVmFkLwy#intro) + +**QuickNode -** **_Blockchain Infrastructure as a Service._** + +- [quicknode.com](https://quicknode.com) +- [Documentation](https://www.quicknode.com/docs/welcome) +- [Discord](https://discord.gg/quicknode) + +**Rivet -** **_Ethereum and Ethereum Classic APIs as a service powered by open source software._** + +- [rivet.cloud](https://rivet.cloud) +- [Documentation](https://rivet.cloud/docs/) +- [GitHub](https://github.com/openrelayxyz/ethercattle-deployment) + +**Zmok -** **_Speed-oriented Ethereum nodes as JSON-RPC/WebSockets API._** + +- [zmok.io](https://zmok.io/) +- [GitHub](https://github.com/zmok-io) +- [Documentation](https://docs.zmok.io/) +- [Discord](https://discord.gg/fAHeh3ka6s) + +### Development tools + +**ethers-kt -** **_Async, high-performance Kotlin/Java/Android library for EVM-based blockchains._** + +- [GitHub](https://github.com/Kr1ptal/ethers-kt) +- [Examples](https://github.com/Kr1ptal/ethers-kt/tree/master/examples) +- [Discord](https://discord.gg/rx35NzQGSb) + +**Nethereum -** **_An open source .NET integration library for blockchain._** + +- [GitHub](https://github.com/Nethereum/Nethereum) +- [Documentation](http://docs.nethereum.com/en/latest/) +- [Discord](https://discord.com/invite/jQPrR58FxX) + +**Python Tooling -** **_Variety of libraries for Ethereum interaction via Python._** + +- [py.ethereum.org](https://python.ethereum.org/) +- [web3.py GitHub](https://github.com/ethereum/web3.py) +- [web3.py Chat](https://gitter.im/ethereum/web3.py) + +**Tatum -** **_The ultimate blockchain development platform._** + +- [Tatum](https://tatum.io/) +- [GitHub](https://github.com/tatumio/) +- [Documentation](https://docs.tatum.io/) +- [Discord](https://discord.gg/EDmW3kjTC9) + +**web3j -** **_A Java/Android/Kotlin/Scala integration library for Ethereum._** + +- [GitHub](https://github.com/web3j/web3j) +- [Docs](https://docs.web3j.io/) +- [Gitter](https://gitter.im/web3j/web3j) + +### Blockchain services + +**BlockCypher -** **_Ethereum Web APIs._** + +- [blockcypher.com](https://www.blockcypher.com/) +- [Documentation](https://www.blockcypher.com/dev/ethereum/) + +**Chainbase -** **_All-in-one web3 data infrastructure for Ethereum._** + +- [chainbase.com](https://chainbase.com/) +- [Documentation](https://docs.chainbase.com/) +- [Discord](https://discord.gg/Wx6qpqz4AF) + +**Chainstack -** **_Elastic and dedicated Ethereum nodes as a service._** + +- [chainstack.com](https://chainstack.com) +- [Documentation](https://docs.chainbase.com/docs) +- [Ethereum API reference](https://docs.chainstack.com/reference/ethereum-getting-started) + +**Coinbase Cloud Node -** **_Blockchain Infrastructure API._** + +- [Coinbase Cloud Node](https://www.coinbase.com/cloud) +- [Documentation](https://docs.cloud.coinbase.com/) + +**DataHub by Figment -** **_Web3 API services with Ethereum Mainnet and testnets._** + +- [DataHub](https://www.figment.io/) +- [Documentation](https://docs.figment.io/) + +**Moralis -** **_Enterprise-Grade EVM API Provider._** + +- [moralis.io](https://moralis.io) +- [Documentation](https://docs.moralis.io/) +- [GitHub](https://github.com/MoralisWeb3) +- [Discord](https://moralis.io/joindiscord/) +- [Forum](https://forum.moralis.io/) + +**NFTPort -** **_Ethereum Data and Mint APIs._** + +- [nftport.xyz](https://www.nftport.xyz/) +- [Documentation](https://docs.nftport.xyz/) +- [GitHub](https://github.com/nftport/) +- [Discord](https://discord.com/invite/K8nNrEgqhE) + +**Tokenview -** **_The General Multi-Crypto Blockchain APIs Platform._** + +- [services.tokenview.io](https://services.tokenview.io/) +- [Documentation](https://services.tokenview.io/docs?type=api) +- [GitHub](https://github.com/Tokenview) + +**Watchdata -** **_Provide simple and reliable API access to Ethereum blockchain._** + +- [Watchdata](https://watchdata.io/) +- [Documentation](https://docs.watchdata.io/) +- [Discord](https://discord.com/invite/TZRJbZ6bdn) + +**Covalent -** **_Enriched blockchain APIs for 200+ Chains._** + +- [covalenthq.com](https://www.covalenthq.com/) +- [Documentation](https://www.covalenthq.com/docs/api/) +- [GitHub](https://github.com/covalenthq) +- [Discord](https://www.covalenthq.com/discord/) + + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [Development frameworks](/developers/docs/frameworks/) + +## Related tutorials + +- [Set up Web3js to use the Ethereum blockchain in JavaScript](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– Instructions for getting web3.js set up in your project._ +- [Calling a smart contract from JavaScript](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– Using the DAI token, see how to call contracts function using JavaScript._ + +--- + +## Developers > Docs > Apis > Javascript + +In order for a web app to interact with the Ethereum blockchain (i.e. read blockchain data and/or send transactions to the network), it must connect to an Ethereum node. + +For this purpose, every Ethereum client implements the [JSON-RPC](/developers/docs/apis/json-rpc/) specification, so there are a uniform set of [methods](/developers/docs/apis/json-rpc/#json-rpc-methods) that applications can rely on. + +If you want to use JavaScript to connect with an Ethereum node, it's possible to use vanilla JavaScript but several convenience libraries exist within the ecosystem that make this much easier. With these libraries, developers can write intuitive, one-line methods to initialize JSON-RPC requests (under the hood) that interact with Ethereum. + +Please note that since [The Merge](/roadmap/merge/), two connected pieces of Ethereum software - an execution client and a consensus client - are required to run a node. Please ensure your node includes both an execution and consensus client. If your node is not on your local machine (e.g. your node is running on an AWS instance) update the IP addresses in the tutorial accordingly. For more information please see our page on [running a node](/developers/docs/nodes-and-clients/run-a-node/). + +## Prerequisites + +As well as understanding JavaScript, it might be helpful to understand the [Ethereum stack](/developers/docs/ethereum-stack/) and [Ethereum clients](/developers/docs/nodes-and-clients/). + +## Why use a library? + +These libraries abstract away much of the complexity of interacting directly with an Ethereum node. They also provide utility functions (e.g. converting ETH to Gwei) so as a developer you can spend less time dealing with the intricacies of Ethereum clients and more time focused on the unique functionality of your application. + +## Library features + +### Connect to Ethereum nodes + +Using providers, these libraries allow you to connect to Ethereum and read its data, whether that's over JSON-RPC, INFURA, Etherscan, Alchemy or MetaMask. + +> **Warning:** Web3.js was archived on March 4, 2025. [Read the announcement](https://blog.chainsafe.io/web3-js-sunset/). Consider using alternative libraries like ethers.js or viem for new projects. + +**Ethers example** + +```js +// A BrowserProvider wraps a standard Web3 provider, which is +// what MetaMask injects as window.ethereum into each page +const provider = new ethers.BrowserProvider(window.ethereum) + +// The MetaMask plugin also allows signing transactions to +// send ether and pay to change state within the blockchain. +// For this, we need the account signer... +const signer = provider.getSigner() +``` + +**Web3js example** + +```js +var web3 = new Web3("http://localhost:8545") +// or +var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")) + +// change provider +web3.setProvider("ws://localhost:8546") +// or +web3.setProvider(new Web3.providers.WebsocketProvider("ws://localhost:8546")) + +// Using the IPC provider in node.js +var net = require("net") +var web3 = new Web3("/Users/myuser/Library/Ethereum/geth.ipc", net) // mac os path +// or +var web3 = new Web3( + new Web3.providers.IpcProvider("/Users/myuser/Library/Ethereum/geth.ipc", net) +) // mac os path +// on windows the path is: "\\\\.\\pipe\\geth.ipc" +// on linux the path is: "/users/myuser/.ethereum/geth.ipc" +``` + +Once set up you'll be able to query the blockchain for: + +- block numbers +- gas estimates +- smart contract events +- network id +- and more... + +### Wallet functionality + +These libraries give you functionality to create wallets, manage keys and sign transactions. + +Here's an examples from Ethers + +```js +// Create a wallet instance from a mnemonic... +mnemonic = + "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol" +walletMnemonic = Wallet.fromPhrase(mnemonic) + +// ...or from a private key +walletPrivateKey = new Wallet(walletMnemonic.privateKey) + +walletMnemonic.address === walletPrivateKey.address +// true + +// The address as a Promise per the Signer API +walletMnemonic.getAddress() +// + +// A Wallet address is also available synchronously +walletMnemonic.address +// '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' + +// The internal cryptographic components +walletMnemonic.privateKey +// '0x1da6847600b0ee25e9ad9a52abbd786dd2502fa4005dd5af9310b7cc7a3b25db' +walletMnemonic.publicKey +// '0x04b9e72dfd423bcf95b3801ac93f4392be5ff22143f9980eb78b3a860c4843bfd04829ae61cdba4b3b1978ac5fc64f5cc2f4350e35a108a9c9a92a81200a60cd64' + +// The wallet mnemonic +walletMnemonic.mnemonic +// + +// Note: A wallet created with a private key does not +// have a mnemonic (the derivation prevents it) +walletPrivateKey.mnemonic +// null + +// Signing a message +walletMnemonic.signMessage("Hello World") +// + +tx = + +// Signing a transaction +walletMnemonic.signTransaction(tx) +// + +// The connect method returns a new instance of the +// Wallet connected to a provider +wallet = walletMnemonic.connect(provider) + +// Querying the network +wallet.getBalance() +// } +wallet.getTransactionCount() +// + +// Sending ether +wallet.sendTransaction(tx) +``` + +[Read the full docs](https://docs.ethers.io/v5/api/signer/#Wallet) + +Once set up you'll be able to: + +- create accounts +- send transactions +- sign transactions +- and more... + +### Interact with smart contract functions + +JavaScript client libraries allow your application to call smart contract functions by reading the Application Binary Interface (ABI) of a compiled contract. + +The ABI essentially explains the contract's functions in a JSON format and allows you to use it like a normal JavaScript object. + +So the following Solidity contract: + +```solidity +contract Test + + event Event(uint indexed b, bytes32 c); + + event Event2(uint indexed b, bytes32 c); + + function foo(uint b, bytes32 c) returns(address) +} +``` + +Would result in the following JSON: + +```json +[], + },, ], + "outputs":[] + },, ], + "anonymous":false + },,], + "anonymous":false +}] +``` + +This means you can: + +- Send a transaction to the smart contract and execute its method +- Call to estimate the gas a method execution will take when executed in the EVM +- Deploy a contract +- And more... + +### Utility functions + +Utility functions give you handy shortcuts that make building with Ethereum a little easier. + +ETH values are in Wei by default. 1 ETH = 1,000,000,000,000,000,000 WEI – this means you're dealing with a lot of numbers! `web3.utils.toWei` converts ether to Wei for you. + +And in ethers it looks like this: + +```js +// Get the balance of an account (by address or ENS name) +balance = await provider.getBalance("ethers.eth") +// + +// Often you will need to format the output for the user +// which prefer to see values in ether (instead of wei) +ethers.utils.formatEther(balance) +// '2.337132817842795605' +``` + +- [Web3js utility functions](https://docs.web3js.org/api/web3-utils) +- [Ethers utility functions](https://docs.ethers.io/v5/api/utils/) + +## Available libraries + +**Web3.js -** **_Ethereum JavaScript API._** + +- [Documentation](https://docs.web3js.org/) +- [GitHub](https://github.com/ethereum/web3.js/) + +**Ethers.js -** **_Complete Ethereum wallet implementation and utilities in JavaScript and TypeScript._** + +- [Documentation](https://docs.ethers.io/) +- [GitHub](https://github.com/ethers-io/ethers.js/) + +**The Graph -** **_A protocol for indexing Ethereum and IPFS data and querying it using GraphQL._** + +- [The Graph](https://thegraph.com/) +- [Graph Explorer](https://thegraph.com/explorer/) +- [Documentation](https://thegraph.com/docs/) +- [GitHub](https://github.com/graphprotocol/) +- [Discord](https://thegraph.com/discord) + +**light.js -** **_A high-level reactive JS library optimized for light clients._** + +- [GitHub](https://github.com/openethereum/js-libs/tree/master/packages/light.js) + +**Web3-wrapper -** **_Typescript alternative to Web3.js._** + +- [Documentation](https://0x.org/docs/web3-wrapper#introduction) +- [GitHub](https://github.com/0xProject/0x-monorepo/tree/development/packages/web3-wrapper) + +**Alchemyweb3 -** **_Wrapper around Web3.js with automatic retries and enhanced apis._** + +- [Documentation](https://docs.alchemy.com/reference/api-overview) +- [GitHub](https://github.com/alchemyplatform/alchemy-web3) + +**Alchemy NFT API -** **_API for fetching NFT data, including ownership, metadata attributes and more._** + +- [Documentation](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) +- [GitHub](https://github.com/alchemyplatform/alchemy-web3) + +**viem -** **_TypeScript Interface for Ethereum._** + +- [Documentation](https://viem.sh) +- [GitHub](https://github.com/wagmi-dev/viem) + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [Development frameworks](/developers/docs/frameworks/) + +## Related tutorials + +- [Set up Web3js to use the Ethereum blockchain in JavaScript](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– Instructions for getting web3.js set up in your project._ +- [Calling a smart contract from JavaScript](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– Using the DAI token, see how to call contracts function using JavaScript._ +- [Sending transactions using web3 and Alchemy](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) _– Step by step walkthrough for sending transactions from the backend._ + +--- + +## Developers > Docs > Apis > Json Rpc + +In order for a software application to interact with the Ethereum blockchain - either by reading blockchain data or sending transactions to the network - it must connect to an Ethereum node. + +For this purpose, every [Ethereum client](/developers/docs/nodes-and-clients/#execution-clients) implements a [JSON-RPC specification](https://github.com/ethereum/execution-apis), so there is a uniform set of methods that applications can rely on regardless of the specific node or client implementation. + +[JSON-RPC](https://www.jsonrpc.org/specification) is a stateless, light-weight remote procedure call (RPC) protocol. It defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as data format. + +## Client implementations + +Ethereum clients each may utilize different programming languages when implementing the JSON-RPC specification. See individual [client documentation](/developers/docs/nodes-and-clients/#execution-clients) for further details related to specific programming languages. We recommend checking the documentation of each client for the latest API support information. + +## Convenience Libraries + +While you may choose to interact directly with Ethereum clients via the JSON-RPC API, there are often easier options for dapp developers. Many [JavaScript](/developers/docs/apis/javascript/#available-libraries) and [backend API](/developers/docs/apis/backend/#available-libraries) libraries exist to provide wrappers on top of the JSON-RPC API. With these libraries, developers can write intuitive, one-line methods in the programming language of their choice to initialize JSON-RPC requests (under the hood) that interact with Ethereum. + +## Consensus client APIs + +This page deals mainly with the JSON-RPC API used by Ethereum execution clients. However, consensus clients also have an RPC API that allows users to query information about the node, request Beacon blocks, Beacon state, and other consensus-related information directly from a node. This API is documented on the [Beacon API webpage](https://ethereum.github.io/beacon-APIs/#/). + +An internal API is also used for inter-client communication within a node - that is, it enables the consensus client and execution client to swap data. This is called the 'Engine API' and the specs are available on [GitHub](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md). + +## Execution client spec + +[Read the full JSON-RPC API spec on GitHub](https://github.com/ethereum/execution-apis). This API is documented on the [Execution API webpage](https://ethereum.github.io/execution-apis/) and includes an Inspector to try out all the available methods. + +## Conventions + +### Hex value encoding + +Two key data types get passed over JSON: unformatted byte arrays and quantities. Both are passed with a hex encoding but with different requirements for formatting. + +#### Quantities + +When encoding quantities (integers, numbers): encode as hex, prefix with "0x", the most compact representation (slight exception: zero should be represented as "0x0"). + +Here are some examples: + +- 0x41 (65 in decimal) +- 0x400 (1024 in decimal) +- WRONG: 0x (should always have at least one digit - zero is "0x0") +- WRONG: 0x0400 (no leading zeroes allowed) +- WRONG: ff (must be prefixed 0x) + +### Unformatted data + +When encoding unformatted data (byte arrays, account addresses, hashes, bytecode arrays): encode as hex, prefix with "0x", two hex digits per byte. + +Here are some examples: + +- 0x41 (size 1, "A") +- 0x004200 (size 3, "0B0") +- 0x (size 0, "") +- WRONG: 0xf0f0f (must be even number of digits) +- WRONG: 004200 (must be prefixed 0x) + +### The block parameter + +The following methods have a block parameter: + +- [eth_getBalance](#eth_getbalance) +- [eth_getCode](#eth_getcode) +- [eth_getTransactionCount](#eth_gettransactioncount) +- [eth_getStorageAt](#eth_getstorageat) +- [eth_call](#eth_call) + +When requests are made that query the state of Ethereum, the provided block parameter determines the height of the block. + +The following options are possible for the block parameter: + +- `HEX String` - an integer block number +- `String "earliest"` for the earliest/genesis block +- `String "latest"` - for the latest proposed block +- `String "safe"` - for the latest safe head block +- `String "finalized"` - for the latest finalized block +- `String "pending"` - for the pending state/transactions + +## Examples + +On this page we provide examples of how to use individual JSON_RPC API endpoints using the command line tool, [curl](https://curl.se). These individual endpoint examples are found below in the [Curl examples](#curl-examples) section. Further down the page, we also provide an [end-to-end example](#usage-example) for compiling and deploying a smart contract using a Geth node, the JSON_RPC API and curl. + +## Curl examples + +Examples of using the JSON_RPC API by making [curl](https://curl.se) requests to an Ethereum node are provided below. Each example +includes a description of the specific endpoint, its parameters, return type, and a worked example of how it should be used. + +The curl requests might return an error message relating to the content type. This is because the `--data` option sets the content type to `application/x-www-form-urlencoded`. If your node does complain about this, manually set the header by placing `-H "Content-Type: application/json"` at the start of the call. The examples also do not include the URL/IP & port combination which must be the last argument given to curl (e.g. `127.0.0.1:8545`). A complete curl request including these additional data takes the following form: + +```shell +curl -H "Content-Type: application/json" -X POST --data '' 127.0.0.1:8545 +``` + +## Gossip, State, History + +A handful of core JSON-RPC methods require data from the Ethereum network, and fall neatly into three main categories: _Gossip, State, and History_. Use the links in these sections to jump to each method, or use the table of contents to explore the whole list of methods. + +### Gossip Methods + +> These methods track the head of the chain. This is how transactions make their way around the network, find their way into blocks, and how clients find out about new blocks. + +- [eth_blockNumber](#eth_blocknumber) +- [eth_sendRawTransaction](#eth_sendrawtransaction) + +### State Methods + +> Methods that report the current state of all the data stored. The "state" is like one big shared piece of RAM, and includes account balances, contract data, and gas estimations. + +- [eth_getBalance](#eth_getbalance) +- [eth_getStorageAt](#eth_getstorageat) +- [eth_getTransactionCount](#eth_gettransactioncount) +- [eth_getCode](#eth_getcode) +- [eth_call](#eth_call) +- [eth_estimateGas](#eth_estimategas) + +### History Methods + +> Fetches historical records of every block back to genesis. This is like one large append-only file, and includes all block headers, block bodies, uncle blocks, and transaction receipts. + +- [eth_getBlockTransactionCountByHash](#eth_getblocktransactioncountbyhash) +- [eth_getBlockTransactionCountByNumber](#eth_getblocktransactioncountbynumber) +- [eth_getUncleCountByBlockHash](#eth_getunclecountbyblockhash) +- [eth_getUncleCountByBlockNumber](#eth_getunclecountbyblocknumber) +- [eth_getBlockByHash](#eth_getblockbyhash) +- [eth_getBlockByNumber](#eth_getblockbynumber) +- [eth_getTransactionByHash](#eth_gettransactionbyhash) +- [eth_getTransactionByBlockHashAndIndex](#eth_gettransactionbyblockhashandindex) +- [eth_getTransactionByBlockNumberAndIndex](#eth_gettransactionbyblocknumberandindex) +- [eth_getTransactionReceipt](#eth_gettransactionreceipt) +- [eth_getUncleByBlockHashAndIndex](#eth_getunclebyblockhashandindex) +- [eth_getUncleByBlockNumberAndIndex](#eth_getunclebyblocknumberandindex) + +## JSON-RPC API Playground + +You can use the [playground tool](https://ethereum-json-rpc.com) to discover and try out the API methods. It also shows you which methods and networks are supported by various node providers. + +## JSON-RPC API Methods + +### web3_clientVersion + +Returns the current client version. + +**Parameters** + +None + +**Returns** + +`String` - The current client version + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### web3_sha3 + +Returns Keccak-256 (_not_ the standardized SHA3-256) of the given data. + +**Parameters** + +1. `DATA` - The data to convert into a SHA3 hash + +```js +params: ["0x68656c6c6f20776f726c64"] +``` + +**Returns** + +`DATA` - The SHA3 result of the given string. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### net_version + +Returns the current network id. + +**Parameters** + +None + +**Returns** + +`String` - The current network id. + +The full list of current network IDs is available at [chainlist.org](https://chainlist.org). Some common ones are: + +- `1`: Ethereum Mainnet +- `11155111`: Sepolia testnet +- `560048` : Hoodi Testnet + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### net_listening + +Returns `true` if client is actively listening for network connections. + +**Parameters** + +None + +**Returns** + +`Boolean` - `true` when listening, otherwise `false`. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### net_peerCount + +Returns number of peers currently connected to the client. + +**Parameters** + +None + +**Returns** + +`QUANTITY` - integer of the number of connected peers. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_protocolVersion + +Returns the current Ethereum protocol version. Note that this method is [not available in Geth](https://github.com/ethereum/go-ethereum/pull/22064#issuecomment-788682924). + +**Parameters** + +None + +**Returns** + +`String` - The current Ethereum protocol version + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_syncing + +Returns an object with data about the sync status or `false`. + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +The precise return data varies between client implementations. All clients return `False` when the node is not syncing, and all clients return the following fields. + +`Object|Boolean`, An object with sync status data or `FALSE`, when not syncing: + +- `startingBlock`: `QUANTITY` - The block at which the import started (will only be reset, after the sync reached his head) +- `currentBlock`: `QUANTITY` - The current block, same as eth_blockNumber +- `highestBlock`: `QUANTITY` - The estimated highest block + +However, the individual clients may also provide additional data. For example Geth returns the following: + +```json + +} +``` + +Whereas Besu returns: + +```json + +} +``` + +Refer to the documentation for your specific client for more details. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +} +// Or when not syncing + +``` + +### eth_coinbase + +Returns the client coinbase address. + + + Try endpoint in playground + + +> **Note:** This method has been deprecated as of **v1.14.0** and is no longer supported. Attempting to use this method will result in a "Method not supported" error. + +**Parameters** + +None + +**Returns** + +`DATA`, 20 bytes - the current coinbase address. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_chainId + +Returns the chain ID used for signing replay-protected transactions. + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`chainId`, hexadecimal value as a string representing the integer of the current chain id. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_mining + +Returns `true` if client is actively mining new blocks. This can only return `true` for proof-of-work networks and may not be available in some clients since [The Merge](/roadmap/merge/). + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`Boolean` - returns `true` if the client is mining, otherwise `false`. + +**Example** + +```js +// Request +curl -X POST --data '' +// + +``` + +### eth_hashrate + +Returns the number of hashes per second that the node is mining with. This can only return `true` for proof-of-work networks and may not be available in some clients since [The Merge](/roadmap/merge/). + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`QUANTITY` - number of hashes per second. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_gasPrice + +Returns an estimate of the current price per gas in wei. For example, the Besu client examines the last 100 blocks and returns the median gas unit price by default. + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`QUANTITY` - integer of the current gas price in wei. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_accounts + +Returns a list of addresses owned by client. + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`Array of DATA`, 20 Bytes - addresses owned by the client. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_blockNumber + +Returns the number of most recent block. + + + Try endpoint in playground + + +**Parameters** + +None + +**Returns** + +`QUANTITY` - integer of the current block number the client is on. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getBalance + +Returns the balance of the account of given address. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 20 Bytes - address to check for balance. +2. `QUANTITY|TAG` - integer block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"`, or `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +```js +params: ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"] +``` + +**Returns** + +`QUANTITY` - integer of the current balance in wei. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getStorageAt + +Returns the value from a storage position at a given address. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 20 Bytes - address of the storage. +2. `QUANTITY` - integer of the position in the storage. +3. `QUANTITY|TAG` - integer block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"`, `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +**Returns** + +`DATA` - the value at this storage position. + +**Example** +Calculating the correct position depends on the storage to retrieve. Consider the following contract deployed at `0x295a70b2de5e3953354a6a8344e616ed314d7251` by address `0x391694e7e0b0cce554cb130d723a9d27458f9298`. + +``` +contract Storage +} +``` + +Retrieving the value of pos0 is straight forward: + +```js +curl -X POST --data '' localhost:8545 + +``` + +Retrieving an element of the map is harder. The position of an element in the map is calculated with: + +```js +keccak(LeftPad32(key, 0), LeftPad32(map position, 0)) +``` + +This means to retrieve the storage on pos1["0x391694e7e0b0cce554cb130d723a9d27458f9298"] we need to calculate the position with: + +```js +keccak( + decodeHex( + "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + + "0000000000000000000000000000000000000000000000000000000000000001" + ) +) +``` + +The geth console which comes with the web3 library can be used to make the calculation: + +```js +> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001" +undefined +> web3.sha3(key, ) +"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9" +``` + +Now to fetch the storage: + +```js +curl -X POST --data '' localhost:8545 + +``` + +### eth_getTransactionCount + +Returns the number of transactions _sent_ from an address. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 20 Bytes - address. +2. `QUANTITY|TAG` - integer block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"` or `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +```js +params: [ + "0x407d73d8a49eeb85d32cf465507dd71d507100c1", + "latest", // state at the latest block +] +``` + +**Returns** + +`QUANTITY` - integer of the number of transactions send from this address. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getBlockTransactionCountByHash + +Returns the number of transactions in a block from a block matching the given block hash. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - hash of a block + +```js +params: ["0xd03ededb7415d22ae8bac30f96b2d1de83119632693b963642318d87d1bece5b"] +``` + +**Returns** + +`QUANTITY` - integer of the number of transactions in this block. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getBlockTransactionCountByNumber + +Returns the number of transactions in a block matching the given block number. + + + Try endpoint in playground + + +**Parameters** + +1. `QUANTITY|TAG` - integer of a block number, or the string `"earliest"`, `"latest"`, `"pending"`, `"safe"` or `"finalized"`, as in the [block parameter](/developers/docs/apis/json-rpc/#block-parameter). + +```js +params: [ + "0x13738ca", // 20396234 +] +``` + +**Returns** + +`QUANTITY` - integer of the number of transactions in this block. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getUncleCountByBlockHash + +Returns the number of uncles in a block from a block matching the given block hash. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - hash of a block + +```js +params: ["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2"] +``` + +**Returns** + +`QUANTITY` - integer of the number of uncles in this block. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getUncleCountByBlockNumber + +Returns the number of uncles in a block from a block matching the given block number. + + + Try endpoint in playground + + +**Parameters** + +1. `QUANTITY|TAG` - integer of a block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"` or `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +```js +params: [ + "0xe8", // 232 +] +``` + +**Returns** + +`QUANTITY` - integer of the number of uncles in this block. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getCode + +Returns code at a given address. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 20 Bytes - address +2. `QUANTITY|TAG` - integer block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"` or `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +```js +params: [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0x5daf3b", // 6139707 +] +``` + +**Returns** + +`DATA` - the code from the given address. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_sign + +The sign method calculates an Ethereum specific signature with: `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`. + +By adding a prefix to the message makes the calculated signature recognizable as an Ethereum specific signature. This prevents misuse where a malicious dapp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. + +Note: the address to sign with must be unlocked. + +**Parameters** + +1. `DATA`, 20 Bytes - address +2. `DATA`, N Bytes - message to sign + +**Returns** + +`DATA`: Signature + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_signTransaction + +Signs a transaction that can be submitted to the network at a later time using with [eth_sendRawTransaction](#eth_sendrawtransaction). + +**Parameters** + +1. `Object` - The transaction object + +- `type`: +- `from`: `DATA`, 20 Bytes - The address the transaction is sent from. +- `to`: `DATA`, 20 Bytes - (optional when creating new contract) The address the transaction is directed to. +- `gas`: `QUANTITY` - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. +- `gasPrice`: `QUANTITY` - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas, in Wei. +- `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction, in Wei. +- `data`: `DATA` - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. +- `nonce`: `QUANTITY` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + +**Returns** + +`DATA`, The RLP-encoded transaction object signed by the specified account. + +**Example** + +```js +// Request +curl -X POST --data ']}' +// Result + +``` + +### eth_sendTransaction + +Creates new message call transaction or a contract creation, if the data field contains code, and signs it using the account specified in `from`. + +**Parameters** + +1. `Object` - The transaction object + +- `from`: `DATA`, 20 Bytes - The address the transaction is sent from. +- `to`: `DATA`, 20 Bytes - (optional when creating new contract) The address the transaction is directed to. +- `gas`: `QUANTITY` - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. +- `gasPrice`: `QUANTITY` - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas. +- `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction. +- `input`: `DATA` - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. +- `nonce`: `QUANTITY` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + +```js +params: [ + , +] +``` + +**Returns** + +`DATA`, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available. + +Use [eth_getTransactionReceipt](#eth_gettransactionreceipt) to get the contract address, after the transaction was proposed in a block, when you created a contract. + +**Example** + +```js +// Request +curl -X POST --data '],"id":1}' +// Result + +``` + +### eth_sendRawTransaction + +Creates new message call transaction or a contract creation for signed transactions. + +**Parameters** + +1. `DATA`, The signed transaction data. + +```js +params: [ + "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", +] +``` + +**Returns** + +`DATA`, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available. + +Use [eth_getTransactionReceipt](#eth_gettransactionreceipt) to get the contract address, after the transaction was proposed in a block, when you created a contract. + +**Example** + +```js +// Request +curl -X POST --data '],"id":1}' +// Result + +``` + +### eth_call + +Executes a new message call immediately without creating a transaction on the blockchain. Often used for executing read-only smart contract functions, for example the `balanceOf` for an ERC-20 contract. + + + Try endpoint in playground + + +**Parameters** + +1. `Object` - The transaction call object + +- `from`: `DATA`, 20 Bytes - (optional) The address the transaction is sent from. +- `to`: `DATA`, 20 Bytes - The address the transaction is directed to. +- `gas`: `QUANTITY` - (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions. +- `gasPrice`: `QUANTITY` - (optional) Integer of the gasPrice used for each paid gas +- `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction +- `input`: `DATA` - (optional) Hash of the method signature and encoded parameters. For details see [Ethereum Contract ABI in the Solidity documentation](https://docs.soliditylang.org/en/latest/abi-spec.html). + +2. `QUANTITY|TAG` - integer block number, or the string `"latest"`, `"earliest"`, `"pending"`, `"safe"` or `"finalized"`, see the [block parameter](/developers/docs/apis/json-rpc/#block-parameter) + +**Returns** + +`DATA` - the return value of executed contract. + +**Example** + +```js +// Request +curl -X POST --data '],"id":1}' +// Result + +``` + +### eth_estimateGas + +Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance. + + + Try endpoint in playground + + +**Parameters** + +See [eth_call](#eth_call) parameters, except that all properties are optional. If no gas limit is specified geth uses the block gas limit from the pending block as an upper bound. As a result the returned estimate might not be enough to executed the call/transaction when the amount of gas is higher than the pending block gas limit. + +**Returns** + +`QUANTITY` - the amount of gas used. + +**Example** + +```js +// Request +curl -X POST --data '],"id":1}' +// Result + +``` + +### eth_getBlockByHash + +Returns information about a block by hash. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - Hash of a block. +2. `Boolean` - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions. + +```js +params: [ + "0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae", + false, +] +``` + +**Returns** + +`Object` - A block object, or `null` when no block was found: + +- `number`: `QUANTITY` - the block number. `null` when its pending block. +- `hash`: `DATA`, 32 Bytes - hash of the block. `null` when its pending block. +- `parentHash`: `DATA`, 32 Bytes - hash of the parent block. +- `nonce`: `DATA`, 8 Bytes - hash of the generated proof-of-work. `null` when its pending block, `0x0` for proof-of-stake blocks (since The Merge) +- `sha3Uncles`: `DATA`, 32 Bytes - SHA3 of the uncles data in the block. +- `logsBloom`: `DATA`, 256 Bytes - the bloom filter for the logs of the block. `null` when its pending block. +- `transactionsRoot`: `DATA`, 32 Bytes - the root of the transaction trie of the block. +- `stateRoot`: `DATA`, 32 Bytes - the root of the final state trie of the block. +- `receiptsRoot`: `DATA`, 32 Bytes - the root of the receipts trie of the block. +- `miner`: `DATA`, 20 Bytes - the address of the beneficiary to whom the block rewards were given. +- `difficulty`: `QUANTITY` - integer of the difficulty for this block. +- `totalDifficulty`: `QUANTITY` - integer of the total difficulty of the chain until this block. +- `extraData`: `DATA` - the "extra data" field of this block. +- `size`: `QUANTITY` - integer the size of this block in bytes. +- `gasLimit`: `QUANTITY` - the maximum gas allowed in this block. +- `gasUsed`: `QUANTITY` - the total used gas by all transactions in this block. +- `timestamp`: `QUANTITY` - the unix timestamp for when the block was collated. +- `transactions`: `Array` - Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. +- `uncles`: `Array` - Array of uncle hashes. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +} +``` + +### eth_getBlockByNumber + +Returns information about a block by block number. + + + Try endpoint in playground + + +**Parameters** + +1. `QUANTITY|TAG` - integer of a block number, or the string `"earliest"`, `"latest"`, `"pending"`, `"safe"` or `"finalized"`, as in the [block parameter](/developers/docs/apis/json-rpc/#block-parameter). +2. `Boolean` - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions. + +```js +params: [ + "0x1b4", // 436 + true, +] +``` + +**Returns** +See [eth_getBlockByHash](#eth_getblockbyhash) + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getBlockByHash](#eth_getblockbyhash) + +### eth_getTransactionByHash + +Returns the information about a transaction requested by transaction hash. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - hash of a transaction + +```js +params: ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] +``` + +**Returns** + +`Object` - A transaction object, or `null` when no transaction was found: + +- `blockHash`: `DATA`, 32 Bytes - hash of the block where this transaction was in. `null` when its pending. +- `blockNumber`: `QUANTITY` - block number where this transaction was in. `null` when its pending. +- `from`: `DATA`, 20 Bytes - address of the sender. +- `gas`: `QUANTITY` - gas provided by the sender. +- `gasPrice`: `QUANTITY` - gas price provided by the sender in Wei. +- `hash`: `DATA`, 32 Bytes - hash of the transaction. +- `input`: `DATA` - the data send along with the transaction. +- `nonce`: `QUANTITY` - the number of transactions made by the sender prior to this one. +- `to`: `DATA`, 20 Bytes - address of the receiver. `null` when its a contract creation transaction. +- `transactionIndex`: `QUANTITY` - integer of the transactions index position in the block. `null` when its pending. +- `value`: `QUANTITY` - value transferred in Wei. +- `v`: `QUANTITY` - ECDSA recovery id +- `r`: `QUANTITY` - ECDSA signature r +- `s`: `QUANTITY` - ECDSA signature s + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +} +``` + +### eth_getTransactionByBlockHashAndIndex + +Returns information about a transaction by block hash and transaction index position. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - hash of a block. +2. `QUANTITY` - integer of the transaction index position. + +```js +params: [ + "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "0x0", // 0 +] +``` + +**Returns** +See [eth_getTransactionByHash](#eth_gettransactionbyhash) + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getTransactionByHash](#eth_gettransactionbyhash) + +### eth_getTransactionByBlockNumberAndIndex + +Returns information about a transaction by block number and transaction index position. + + + Try endpoint in playground + + +**Parameters** + +1. `QUANTITY|TAG` - a block number, or the string `"earliest"`, `"latest"`, `"pending"`, `"safe"` or `"finalized"`, as in the [block parameter](/developers/docs/apis/json-rpc/#block-parameter). +2. `QUANTITY` - the transaction index position. + +```js +params: [ + "0x9c47cf", // 10241999 + "0x24", // 36 +] +``` + +**Returns** +See [eth_getTransactionByHash](#eth_gettransactionbyhash) + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getTransactionByHash](#eth_gettransactionbyhash) + +### eth_getTransactionReceipt + +Returns the receipt of a transaction by transaction hash. + +**Note** That the receipt is not available for pending transactions. + +**Parameters** + +1. `DATA`, 32 Bytes - hash of a transaction + +```js +params: ["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"] +``` + +**Returns** +`Object` - A transaction receipt object, or `null` when no receipt was found: + +- `transactionHash `: `DATA`, 32 Bytes - hash of the transaction. +- `transactionIndex`: `QUANTITY` - integer of the transactions index position in the block. +- `blockHash`: `DATA`, 32 Bytes - hash of the block where this transaction was in. +- `blockNumber`: `QUANTITY` - block number where this transaction was in. +- `from`: `DATA`, 20 Bytes - address of the sender. +- `to`: `DATA`, 20 Bytes - address of the receiver. null when its a contract creation transaction. +- `cumulativeGasUsed` : `QUANTITY ` - The total amount of gas used when this transaction was executed in the block. +- `effectiveGasPrice` : `QUANTITY` - The sum of the base fee and tip paid per unit of gas. +- `gasUsed `: `QUANTITY ` - The amount of gas used by this specific transaction alone. +- `contractAddress `: `DATA`, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise `null`. +- `logs`: `Array` - Array of log objects, which this transaction generated. +- `logsBloom`: `DATA`, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs. +- `type`: `QUANTITY` - integer of the transaction type, `0x0` for legacy transactions, `0x1` for access list types, `0x2` for dynamic fees. + +It also returns _either_ : + +- `root` : `DATA` 32 bytes of post-transaction stateroot (pre Byzantium) +- `status`: `QUANTITY` either `1` (success) or `0` (failure) + +**Example** + +```js +// Request +curl -X POST --data '' +// Result +], + "logsBloom": "0x00...0", // 256 byte bloom filter + "status": "0x1", + "to": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "transactionHash": + "0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5", + "transactionIndex": "0x66", + "type": "0x2" + } +} +``` + +### eth_getUncleByBlockHashAndIndex + +Returns information about a uncle of a block by hash and uncle index position. + + + Try endpoint in playground + + +**Parameters** + +1. `DATA`, 32 Bytes - The hash of a block. +2. `QUANTITY` - The uncle's index position. + +```js +params: [ + "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "0x0", // 0 +] +``` + +**Returns** +See [eth_getBlockByHash](#eth_getblockbyhash) + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getBlockByHash](#eth_getblockbyhash) + +**Note**: An uncle doesn't contain individual transactions. + +### eth_getUncleByBlockNumberAndIndex + +Returns information about a uncle of a block by number and uncle index position. + + + Try endpoint in playground + + +**Parameters** + +1. `QUANTITY|TAG` - a block number, or the string `"earliest"`, `"latest"`, `"pending"`, `"safe"`, `"finalized"`, as in the [block parameter](/developers/docs/apis/json-rpc/#block-parameter). +2. `QUANTITY` - the uncle's index position. + +```js +params: [ + "0x29c", // 668 + "0x0", // 0 +] +``` + +**Returns** +See [eth_getBlockByHash](#eth_getblockbyhash) + +**Note**: An uncle doesn't contain individual transactions. + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getBlockByHash](#eth_getblockbyhash) + +### eth_newFilter + +Creates a filter object, based on filter options, to notify when the state changes (logs). +To check if the state has changed, call [eth_getFilterChanges](#eth_getfilterchanges). + +**A note on specifying topic filters:** +Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters: + +- `[]` "anything" +- `[A]` "A in first position (and anything after)" +- `[null, B]` "anything in first position AND B in second position (and anything after)" +- `[A, B]` "A in first position AND B in second position (and anything after)" +- `[[A, B], [A, B]]` "(A OR B) in first position AND (A OR B) in second position (and anything after)" +- **Parameters** + +1. `Object` - The filter options: + +- `fromBlock`: `QUANTITY|TAG` - (optional, default: `"latest"`) Integer block number, or `"latest"` for the last proposed block, `"safe"` for the latest safe block, `"finalized"` for the latest finalized block, or `"pending"`, `"earliest"` for transactions not yet in a block. +- `toBlock`: `QUANTITY|TAG` - (optional, default: `"latest"`) Integer block number, or `"latest"` for the last proposed block, `"safe"` for the latest safe block, `"finalized"` for the latest finalized block, or `"pending"`, `"earliest"` for transactions not yet in a block. +- `address`: `DATA|Array`, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate. +- `topics`: `Array of DATA`, - (optional) Array of 32 Bytes `DATA` topics. Topics are order-dependent. Each topic can also be an array of DATA with "or" options. + +```js +params: [ + , +] +``` + +**Returns** +`QUANTITY` - A filter id. + +**Example** + +```js +// Request +curl -X POST --data '],"id":73}' +// Result + +``` + +### eth_newBlockFilter + +Creates a filter in the node, to notify when a new block arrives. +To check if the state has changed, call [eth_getFilterChanges](#eth_getfilterchanges). + +**Parameters** +None + +**Returns** +`QUANTITY` - A filter id. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_newPendingTransactionFilter + +Creates a filter in the node, to notify when new pending transactions arrive. +To check if the state has changed, call [eth_getFilterChanges](#eth_getfilterchanges). + +**Parameters** +None + +**Returns** +`QUANTITY` - A filter id. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_uninstallFilter + +Uninstalls a filter with given id. Should always be called when watch is no longer needed. +Additionally Filters timeout when they aren't requested with [eth_getFilterChanges](#eth_getfilterchanges) for a period of time. + +**Parameters** + +1. `QUANTITY` - The filter id. + +```js +params: [ + "0xb", // 11 +] +``` + +**Returns** +`Boolean` - `true` if the filter was successfully uninstalled, otherwise `false`. + +**Example** + +```js +// Request +curl -X POST --data '' +// Result + +``` + +### eth_getFilterChanges + +Polling method for a filter, which returns an array of logs which occurred since last poll. + +**Parameters** + +1. `QUANTITY` - the filter id. + +```js +params: [ + "0x16", // 22 +] +``` + +**Returns** +`Array` - Array of log objects, or an empty array if nothing has changed since last poll. + +- For filters created with `eth_newBlockFilter` the return are block hashes (`DATA`, 32 Bytes), e.g. `["0x3454645634534..."]`. +- For filters created with `eth_newPendingTransactionFilter ` the return are transaction hashes (`DATA`, 32 Bytes), e.g. `["0x6345343454645..."]`. +- For filters created with `eth_newFilter` logs are objects with following params: + - `removed`: `TAG` - `true` when the log was removed, due to a chain reorganization. `false` if its a valid log. + - `logIndex`: `QUANTITY` - integer of the log index position in the block. `null` when its pending log. + - `transactionIndex`: `QUANTITY` - integer of the transactions index position log was created from. `null` when its pending log. + - `transactionHash`: `DATA`, 32 Bytes - hash of the transactions this log was created from. `null` when its pending log. + - `blockHash`: `DATA`, 32 Bytes - hash of the block where this log was in. `null` when its pending. `null` when its pending log. + - `blockNumber`: `QUANTITY` - the block number where this log was in. `null` when its pending. `null` when its pending log. + - `address`: `DATA`, 20 Bytes - address from which this log originated. + - `data`: `DATA` - contains zero or more 32 Bytes non-indexed arguments of the log. + - `topics`: `Array of DATA` - Array of 0 to 4 32 Bytes `DATA` of indexed log arguments. (In _solidity_: The first topic is the _hash_ of the signature of the event (e.g. `Deposit(address,bytes32,uint256)`), except you declared the event with the `anonymous` specifier.) +- **Example** + +```js +// Request +curl -X POST --data '' +// Result +,] +} +``` + +### eth_getFilterLogs + +Returns an array of all logs matching filter with given id. + +**Parameters** + +1. `QUANTITY` - The filter id. + +```js +params: [ + "0x16", // 22 +] +``` + +**Returns** +See [eth_getFilterChanges](#eth_getfilterchanges) + +**Example** + +```js +// Request +curl -X POST --data '' +``` + +Result see [eth_getFilterChanges](#eth_getfilterchanges) + +### eth_getLogs + +Returns an array of all logs matching a given filter object. + +**Parameters** + +1. `Object` - The filter options: + +- `fromBlock`: `QUANTITY|TAG` - (optional, default: `"latest"`) Integer block number, or `"latest"` for the last proposed block, `"safe"` for the latest safe block, `"finalized"` for the latest finalized block, or `"pending"`, `"earliest"` for transactions not yet in a block. +- `toBlock`: `QUANTITY|TAG` - (optional, default: `"latest"`) Integer block number, or `"latest"` for the last proposed block, `"safe"` for the latest safe block, `"finalized"` for the latest finalized block, or `"pending"`, `"earliest"` for transactions not yet in a block. +- `address`: `DATA|Array`, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate. +- `topics`: `Array of DATA`, - (optional) Array of 32 Bytes `DATA` topics. Topics are order-dependent. Each topic can also be an array of DATA with "or" options. +- `blockHash`: `DATA`, 32 Bytes - (optional, **future**) With the addition of EIP-234, `blockHash` will be a new filter option which restricts the logs returned to the single block with the 32-byte hash `blockHash`. Using `blockHash` is equivalent to `fromBlock` = `toBlock` = the block number with hash `blockHash`. If `blockHash` is present in the filter criteria, then neither `fromBlock` nor `toBlock` are allowed. + +```js +params: [ + , +] +``` + +**Returns** +See [eth_getFilterChanges](#eth_getfilterchanges) + +**Example** + +```js +// Request +curl -X POST --data '],"id":74}' +``` + +Result see [eth_getFilterChanges](#eth_getfilterchanges) + +## Usage Example + +### Deploying a contract using JSON_RPC + +This section includes a demonstration of how to deploy a contract using only the RPC interface. There are alternative routes to deploying contracts where this complexity is abstracted away—for example, using libraries built on top of the RPC interface such as [web3.js](https://web3js.readthedocs.io/) and [web3.py](https://github.com/ethereum/web3.py). These abstractions are generally easier to understand and less error-prone, but it is still helpful to understand what is happening under the hood. + +The following is a straightforward smart contract called `Multiply7` that will be deployed using the JSON-RPC interface to an Ethereum node. This tutorial assumes the reader is already running a Geth node. More information on nodes and clients is available [here](/developers/docs/nodes-and-clients/run-a-node). Please refer to individual [client](/developers/docs/nodes-and-clients/) documentation to see how to start the HTTP JSON-RPC for non-Geth clients. Most clients default to serving on `localhost:8545`. + +```javascript +contract Multiply7 +} +``` + +The first thing to do is make sure the HTTP RPC interface is enabled. This means we supply Geth with the `--http` flag on startup. In this example we use the Geth node on a private development chain. Using this approach we don't need ether on the real network. + +```bash +geth --http --dev console 2>>geth.log +``` + +This will start the HTTP RPC interface on `http://localhost:8545`. + +We can verify that the interface is running by retrieving the coinbase address (by obtaining the first address from the array of accounts) and balance using [curl](https://curl.se). Please note that data in these examples will differ on your local node. If you want to try these commands, replace the request params in the second curl request with the result returned from the first. + +```bash +curl --data '' -H "Content-Type: application/json" localhost:8545 + + +curl --data '' -H "Content-Type: application/json" localhost:8545 + +``` + +Because numbers are hex encoded, the balance is returned in wei as a hex string. If we want to have the balance in ether as a number we can use web3 from the Geth console. + +```javascript +web3.fromWei("0x1639e49bba16280000", "ether") +// "410" +``` + +Now that there is some ether on our private development chain, we can deploy the contract. The first step is to compile the Multiply7 contract to byte code that can be sent to the EVM. To install solc, the Solidity compiler, follow the [Solidity documentation](https://docs.soliditylang.org/en/latest/installing-solidity.html). (You might want to use an older `solc` release to match [the version of compiler used for our example](https://github.com/ethereum/solidity/releases/tag/v0.4.20).) + +The next step is to compile the Multiply7 contract to byte code that can be send to the EVM. + +```bash +echo 'pragma solidity ^0.4.16; contract Multiply7 }' | solc --bin + +======= :Multiply7 ======= +Binary: +6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029 +``` + +Now that we have the compiled code we need to determine how much gas it costs to deploy it. The RPC interface has an `eth_estimateGas` method that will give us an estimate. + +```bash +curl --data '], "id": 5}' -H "Content-Type: application/json" localhost:8545 + +``` + +And finally deploy the contract. + +```bash +curl --data '], "id": 6}' -H "Content-Type: application/json" localhost:8545 + +``` + +The transaction is accepted by the node and a transaction hash is returned. This hash can be used to track the transaction. The next step is to determine the address where our contract is deployed. Each executed transaction will create a receipt. This receipt contains various information about the transaction such as in which block the transaction was included and how much gas was used by the EVM. If a transaction +creates a contract it will also contain the contract address. We can retrieve the receipt with the `eth_getTransactionReceipt` RPC method. + +```bash +curl --data '' -H "Content-Type: application/json" localhost:8545 +} +``` + +Our contract was created on `0x4d03d617d700cf81935d7f797f4e2ae719648262`. A null result instead of a receipt means the transaction has not been included in a block yet. Wait for a moment and check if your consensus client is running and retry it. + +#### Interacting with smart contracts + +In this example we will be sending a transaction using `eth_sendTransaction` to the `multiply` method of the contract. + +`eth_sendTransaction` requires several arguments, specifically `from`, `to` and `data`. `From` is the public address of our account, and `to` is the contract address. The `data` argument contains a payload that defines which method must be called and with which arguments. This is where the [ABI (application binary interface)](https://docs.soliditylang.org/en/latest/abi-spec.html) comes into play. The ABI is a JSON file that defines how to define and encode data for the EVM. + +The bytes of the payload defines which method in the contract is called. This is the first 4 bytes from the Keccak hash over the function name and its argument types, hex encoded. The multiply function accepts an uint which is an alias for uint256. This leaves us with: + +```javascript +web3.sha3("multiply(uint256)").substring(0, 10) +// "0xc6888fa1" +``` + +The next step is to encode the arguments. There is only one uint256, say, the value 6. The ABI has a section which specifies how to encode uint256 types. + +`int: enc(X)` is the big-endian two’s complement encoding of X, padded on the higher-order (left) side with 0xff for negative X and with zero > bytes for positive X such that the length is a multiple of 32 bytes. + +This encodes to `0000000000000000000000000000000000000000000000000000000000000006`. + +Combining the function selector and the encoded argument our data will be `0xc6888fa10000000000000000000000000000000000000000000000000000000000000006`. + +This can now be sent to the node: + +```bash +curl --data '], "id": 8}' -H "Content-Type: application/json" localhost:8545 + +``` + +Since a transaction was sent, a transaction hash was returned. Retrieving the receipt gives: + +```javascript +], + transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74", + transactionIndex: 0 +} +``` + +The receipt contains a log. This log was generated by the EVM on transaction execution and included in the receipt. The `multiply` function shows that the `Print` event was raised with the input times 7. Since the argument for the `Print` event was a uint256 we can decode it according to the ABI rules which will leave us with the expected decimal 42. Apart from the data it is worth noting that topics can be used to determine which event created the log: + +```javascript +web3.sha3("Print(uint256)") +// "24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da" +``` + +This was just a brief introduction into some of the most common tasks, demonstrating direct usage of the JSON-RPC. + +## Related topics + +- [JSON-RPC specification](http://www.jsonrpc.org/specification) +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [JavaScript APIs](/developers/docs/apis/javascript/) +- [Backend APIs](/developers/docs/apis/backend/) +- [Execution clients](/developers/docs/nodes-and-clients/#execution-clients) + +--- + +## Developers > Docs > Blocks + +Blocks are batches of transactions with a hash of the previous block in the chain. This links blocks together (in a chain) because hashes are cryptographically derived from the block data. This prevents fraud, because one change in any block in history would invalidate all the following blocks as all subsequent hashes would change and everyone running the blockchain would notice. + +## Prerequisites + +Blocks are a very beginner-friendly topic. But to help you better understand this page, we recommend you first read [Accounts](/developers/docs/accounts/), [Transactions](/developers/docs/transactions/), and our [introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +## Why blocks? + +To ensure that all participants on the Ethereum network maintain a synchronized state and agree on the precise history of transactions, we batch transactions into blocks. This means dozens (or hundreds) of transactions are committed, agreed on, and synchronized all at once. + +![A diagram showing transaction in a block causing state changes](./tx-block.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +By spacing out commits, we give all network participants enough time to come to consensus: even though transaction requests occur dozens of times per second, blocks are only created and committed on Ethereum once every twelve seconds. + +## How blocks work + +To preserve the transaction history, blocks are strictly ordered (every new block created contains a reference to its parent block), and transactions within blocks are strictly ordered as well. Except in rare cases, at any given time, all participants on the network are in agreement on the exact number and history of blocks, and are working to batch the current live transaction requests into the next block. + +Once a block is put together by a randomly selected validator on the network, it is propagated to the rest of the network; all nodes add this block to the end of their blockchain, and a new validator is selected to create the next block. The exact block-assembly process and commitment/consensus process is currently specified by Ethereum’s “proof-of-stake” protocol. + +## Proof-of-stake protocol + +Proof-of-stake means the following: + +- Validating nodes have to stake 32 ETH into a deposit contract as collateral against bad behavior. This helps protect the network because provably dishonest activity leads to some or all of that stake being destroyed. +- In every slot (spaced twelve seconds apart) a validator is randomly selected to be the block proposer. They bundle transactions together, execute them and determine a new 'state'. They wrap this information into a block and pass it around to other validators. +- Other validators who hear about the new block re-execute the transactions to ensure they agree with the proposed change to the global state. Assuming the block is valid, they add it to their own database. +- If a validator hears about two conflicting blocks for the same slot they use their fork-choice algorithm to pick the one supported by the most staked ETH. + +[More on proof-of-stake](/developers/docs/consensus-mechanisms/pos) + +## What's in a block? + +There is a lot of information contained within a block. At the highest level a block contains the following fields: + +| Field | Description | +| :--------------- | :---------------------------------------------------- | +| `slot` | the slot the block belongs to | +| `proposer_index` | the ID of the validator proposing the block | +| `parent_root` | the hash of the preceding block | +| `state_root` | the root hash of the state object | +| `body` | an object containing several fields, as defined below | + +The block `body` contains several fields of its own: + +| Field | Description | +| :------------------- | :------------------------------------------------- | +| `randao_reveal` | a value used to select the next block proposer | +| `eth1_data` | information about the deposit contract | +| `graffiti` | arbitrary data used to tag blocks | +| `proposer_slashings` | list of validators to be slashed | +| `attester_slashings` | list of attesters to be slashed | +| `attestations` | list of attestations in favor of the current block | +| `deposits` | list of new deposits to the deposit contract | +| `voluntary_exits` | list of validators exiting the network | +| `sync_aggregate` | subset of validators used to serve light clients | +| `execution_payload` | transactions passed from the execution client | + +The `attestations` field contains a list of all the attestations in the block. Attestations have their own data type that contains several pieces of data. Each attestation contains: + +| Field | Description | +| :----------------- | :---------------------------------------------------------- | +| `aggregation_bits` | a list of which validators participated in this attestation | +| `data` | a container with multiple subfields | +| `signature` | aggregate signature of all attesting validators | + +The `data` field in the `attestation` contains the following: + +| Field | Description | +| :------------------ | :------------------------------------------------------- | +| `slot` | the slot the attestation relates to | +| `index` | indices for attesting validators | +| `beacon_block_root` | the root hash of the Beacon block containing this object | +| `source` | the last justified checkpoint | +| `target` | the latest epoch boundary block | + +Executing the transactions in the `execution_payload` updates the global state. All clients re-execute the transactions in the `execution_payload` to ensure the new state matches that in the new block `state_root` field. This is how clients can tell that a new block is valid and safe to add to their blockchain. The `execution payload` itself is an object with several fields. There is also an `execution_payload_header` that contains important summary information about the execution data. These data structures are organized as follows: + +The `execution_payload_header` contains the following fields: + +| Field | Description | +| :------------------ | :------------------------------------------------------------------ | +| `parent_hash` | hash of the parent block | +| `fee_recipient` | account address for paying transaction fees to | +| `state_root` | root hash for the global state after applying changes in this block | +| `receipts_root` | hash of the transaction receipts trie | +| `logs_bloom` | data structure containing event logs | +| `prev_randao` | value used in random validator selection | +| `block_number` | the number of the current block | +| `gas_limit` | maximum gas allowed in this block | +| `gas_used` | the actual amount of gas used in this block | +| `timestamp` | the block time | +| `extra_data` | arbitrary additional data as raw bytes | +| `base_fee_per_gas` | the base fee value | +| `block_hash` | Hash of execution block | +| `transactions_root` | root hash of the transactions in the payload | +| `withdrawal_root` | root hash of the withdrawals in the payload | + +The `execution_payload` itself contains the following (notice this is identical to the header except that instead of the root hash of the transactions it includes the actual list of transactions and withdrawal information) : + +| Field | Description | +| :----------------- | :------------------------------------------------------------------ | +| `parent_hash` | hash of the parent block | +| `fee_recipient` | account address for paying transaction fees to | +| `state_root` | root hash for the global state after applying changes in this block | +| `receipts_root` | hash of the transaction receipts trie | +| `logs_bloom` | data structure containing event logs | +| `prev_randao` | value used in random validator selection | +| `block_number` | the number of the current block | +| `gas_limit` | maximum gas allowed in this block | +| `gas_used` | the actual amount of gas used in this block | +| `timestamp` | the block time | +| `extra_data` | arbitrary additional data as raw bytes | +| `base_fee_per_gas` | the base fee value | +| `block_hash` | Hash of execution block | +| `transactions` | list of transactions to be executed | +| `withdrawals` | list of withdrawal objects | + +The `withdrawals` list contains `withdrawal` objects structured in the following way: + +| Field | Description | +| :--------------- | :--------------------------------- | +| `address` | account address that has withdrawn | +| `amount` | withdrawal amount | +| `index` | withdrawal index value | +| `validatorIndex` | validator index value | + +## Block time + +Block time refers to the time separating blocks. In Ethereum, time is divided up into twelve second units called 'slots'. In each slot a single validator is selected to propose a block. Assuming all validators are online and fully functional there will be a block in every slot, meaning the block time is 12s. However, occasionally validators might be offline when called to propose a block, meaning slots can sometimes go empty. + +This implementation differs from proof-of-work based systems where block times are probabilistic and tuned by the protocol's target mining difficulty. Ethereum's [average block time](https://etherscan.io/chart/blocktime) is a perfect example of this whereby the transition from proof-of-work to proof-of-stake can be clearly inferred based on the consistency of the new 12s block time. + +## Block size + +A final important note is that blocks themselves are bounded in size. Each block has a target size of 15 million gas but the size of blocks will increase or decrease in accordance with network demands, up until the block limit of 30 million gas (2x target block size). The block gas limit can be adjusted upwards or downwards by a factor of 1/1024 from the previous block's gas limit. As a result, validators can change the block gas limit through consensus. The total amount of gas expended by all transactions in the block must be less than the block gas limit. This is important because it ensures that blocks can’t be arbitrarily large. If blocks could be arbitrarily large, then less performant full nodes would gradually stop being able to keep up with the network due to space and speed requirements. The larger the block, the greater the computing power required to process them in time for the next slot. This is a centralizing force, which is resisted by capping block sizes. + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Transactions](/developers/docs/transactions/) +- [Gas](/developers/docs/gas/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos) + +--- + +## Developers > Docs > Bridges + +With the proliferation of L1 blockchains and L2 [scaling](/developers/docs/scaling/) solutions, alongside an ever-growing number of decentralized applications going cross-chain, the need for communication and asset movement across chains has become an essential part of network infrastructure. Different types of bridges exist to help make this possible. + +## Need for bridges + +Bridges exist to connect blockchain networks. They enable connectivity and interoperability between blockchains. + +Blockchains exist in siloed environments, meaning there is no way for blockchains to trade and communicate with other blockchains naturally. As a result, while there could be significant activity and innovation within an ecosystem, it is limited by the lack of connectivity and interoperability with other ecosystems. + +Bridges offer a way for isolated blockchain environments to connect with each other. They establish a transportation route between blockchains where tokens, messages, arbitrary data, and even [smart contract](/developers/docs/smart-contracts/) calls can be transferred from one chain to another. + +## Benefits of bridges + +Put simply, bridges unlock numerous use cases by allowing blockchain networks to exchange data and move assets between them. + +Blockchains have unique strengths, weaknesses, and approaches to building applications (such as speed, throughput, costliness, etc.). Bridges help the development of the overall crypto ecosystem by enabling blockchains to leverage the innovations of each other. + +For developers, bridges enable the following: + +- the transfer of any data, information, and assets across chains. +- unlocking new features and use cases for protocols as bridges expand the design space for what protocols can offer. For example, a protocol for yield farming originally deployed on Ethereum Mainnet can offer liquidity pools across all EVM-compatible chains. +- the opportunity to leverage the strengths of different blockchains. For example, developers can benefit from the lower fees offered by the different L2 solutions by deploying their dapps across rollups, and sidechains and users can bridge across them. +- collaboration among developers from various blockchain ecosystems to build new products. +- attracting users and communities from various ecosystems to their dapps. + +## How do bridges work? + +While there are many [types of bridge designs](https://li.fi/knowledge-hub/blockchain-bridges-and-classification/), three ways to facilitate the cross-chain transfer of assets stand out: + +- **Lock and mint –** Lock assets on the source chain and mint assets on the destination chain. +- **Burn and mint –** Burn assets on the source chain and mint assets on the destination chain. +- **Atomic swaps –** Swap assets on the source chain for assets on the destination chain with another party. + +## Bridge types + +Bridges can usually be classified into one of the following buckets: + +- **Native bridges –** These bridges are typically built to bootstrap liquidity on a particular blockchain, making it easier for users to move funds to the ecosystem. For example, the [Arbitrum Bridge](https://bridge.arbitrum.io/) is built to make it convenient for users to bridge from Ethereum Mainnet to Arbitrum. Other such bridges include Polygon PoS Bridge, [Optimism Gateway](https://app.optimism.io/bridge), etc. +- **Validator or oracle based bridges –** These bridges rely on an external validator set or oracles to validate cross-chain transfers. Examples: Multichain and Across. +- **Generalized message passing bridges –** These bridges can transfer assets, along with messages and arbitrary data across chains. Examples: Axelar, LayerZero, and Nomad. +- **Liquidity networks –** These bridges primarily focus on transferring assets from one chain to another via atomic swaps. Generally, they don’t support cross-chain message passing. Examples: Connext and Hop. + +## Trade-offs to consider + +With bridges, there are no perfect solutions. Rather, there are only trade-offs made to fulfill a purpose. Developers and users can evaluate bridges based on the following factors: + +- **Security –** Who verifies the system? Bridges secured by external validators are typically less secure than bridges that are locally or natively secured by the blockchain’s validators. +- **Convenience –** How long does it take to complete a transaction, and how many transactions did a user need to sign? For a developer, how long does it take to integrate a bridge, and how complex is the process? +- **Connectivity –** What are the different destination chains a bridge can connect (i.e., rollups, sidechains, other layer 1 blockchains, etc.), and how hard is it to integrate a new blockchain? +- **Ability to pass more complex data –** Can a bridge enable the transfer of messages and more complex arbitrary data across chains, or does it only support cross-chain asset transfers? +- **Cost-effectiveness –** How much does it cost to transfer assets across chains via a bridge? Typically, bridges charge a fixed or variable fee depending on gas costs and the liquidity of specific routes. It is also critical to evaluate the cost-effectiveness of a bridge based on the capital required to ensure its security. + +At a high level, bridges can be categorized as trusted and trustless. + +- **Trusted –** Trusted bridges are externally verified. They use an external set of verifiers (Federations with multi-sig, multi-party computation systems, oracle network) to send data across chains. As a result, they can offer great connectivity and enable fully generalized message passing across chains. They also tend to perform well with speed and cost-effectiveness. This comes at the cost of security, as users have to rely on the security of the bridge. +- **Trustless –** These bridges rely on the blockchains they are connecting and their validators to transfer messages and tokens. They are 'trustless' because they do not add new trust assumptions (in addition to the blockchains). As a result, trustless bridges are considered to be more secure than trusted bridges. + +To evaluate trustless bridges based on other factors, we must break them down into generalized message passing bridges and liquidity networks. + +- **Generalized message passing bridges –** These bridges excel with security and the ability to transfer more complex data across chains. Typically, they are also good with cost-effectiveness. However, these strengths generally come at the cost of connectivity for light client bridges (ex: IBC) and speed drawbacks for optimistic bridges (ex: Nomad) that use fraud proofs. +- **Liquidity networks –** These bridges use atomic swaps for transferring assets and are locally verified systems (i.e., they use the underlying blockchains’ validators to verify transactions). As a result, they excel with security and speed. Moreover, they are considered comparatively cost-effective and offer good connectivity. However, the major tradeoff is their inability to pass more complex data – as they don’t support cross-chain message passing. + +## Risk with bridges + +Bridges account for the top three [biggest hacks in DeFi](https://rekt.news/leaderboard/) and are still in the early stages of development. Using any bridge carries the following risks: + +- **Smart contract risk –** While many bridges have successfully passed audits, all it takes is one flaw in a smart contract for assets to be exposed to hacks (ex: [Solana’s Wormhole Bridge](https://rekt.news/wormhole-rekt/)). +- **Systemic financial risks** – Many bridges use wrapped assets to mint canonical versions of the original asset on a new chain. This exposes the ecosystem to systemic risk, as we have seen wrapped versions of tokens exploited. +- **Counterparty risk –** Some bridges utilize a trusted design that requires users to rely on the assumption that validators will not collude to steal user funds. The need for users to trust these third-party actors exposes them to risks such as rug pulls, censorship, and other malicious activities. +- **Open issues –** Given that bridges are in the nascent stages of development, there are many unanswered questions related to how bridges will perform in different market conditions, like times of network congestion and during unforeseen events such as network-level attacks or state rollbacks. This uncertainty poses certain risks, the degree of which is still unknown. + +## How can dapps use bridges? + +Here are some practical applications that developers can consider about bridges and taking their dapp cross-chain: + +### Integrating bridges + +For developers, there are many ways to add support for bridges: + +1. **Building your own bridge –** Building a secure and reliable bridge is not easy, especially if you take a more trust-minimized route. Moreover, it requires years of experience and technical expertise related to scalability and interoperability studies. Additionally, it would require a hands-on team to maintain a bridge and attract sufficient liquidity to make it feasible. + +2. **Showing users multiple bridge options –** Many [dapps](/developers/docs/dapps/) require users to have their native token to interact with them. To enable users to access their tokens, they offer different bridge options on their website. However, this method is a quick fix to the problem as it takes the user away from the dapp interface and still requires them to interact with other dapps and bridges. This is a cumbersome onboarding experience with the increased scope of making mistakes. + +3. **Integrating a bridge –** This solution doesn’t require the dapp to send users to the external bridge and DEX interfaces. It allows dapps to improve the user onboarding experience. However, this approach has its limitations: + + - Assessment and maintenance of bridges are hard and time-consuming. + - Selecting one bridge creates a single point of failure and dependency. + - The dapp is limited by the bridge’s capabilities. + - Bridges alone might not be enough. Dapps might need DEXs to offer more functionality such as cross-chain swaps. + +4. **Integrating multiple bridges –** This solution solves many problems associated with integrating a single bridge. However, it also has limitations, as integrating multiple bridges is resource-consuming and creates technical and communication overheads for developers—the scarcest resource in crypto. + +5. **Integrating a bridge aggregator –** Another option for dapps is integrating a bridge aggregation solution that gives them access to multiple bridges. Bridge aggregators inherit the strengths of all the bridges and thus are not limited by any single bridge’s capabilities. Notably, the bridge aggregators typically maintain the bridge integrations, which saves the dapp from the hassle of staying on top of the technical and operational aspects of a bridge integration. + +That being said, bridge aggregators also have their limitations. For instance, while they can offer more bridge options, many more bridges are typically available in the market other than those offered on the aggregator's platform. Moreover, just like bridges, bridge aggregators are also exposed to smart contract and technology risks (more smart contracts = more risks). + +If a dapp goes down the route of integrating a bridge or an aggregator, there are different options based on how deep the integration is meant to be. For instance, if it’s only a front-end integration to improve the user onboarding experience, a dapp would integrate the widget. However, if the integration is to explore deeper cross-chain strategies like staking, yield farming, etc., the dapp integrates the SDK or API. + +### Deploying a dapp on multiple chains + +To deploy a dapp on multiple chains, developers can use development platforms like [Alchemy](https://www.alchemy.com/), [Hardhat](https://hardhat.org/), [Moralis](https://moralis.io/), etc. Typically, these platforms come with composable plugins that can enable dapps to go cross-chain. For instance, developers can use a deterministic deployment proxy offered by the [hardhat-deploy plugin](https://github.com/wighawag/hardhat-deploy). + +#### Examples: + +- [How to build cross-chain dapps](https://moralis.io/how-to-build-cross-chain-dapps/) +- [Building a Cross-Chain NFT Marketplace](https://youtu.be/WZWCzsB1xUE) +- [Moralis: Building cross-chain NFT dapps](https://www.youtube.com/watch?v=ehv70kE1QYo) + +### Monitoring contract activity across chains + +To monitor contract activity across chains, developers can use subgraphs and developer platforms like Tenderly to observe smart contracts in real-time. Such platforms also have tools that offer greater data monitoring functionality for cross-chain activities, such as checking for [events emitted by contracts](https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=events#events), etc. + +#### Tools + +- [The Graph](https://thegraph.com/en/) +- [Tenderly](https://tenderly.co/) + +## Further reading +- [Blockchain Bridges](/bridges/) – ethereum.org +- [L2Beat Bridge Risk Framework](https://l2beat.com/bridges/summary) +- [Blockchain Bridges: Building Networks of Cryptonetworks](https://medium.com/1kxnetwork/blockchain-bridges-5db6afac44f8) - Sep 8, 2021 – Dmitriy Berenzon +- [The Interoperability Trilemma](https://blog.connext.network/the-interoperability-trilemma-657c2cf69f17) - Oct 1, 2021 – Arjun Bhuptani +- [Clusters: How Trusted & Trust-Minimized Bridges Shape the Multi-Chain Landscape](https://blog.celestia.org/clusters/) - Oct 4, 2021 – Mustafa Al-Bassam +- [LI.FI: With Bridges, Trust is a Spectrum](https://blog.li.fi/li-fi-with-bridges-trust-is-a-spectrum-354cd5a1a6d8) - Apr 28, 2022 – Arjun Chand +- [The State Of Rollup Interoperability Solutions](https://research.2077.xyz/the-state-of-rollup-interoperability) - June 20, 2024 – Alex Hook +- [Harnessing Shared Security For Secure Cross-Chain Interoperability: Lagrange State Committees And Beyond](https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - June 12, 2024 – Emmanuel Awosika + +Additionally, here are some insightful presentations by [James Prestwich](https://twitter.com/_prestwich) that can help develop a deeper understanding of bridges: + +- [Building Bridges, Not Walled Gardens](https://youtu.be/ZQJWMiX4hT0) +- [Breaking Down Bridges](https://youtu.be/b0mC-ZqN8Oo) +- [Why are the Bridges Burning](https://youtu.be/c7cm2kd20j8) + +--- + +## Developers > Docs > Consensus Mechanisms + +The term 'consensus mechanism' is often used colloquially to refer to 'proof-of-stake', 'proof-of-work' or 'proof-of-authority' protocols. However, these are just components in consensus mechanisms that protect against [Sybil attacks](/glossary/#sybil-attack). Consensus mechanisms are the complete stack of ideas, protocols and incentives that enable a distributed set of nodes to agree on the state of a blockchain. + +## Prerequisites + +To better understand this page, we recommend you first read our [introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +## What is consensus? + +By consensus, we mean that a general agreement has been reached. Consider a group of people going to the cinema. If there is no disagreement on a proposed choice of film, then a consensus is achieved. If there is disagreement, the group must have the means to decide which film to see. In extreme cases, the group will eventually split. + +In regard to the Ethereum blockchain, the process is formalized, and reaching consensus means that at least 66% of the nodes on the network agree on the global state of the network. + +## What is a consensus mechanism? + +The term consensus mechanism refers to the entire stack of protocols, incentives and ideas that allow a network of nodes to agree on the state of a blockchain. + +Ethereum uses a proof-of-stake-based consensus mechanism that derives its crypto-economic security from a set of rewards and penalties applied to capital locked by stakers. This incentive structure encourages individual stakers to operate honest validators, punishes those who don't, and creates an extremely high cost to attack the network. + +Then, there is a protocol that governs how honest validators are selected to propose or validate blocks, process transactions and vote for their view of the head of the chain. In the rare situations where multiple blocks are in the same position near the head of the chain, there is a fork-choice mechanism that selects blocks that make up the 'heaviest' chain, measured by the number of validators that voted for the blocks weighted by their staked ether balance. + +Some concepts are important to consensus that are not explicitly defined in code, such as the additional security offered by potential out-of-band social coordination as a last line of defense against attacks on the network. + +These components together form the consensus mechanism. + +## Types of consensus mechanisms + +### Proof-of-work based + +Like Bitcoin, Ethereum once used a **proof-of-work (PoW)** based consensus protocol. + +#### Block creation + +Miners compete to create new blocks filled with processed transactions. The winner shares the new block with the rest of the network and earns some freshly minted ETH. The race is won by the computer which is able to solve a math puzzle fastest. This produces the cryptographic link between the current block and the block that went before. Solving this puzzle is the work in "proof-of-work". The canonical chain is then determined by a fork-choice rule that selects the set of blocks that have had the most work done to mine them. + +#### Security + +The network is kept secure by the fact that you'd need 51% of the network's computing power to defraud the chain. This would require such huge investments in equipment and energy; you're likely to spend more than you'd gain. + +More on [proof-of-work](/developers/docs/consensus-mechanisms/pow/) + +### Proof-of-stake based + +Ethereum now uses a **proof-of-stake (PoS)** based consensus protocol. + +#### Block creation + +Validators create blocks. One validator is randomly selected in each slot to be the block proposer. Their consensus client requests a bundle of transactions as an 'execution payload' from their paired execution client. They wrap this in consensus data to form a block, which they send to other nodes on the Ethereum network. This block production is rewarded in ETH. In rare cases when multiple possible blocks exist for a single slot, or nodes hear about blocks at different times, the fork choice algorithm picks the block that forms the chain with the greatest weight of attestations (where weight is the number of validators attesting scaled by their ETH balance). + +#### Security + +A proof-of-stake system is secure crypto-economically because an attacker attempting to take control of the chain must destroy a massive amount of ETH. A system of rewards incentivizes individual stakers to behave honestly, and penalties disincentivize stakers from acting maliciously. + +More on [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) + +### A visual guide + +Watch more on the different types of consensus mechanisms used on Ethereum: + + + +### Sybil resistance & chain selection + +Proof-of-work and proof-of-stake alone are not consensus protocols, but they are often referred to as such for simplicity. They are actually Sybil resistance mechanisms and block author selectors; they are a way to decide who is the author of the latest block. Another important component is the chain selection (aka fork choice) algorithm that enables nodes to pick one single correct block at the head of the chain in scenarios where multiple blocks exist in the same position. + +**Sybil resistance** measures how a protocol fares against a Sybil attack. Resistance to this type of attack is essential for a decentralized blockchain and enables miners and validators to be rewarded equally based on resources put in. Proof-of-work and proof-of-stake protect against this by making users expend a lot of energy or put up a lot of collateral. These protections are an economic deterrent to Sybil attacks. + +A **chain selection rule** is used to decide which chain is the "correct" chain. Bitcoin uses the "longest chain" rule, which means that whichever blockchain is the longest will be the one the rest of the nodes accept as valid and work with. For proof-of-work chains, the longest chain is determined by the chain's total cumulative proof-of-work difficulty. Ethereum used to use the longest chain rule too; however, now that Ethereum runs on proof-of-stake it adopted an updated fork-choice algorithm that measures the 'weight' of the chain. The weight is the accumulated sum of validator votes, weighted by validator staked-ether balances. + +Ethereum uses a consensus mechanism known as [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) that combines [Casper FFG proof-of-stake](https://arxiv.org/abs/1710.09437) with the [GHOST fork-choice rule](https://arxiv.org/abs/2003.03052). + +## Further reading + +- [What Is a Blockchain Consensus Algorithm?](https://academy.binance.com/en/articles/what-is-a-blockchain-consensus-algorithm) +- [What is Nakamoto Consensus? Complete Beginner’s Guide](https://blockonomi.com/nakamoto-consensus/) +- [How Does Casper work?](https://medium.com/unitychain/intro-to-casper-ffg-9ed944d98b2d) +- [On the Security and Performance of Proof of Work Blockchains](https://eprint.iacr.org/2016/555.pdf) +- [Byzantine fault](https://en.wikipedia.org/wiki/Byzantine_fault) + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) +- [Mining](/developers/docs/consensus-mechanisms/pow/mining/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) + +--- + +## Developers > Docs > Consensus Mechanisms > Poa + +**Proof-of-authority (PoA)** is a reputation-based consensus algorithm that is a modified version of [proof-of-stake](/developers/docs/consensus-mechanisms/pos/). It is mostly used by private chains, testnets, and local development networks. PoA is a reputation-based consensus algorithm that requires trusting a set of authorized signers to produce blocks, instead of a stake-based mechanism in PoS. + +## Prerequisites + +To better understand this page, we recommend you first read up on [transactions](/developers/docs/transactions/), [blocks](/developers/docs/blocks/), and [consensus mechanisms](/developers/docs/consensus-mechanisms/). + +## What is proof-of-authority (PoA)? + +Proof-of-authority is a modified version of **[proof-of-stake](/developers/docs/consensus-mechanisms/pos/) (PoS)** that is a reputation-based consensus algorithm instead of stake-based mechanism in PoS. The term has been introduced for the first time in 2017 by Gavin Wood, and this consensus algorithm has been mostly used by private chains, testnets and local development networks, as it overcomes the need for high quality resources as PoW does, and overcomes the scalability issues with PoS by having small subset of nodes storing the blockchain and producing blocks. + +Proof-of-authority requires trusting a set of authorized signers that are set in the [genesis block](/glossary/#genesis-block). In most current implementations, all authorized signers retain equal power and privileges when determining consensus of the chain. The idea behind reputation staking is every authorized validator is well-known to everyone through things like know your customer (KYC), or by having a well-known organization being the only validator—this way if a validator does anything wrong, their identity is known. + +There are multiple implementations of PoA, but the standard Ethereum implementation is **clique**, which implements [EIP-225](https://eips.ethereum.org/EIPS/eip-225). Clique is developer-friendly and an easy-to-implement standard, supporting all client syncing types. Other implementations include [IBFT 2.0](https://besu.hyperledger.org/stable/private-networks/concepts/poa) and [Aura](https://openethereum.github.io/Chain-specification). + +## How it works + +In PoA, a set of authorized signers are selected to create new blocks. The signers are selected based on their reputation, and they are the only ones allowed to create new blocks. The signers are selected in a round-robin fashion, and each signer is allowed to create a block in a specific time frame. The block creation time is fixed, and the signers are required to create a block within that time frame. + +The reputation in this context is not a quantified thing but rather it is the reputation of well-known corporations like Microsoft and Google, hence the way of selecting the trusted signers is not algorithmic but rather it is the normal human act of _trust_ where an entity let's say for example Microsoft creates a PoA private network between hundreds or thousands of startups and the role itself as the only trusted signer with the possibility of adding other well-known signers like Google in the future, the startups would, without doubt, trust Microsoft to act in an honest manner all the times and use the network. This solves the need to stake in different small/private networks that were built for different purposes to keep them decentralized and functioning, along with the need for miners, which consumes a lot of power and resources. Some private networks use the PoA standard as it such as VeChain, and some modify it such as Binance which uses [PoSA](https://academy.binance.com/en/glossary/proof-of-staked-authority-posa) which is a custom modified version of PoA and PoS. + +The voting process is done by the signers themselves. Each signer votes for the addition or removal of a signer in their block when they create a new block. The votes are tallied up by the nodes, and the signers are added or removed based on the votes reaching a certain threshold `SIGNER_LIMIT`. + +There may be a situation where small forks occur, the difficulty of a block depends on whether the block was signed in turn or out of turn. “In turn” blocks have difficulty 2, and “out of turn” blocks have difficulty 1. In the case of small forks, the chain with most of the signers sealing blocks “in turn” will accumulate the most difficulty and win. + +## Attack vectors + +### Malicious signers + +A malicious user could be added to the list of signers, or a signing key/machine might be compromised. In such a scenario the protocol needs to be able to defend itself against reorganizations and spamming. The proposed solution is that given a list of N authorized signers, any signer may only mint 1 block out of every K. This ensures that damage is limited, and the remainder of the validators can vote out the malicious user. + +### Censorship + +Another interesting attack vector is if a signer (or group of signers) attempts to censor blocks that vote on removing them from the authorization list. To work around this, the allowed minting frequency of signers is restricted to 1 out of N/2. This ensures that malicious signers need to control at least 51% of signing accounts, at which point they would effectively become the new source-of-truth for the chain. + +### Spam + +Another small attack vector is malicious signers injecting new vote proposals inside every block they mint. Since nodes need to tally up all votes to create the actual list of authorized signers, they must record all votes over time. Without placing a limit on the vote window, this could grow slowly, yet unbounded. The solution is to place a _moving_ window of W blocks after which votes are considered stale. _A reasonable window might be 1-2 epochs._ + +### Concurrent blocks + +In a PoA network, When there are N authorized signers, each signer is allowed to mint 1 block out of K, which means that N-K+1 validators are allowed to mint at any given point in time. To prevent these validators from racing for blocks, each signer should add a small random "offset" to the time it releases a new block. Although this process ensures that small forks are rare, occasional forks can still happen, just like mainnet. If a signer is found to be abusing its power and causing chaos, the other signers can vote them out. + +If for example there are 10 authorized signers and each signer is allowed to create 1 block out of 20, then at any given time, 11 validators can create blocks. To prevent them from racing to create blocks, each signer adds a small random "offset" to the time they release a new block. This reduces the occurrence of small forks but still allows occasional forks, as seen on the Ethereum Mainnet. If a signer misuses their authority and causes disruptions, they can be voted out of the network. + +## Pros and cons + +| Pros | Cons | +| --------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| Scalable more than other popular mechanisms such PoS and PoW, as it's based on a limited number of block signers | PoA networks typically have a relatively small number of validating nodes. This makes a PoA network more centralized. | +| PoA blockchains are incredibly cheap to run and maintain | Becoming an authorized signer is typically out of reach for an ordinary person, because the blockchain requires entities with established reputation. | +| The transactions are confirmed very quick as it could reach less than 1 second because only limited number of signers are required to validate new blocks | Malicious signers could reorg, double spend, censor transactions in the network, those attacks are mitigated but still possible | + +## Further reading + +- [EIP-225](https://eips.ethereum.org/EIPS/eip-225) _Clique standard_ +- [Proof of Authority study](https://github.com/cryptoeconomics-study/website/blob/master/docs/sync/2.4-lecture.md) _Cryptoeconomics_ +- [What is Proof of Authority](https://forum.openzeppelin.com/t/proof-of-authority/3577) _OpenZeppelin_ +- [Proof of Authority Explained](https://academy.binance.com/en/articles/proof-of-authority-explained) _binance_ +- [PoA in blockchain](https://medium.com/techskill-brew/proof-of-authority-or-poa-in-blockchain-part-11-blockchain-series-be15b3321cba) +- [Clique explained](https://medium.com/@Destiner/clique-cross-client-proof-of-authority-algorithm-for-ethereum-8b2a135201d) +- [Deprecated PoA, Aura specification](https://openethereum.github.io/Chain-specification) +- [IBFT 2.0, another PoA implementation](https://besu.hyperledger.org/stable/private-networks/concepts/poa) + +### More of a visual learner? + +Watch a visual explanation of proof-of-authority: + + + +## Related topics + +- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Attack And Defense + +Thieves and saboteurs are constantly seeking opportunities to attack Ethereum’s client software. This page outlines the known attack vectors on Ethereum’s consensus layer and outlines how those attacks can be defended. The information on this page is adapted from a [longer form version](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs). + +## Prerequisites + +Some basic knowledge of [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) is required. Also, it will be helpful to have a basic understanding of Ethereum's [incentive layer](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) and fork-choice algorithm, [LMD-GHOST](/developers/docs/consensus-mechanisms/pos/gasper). + +## What do attackers want? + +A common misconception is that a successful attacker can generate new ether, or drain ether from arbitrary accounts. Neither of these are possible because all transactions are executed by all the execution clients on the network. They must satisfy basic conditions of validity (e.g. transactions are signed by sender’s private key, sender has sufficient balance, etc) or else they simply revert. There are three classes of outcome that an attacker might realistically target: reorgs, double finality or finality delay. + +A **“reorg”** is a reshuffling of blocks into a new order, perhaps with some addition or subtraction of blocks in the canonical chain. A malicious reorg might ensure specific blocks are included or excluded, allowing double-spending or value extraction by front-running and back-running transactions (MEV). Re-orgs could also be used to prevent certain transactions from being included in the canonical chain - a form of censorship. The most extreme form of reorg is “finality reversion” which removes or replaces blocks that have previously been finalized. This is only possible if more than ⅓ of the total staked ether is destroyed by the attacker - this guarantee is known as “economic finality” - more on this later. + +**Double finality** is the unlikely but severe condition where two forks are able to finalize simultaneously, creating a permanent schism in the chain. This is theoretically possible for an attacker willing to risk 34% of the total staked ether. The community would be forced to coordinate offchain and come to an agreement about which chain to follow, which would require strength in the social layer. + +A **finality delay** attack prevents the network from reaching the necessary conditions finalizing sections of the chain. Without finality, it is hard to trust financial applications built on top of Ethereum. The aim of a finality delay attack is likely simply to disrupt Ethereum rather than to directly profit, unless the attacker has some strategic short position(s). + +An attack on the social layer might aim to undermine public trust in Ethereum, devalue ether, reduce adoption or to weaken the Ethereum community to make out-of-band coordination more difficult. + +Having established why an adversary might attack Ethereum, the following sections examine _how_ they might go about it. + +## Methods of Attack + +### Layer 0 Attacks + +First of all, individuals that are not actively participating in Ethereum (by running client software) can attack by targeting the social layer (Layer 0). Layer 0 is the foundation upon which Ethereum is built, and as such it represents a potential surface for attacks with consequences that ripple through the rest of the stack. Some examples might include: + +- A misinformation campaign could erode the trust the community has in Ethereum’s roadmap, teams of developers, apps etc. This could then decrease the number of individuals willing to participate in securing the network, degrading both decentralization and crypto-economic security. +- Targeted attacks and/or intimidation directed at the developer community. This could lead to voluntary exit of developers and slow down Ethereum’s progress. + +- Over-zealous regulation could also be considered to be an attack on Layer 0, since it could rapidly disincentivize participation and adoption. +- Infiltration of knowledgeable but malicious actors into the developer community whose aim is to slow down progress by bike-shedding discussions, delaying key decisions, creating spam etc. +- Bribes made to key players in the Ethereum ecosystem to influence decision making. + +What makes these attacks especially dangerous is that in many cases very little capital or technical know-how is required. A Layer 0 attack could be a multiplier on a crypto-economic attack. For example, if censorship or finality reversion were achieved by a malicious majority stakeholder, undermining the social layer might make it more difficult to coordinate a community response out-of-band. + +Defending against Layer 0 attacks is probably not straightforward, but some basic principles can be established. One is maintaining an overall high signal to noise ratio for public information about Ethereum, created and propagated by honest members of the community through blogs, discord servers, annotated specs, books, podcasts and Youtube. Here at ethereum.org we try hard to maintain accurate information and translate it into as many languages as possible. Flooding a space with high quality information and memes is an effective defense against misinformation. + +Another important fortification against social layer attacks is a clear mission statement and governance protocol. Ethereum has positioned itself as the decentralization and security champion among smart-contract layer 1’s, while also highly valuing scalability and sustainability. Whatever disagreements arise in the Ethereum community, these core principles are minimally compromised. Appraising a narrative against these core principles, and examining them through successive rounds of review in the EIP (Ethereum Improvement Proposal) process, might help the community to distinguish good from bad actors and limits the scope for malicious actors to influence the future direction of Ethereum. + +Finally, it is critical that the Ethereum community remains open and welcoming to all participants. A community with gatekeepers and exclusivity is one especially vulnerable to social attack because it is easy to build “us and them” narratives. Tribalism and toxic maximalism hurt the community and erode Layer 0 security. Ethereans with a vested interest in the security of the network should view their conduct online and in meatspace as a direct contributor to the security of Ethereum’s Layer 0. + +### Attacking the protocol + +Anyone can run Ethereum’s client software. To add a validator to a client, a user is required to stake 32 ether into the deposit contract. A validator allows a user to actively participate in Ethereum’s network security by proposing and attesting to new blocks. The validator now has a voice they can use to influence the future contents of the blockchain - they can do so honestly and grow their stash of ether via rewards or they can try to manipulate the process to their own advantage, risking their stake. One way to mount an attack is to accumulate a greater proportion of the total stake and then use it to outvote honest validators. The greater the proportion of the stake controlled by the attacker the greater their voting power, especially at certain economic milestones that we will explore later. However, most attackers will not be able to accumulate sufficient ether to attack in this way, so instead they have to use subtle techniques to manipulate the honest majority into acting a certain way. + +Fundamentally, all small-stake attacks are subtle variations on two types of validator misbehavior: under-activity (failing to attest/propose or doing so late) or over-activity (proposing/attesting too many times in a slot). In their most vanilla forms these actions are easily handled by the fork-choice algorithm and incentive layer, but there are clever ways to game the system to an attacker’s advantage. + +### Attacks using small amounts of ETH + +#### reorgs + +Several papers have explained attacks on Ethereum that achieve reorgs or finality delay with only a small proportion of the total staked ether. These attacks generally rely upon the attacker withholding some information from other validators and then releasing it in some nuanced way and/or at some opportune moment. They usually aim to displace some honest block(s) from the canonical chain. [Neuder et al 2020](https://arxiv.org/pdf/2102.02247.pdf) showed how an attacking validator can create and attest to a block (`B`) for a particular slot `n+1` but refrain from propagating it to other nodes on the network. Instead, they hold on to that attested block until the next slot `n+2`. An honest validator proposes a block (`C`) for slot `n+2`. Almost simultaneously, the attacker can release their withheld block (`B`) and their withheld attestations for it, and also attest to `B` being the head of the chain with their votes for slot `n+2`, effectively denying the existence of honest block `C`. When honest block `D` is released, the fork choice algorithm sees `D` building on top of `B` being heavier than `D` building on `C`. The attacker has therefore managed to remove the honest block `C` in slot `n+2` from the canonical chain using a 1-block ex ante reorg. [An attacker with 34%](https://www.youtube.com/watch?v=6vzXwwk12ZE) of the stake has a very good chance of succeeding in this attack, as explained [in this note](https://notes.ethereum.org/plgVdz-ORe-fGjK06BZ_3A#Fork-choice-by-block-slot-pair). In theory, though, this attack could be attempted with smaller stakes. [Neuder et al 2020](https://arxiv.org/pdf/2102.02247.pdf) described this attack working with a 30% stake, but it was later shown to be viable with [2% of the total stake](https://arxiv.org/pdf/2009.04987.pdf) and then again for a [single validator](https://arxiv.org/abs/2110.10086#) using balancing techniques we will examine in the next section. + +![ex-ante re-org](reorg-schematic.png) + +A conceptual diagram of the one-block reorg attack described above (adapted from https://notes.ethereum.org/plgVdz-ORe-fGjK06BZ_3A#Fork-choice-by-block-slot-pair) + +A more sophisticated attack can split the honest validator set into discrete groups that have different views of the head of the chain. This is known as a **balancing attack**. The attacker waits for their chance to propose a block, and when it arrives they equivocate and propose two. They send one block to half of the honest validator set and the other block to the other half. The equivocation would be detected by the fork-choice algorithm and the block proposer would be slashed and ejected from the network, but the two blocks would still exist and would have about half the validator set attesting to each fork. Meanwhile, the remaining malicious validators hold back their attestations. Then, by selectively releasing the attestations favoring one or other fork to just enough validators just as the fork-choice algorithm executes, they tip the accumulated weight of attestations in favor of one or other fork. This can continue indefinitely, with the attacking validators maintaining an even split of validators across the two forks. Since neither fork can attract a 2/3 supermajority, the network would not finalize. + +**Bouncing attacks** are similar. Votes are again withheld by the attacking validators. Instead of releasing the votes to keep an even split between two forks, they use their votes at opportune moments to justify checkpoints that alternate between fork A and fork B. This flip-flopping of justification between two forks prevents there from being pairs of justified source and target checkpoints that can be finalized on either chain, halting finality. + + + +Both bouncing and balancing attacks rely upon the attacker having very fine control over message timing across the network, which is unlikely. Nevertheless, defenses are built into the protocol in the form of additional weighting given to prompt messages compared to slow ones. This is known as [proposer-weight boosting](https://github.com/ethereum/consensus-specs/pull/2730). To defend against bouncing attacks the fork-choice algorithm was updated so that the latest justified checkpoint can only switch to that of an alternative chain during the [first 1/3 of the slots in each epoch](https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114). This condition prevents the attacker from saving up votes to deploy later - the fork choice algorithm simply stays loyal to the checkpoint it chose in the first 1/3 of the epoch during which time most honest validators would have voted. + +Combined, these measures create a scenario in which an honest block proposer emits their block very rapidly after the start of the slot, then there is a period of ~1/3 of a slot (4 seconds) where that new block might cause the fork-choice algorithm to switch to another chain. After that same deadline, attestations that arrive from slow validators are down-weighted compared to those that arrived earlier. This strongly favors prompt proposers and validators in determining the head of the chain and substantially reduces the likelihood of a successful balancing or bouncing attack. + +It is worth noting, that proposer boosting alone only defends against “cheap reorgs”, i.e. those attempted by an attacker with a small stake. In fact, proposer-boosting itself can be gamed by larger stakeholders. The authors of [this post](https://ethresear.ch/t/change-fork-choice-rule-to-mitigate-balancing-and-reorging-attacks/11127) describe how an attacker with 7% of the stake can deploy their votes strategically to trick honest validators to build on their fork, reorging out an honest block. This attack was devised assuming ideal latency conditions that are very unlikely. The odds are still very long for the attacker, and the greater stake also means more capital at risk and a stronger economic disincentive. + +A [balancing attack specifically targeting the LMD rule](https://ethresear.ch/t/balancing-attack-lmd-edition/11853) was also proposed, which was suggested to be viable in spite of proposer boosting. An attacker sets up two competing chains by equivocating their block proposal and propagating each block to about half the network each, setting up an approximate balance between the forks. Then, the colluding validators equivocate their votes, timing it so that half the network receive their votes for Fork `A` first and the other half receives their votes for Fork `B` first. Since the LMD rule discards the second attestation and keeps only the first for each validator, half the network sees votes for `A` and none for `B`, the other half sees votes for `B` and none for `A`. The authors describe the LMD rule giving the adversary “remarkable power” to mount a balancing attack. + +This LMD attack vector was closed by [updating the fork choice algorithm](https://github.com/ethereum/consensus-specs/pull/2845) so that it discards equivocating validators from the fork choice consideration altogether. Equivocating validators also have their future influence discounted by the fork choice algorithm. This prevents the balancing attack outlined above while also maintaining resilience against avalanche attacks. + +Another class of attack, called [**avalanche attacks**](https://ethresear.ch/t/avalanche-attack-on-proof-of-stake-ghost/11854/3), was described in a [March 2022 paper](https://arxiv.org/pdf/2203.01315.pdf). To mount an avalanche attack, the attacker needs to control several consecutive block proposers. In each of the block proposal slots, the attacker withholds their block, collecting them up until the honest chain reaches an equal subtree weight with the withheld blocks. Then, the withheld blocks are released so that they equivocate maximally. The authors suggest that proposer boosting - the primary defense against balancing and bouncing attacks - does not protect against some variants of avalanche attack. However, the authors also only demonstrated the attack on a highly idealized version of Ethereum’s fork-choice algorithm (they used GHOST without LMD). + +The avalanche attack is mitigated by the LMD portion of the LMD-GHOST fork choice algorithm. LMD means “latest-message-driven” and it refers to a table kept by each validator containing the latest message received from other validators. That field is only updated if the new message is from a later slot than the one already in the table for a particular validator. In practice, this means that in each slot, the first message received is the one that it accepted and any additional messages are equivocations to be ignored. Put another way, the consensus clients don’t count equivocations - they use the first-arriving message from each validator and equivocations are simply discarded, preventing avalanche attacks. + +There are several other potential future upgrades to the fork choice rule that could add to the security provided by proposer-boost. One is [view-merge](https://ethresear.ch/t/view-merge-as-a-replacement-for-proposer-boost/13739), where attesters freeze their view of the fork choice `n` seconds before the beginning of a slot and the proposer then helps to synchronize the view of the chain across the network. Another potential upgrade is [single-slot finality](https://notes.ethereum.org/@vbuterin/single_slot_finality), which protects against attacks based on message timing by finalizing the chain after just one slot. + +#### Finality Delay + +[The same paper](https://econcs.pku.edu.cn/wine2020/wine2020/Workshop/GTiB20_paper_8.pdf) that first described the low-cost single block reorg attack also described a finality delay (a.k.a “liveness failure”) attack that relies on the attacker being the block proposer for an epoch-boundary block. This is critical because these epoch boundary blocks become the checkpoints that Casper FFG uses to finalize portions of the chain. The attacker simply withholds their block until enough honest validators use their FFG votes in favor of the previous epoch-boundary block as the current finalization target. Then they release their withheld block. They attest to their block and the remaining honest validators do too creating forks with different target checkpoints. If they timed it just right, they will prevent finality because there will not be a 2/3 supermajority attesting to either fork. The smaller the stake, the more precise the timing needs to be because the attacker controls fewer attestations directly, and the lower the odds of the attacker controlling the validator proposing a given epoch-boundary block. + +#### Long range attacks + +There is also a class of attack specific to proof-of-stake blockchains that involves a validator that participated in the genesis block maintaining a separate fork of the blockchain alongside the honest one, eventually convincing the honest validator set to switch over to it at some opportune time much later. This type of attack is not possible on Ethereum because of the finality gadget that ensures all validators agree on the state of the honest chain at regular intervals (“checkpoints”). This simple mechanism neutralizes long range attackers because Ethereum clients simply will not reorg finalized blocks. New nodes joining the network do so by finding a trusted recent state hash (a “[weak subjectivity](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) checkpoint”) and using it as a pseudo-genesis block to build on top of. This creates a ‘trust gateway’ for a new node entering the network before it can start to verify information for itself. + +#### Denial of Service + +Ethereum’s PoS mechanism picks a single validator from the total validator set to be a block proposer in each slot. This can be computed using a publicly known function and it is possible for an adversary to identify the next block proposer slightly in advance of their block proposal. Then, the attacker can spam the block proposer to prevent them swapping information with their peers. To the rest of the network, it would appear that the block proposer was offline and the slot would simply go empty. This could be a form of censorship against specific validators, preventing them from adding information to the blockchain. Implementing single secret leader elections (SSLE) or non-single secret leader elections will mitigate DoS risks because only the block proposer ever knows they have been selected and the selection is not knowable in advance. This is not yet implemented, but is an active area of [research and development](https://ethresear.ch/t/secret-non-single-leader-election/11789). + +All of this points to the fact that it is very difficult to successfully attack Ethereum with a small stake. The viable attacks that have been described here require an idealized fork-choice algorithm, improbable network conditions, or the attack vectors have already been closed with relatively minor patches to the client software. This, of course, does not rule out the possibility of zero-days existing out in the wild, but it does demonstrate the extremely high bar of technical aptitude, consensus layer knowledge and luck required for a minority-stake attacker to be effective. From an attacker’s perspective their best bet might be to accumulate as much ether as possible and to return armed with a greater proportion of the total stake. + +### Attackers using >= 33% of the total stake + +All of the attacks mentioned previously in this article become more likely to succeed when the attacker has more staked ether to vote with, and more validators that might be chosen to propose blocks in each slot. A malicious validator might therefore aim to control as much staked ether as possible. + +33% of the staked ether is a benchmark for an attacker because with anything greater than this amount they have the ability to prevent the chain from finalizing without having to finely control the actions of the other validators. They can simply all disappear together. If 1/3 or more of the staked ether is maliciously attesting or failing to attest, then a 2/3 supermajority cannot exist and the chain cannot finalize. The defense against this is the inactivity leak. The inactivity leak identifies those validators that are failing to attest or attesting contrary to the majority. The staked ether owned by these non-attesting validators is gradually bled-away until eventually they collectively represent less than 1/3 of the total so that the chain can finalize again. + +The purpose of the inactivity leak is to get the chain finalizing again. However, the attacker also loses a portion of their staked ether. Persistent inactivity across validators representing 33% of the total staked ether is very expensive even though the validators are not slashed. + +Assuming that the Ethereum network is asynchronous (i.e. there are delays between messages being sent and received), an attacker controlling 34% of the total stake could cause double finality. This is because the attacker can equivocate when they are chosen to be a block producer, then double vote with all of their validators. This creates a situation where a fork of the blockchain exists, each with 34% of the staked ether voting for it. Each fork only requires 50% of the remaining validators to vote in its favor for both forks to be supported by a supermajority, in which case both chains can finalize (because 34% of attackers validators + half of remaining 66% = 67% on each fork). The competing blocks would each have to be received by about 50% of the honest validators so this attack is viable only when the attacker has some degree of control over the timing of messages propagating over the network so that they can nudge half the honest validators onto each chain. The attacker would necessarily destroy their entire stake (34% of ~10 million ether with today’s validator set) to achieve this double finality because 34% of their validators would be double-voting simultaneously - a slashable offense with the maximum correlation penalty. The defense against this attack is the very large cost of destroying 34% of the total staked ether. Recovering from this attack would require the Ethereum community to coordinate “out-of-band” and agree to follow one or other of the forks and ignore the other. + +### Attackers using ~50% of the total stake + +At 50% of the staked ether, a mischievous group of validators could theoretically split the chain into two equally sized forks and then simply use their entire 50% stake to vote contrarily to the honest validator set, thereby maintaining the two forks and preventing finality. The inactivity leak on both forks would eventually lead both chains to finalize. At this point, the only option is to fall back on a social recovery. + +It is very unlikely that an adversarial group of validators could consistently control precisely 50% of the total stake given a degree of flux in honest validator numbers, network latency etc - the huge cost of mounting such an attack combined with the low likelihood of success appears to be a strong disincentive for a rational attacker, especially when a small additional investment in obtaining _more than_ 50% unlocks a lot more power. + +At >50% of the total stake the attacker could dominate the fork choice algorithm. In this case, the attacker would be able to attest with the majority vote, giving them sufficient control to do short reorgs without needing to fool honest clients. The honest validators would follow suit because their fork choice algorithm would also see the attacker’s favored chain as the heaviest, so the chain could finalize. This enables the attacker to censor certain transactions, do short-range reorgs and extract maximum MEV by reordering blocks in their favor. The defense against this is the huge cost of a majority stake (currently just under $19 billion USD) which is put at risk by an attacker because the social layer is likely to step in and adopt an honest minority fork, devaluing the attacker’s stake dramatically. + +### Attackers using >=66% of the total stake + +An attacker with 66% or more of the total staked ether can finalize their preferred chain without having to coerce any honest validators. The attacker can simply vote for their preferred fork and then finalize it, simply because they can vote with a dishonest supermajority. As the supermajority stakeholder, the attacker would always control the contents of the finalized blocks, with the power to spend, rewind and spend again, censor certain transactions and reorg the chain at will. By purchasing additional ether to control 66% rather than 51%, the attacker is effectively buying the ability to do ex post reorgs and finality reversions (i.e. change the past as well as control the future). The only real defenses here are the enormous cost of 66% of the total staked ether, and the option to fall back to the social layer to coordinate adoption of an alternative fork. We can explore this in more detail in the next section. + +## People: the last line of defense + +If the dishonest validators manage to finalize their preferred version of the chain, the Ethereum community is put in a difficult situation. The canonical chain includes a dishonest section baked into its history, while honest validators can end up being punished for attesting to an alternative (honest) chain. Note that a finalized but incorrect chain could also arise from a bug in a majority client. In the end, the ultimate fallback is to rely on the social layer - Layer 0 - to resolve the situation. + +One of the strengths of Ethereum’s PoS consensus is that there are a [range of defensive strategies](https://youtu.be/1m12zgJ42dI?t=1712) that the community can employ in the face of an attack. A minimal response could be to forcibly exit the attackers’ validators from the network without any additional penalty. To re-enter the network the attacker would have to join an activation queue that ensures the validator set grows gradually. For example, adding enough validators to double the amount of staked ether takes about 200 days, effectively buying the honest validators 200 days before the attacker can attempt another 51% attack. However,the community could also decide to penalize the attacker more harshly, by revoking past rewards or burning some portion (up to 100%) of their staked capital. + +Whatever the penalty imposed on the attacker, the community also has to decide together whether the dishonest chain, despite being the one favored by the fork choice algorithm coded into the Ethereum clients, is in fact invalid and that the community should build on top of the honest chain instead. Honest validators could collectively agree to build on top of a community-accepted fork of the Ethereum blockchain that might, for example, have forked off the canonical chain before the attack started or have the attackers’ validators forcibly removed. Honest validators would be incentivized to build on this chain because they would avoid the penalties applied to them for failing (rightly) to attest to the attacker’s chain. Exchanges, on-ramps and applications built on Ethereum would presumably prefer to be on the honest chain and would follow the honest validators to the honest blockchain. + +However, this would be a substantial governance challenge. Some users and validators would undoubtedly lose out as a result of the switch back to the honest chain, transactions in blocks validated after the attack could potentially be rolled back, disrupting the application layer, and it quite simply undermines the ethics of some users who tend to believe “code is law”. Exchanges and applications will most likely have linked offchain actions to onchain transactions that may now be rolled back, starting a cascade of retractions and revisions that would be hard to unpick fairly, especially if ill-gotten gains have been mixed, deposited into DeFi or other derivatives with secondary effects for honest users. Undoubtedly some users, perhaps even institutional ones, would have already benefited from the dishonest chain either by being shrewd or by serendipity, and might oppose a fork to protect their gains. There have been calls to rehearse the community response to >51% attacks so that a sensible coordinated mitigation could be executed quickly. There is some useful discussion by Vitalik on ethresear.ch [here](https://ethresear.ch/t/timeliness-detectors-and-51-attack-recovery-in-blockchains/6925) and [here](https://ethresear.ch/t/responding-to-51-attacks-in-casper-ffg/6363) and on Twitter [here](https://twitter.com/skylar_eth/status/1551798684727508992?s=20&t=oHZ1xv8QZdOgAXhxZKtHEw). The aim of a coordinated social response should be to be very targeted and specific about punishing the attacker and minimizing effects for other users. + +Governance is already a complicated topic. Managing a Layer-0 emergency response to a dishonest finalizing chain would undoubtedly be challenging for the Ethereum community, but it [has happened](/history/#dao-fork-summary) - [twice](/history/#tangerine-whistle) - in Ethereum’s history). + +Nevertheless, there is something fairly satisfying in the final fallback sitting in meatspace. Ultimately, even with this phenomenal stack of technology above us, if the worst were ever to happen real people would have to coordinate their way out of it. + +## Summary + +This page explored some of the ways attackers might attempt to exploit Ethereum’s proof-of-stake consensus protocol. Reorgs and finality delays were explored for attackers with increasing proportions of the total staked ether. Overall, a richer attacker has more chance of success because their stake translates to voting power they can use to influence the contents of future blocks. At certain threshold amounts of staked ether, the attacker’s power levels up: + +33%: finality delay + +34%: finality delay, double finality + +51%: finality delay, double finality, censorship, control over blockchain future + +66%: finality delay, double finality, censorship, control over blockchain future and past + +There are also a range of more sophisticated attacks that require small amounts of staked ether but rely upon a very sophisticated attacker having fine control over message timing to sway the honest validator set in their favor. + +Overall, despite these potential attack vectors the risk of a successful attack is low, certainly lower than proof-of-work equivalents. This is because of the huge cost of the staked ether put at risk by an attacker aiming to overwhelm honest validators with their voting power. The built-in “carrot and stick” incentive layer protects against most malfeasance, especially for low-stake attackers. More subtle bouncing and balancing attacks are also unlikely to succeed because real network conditions make the fine control of message delivery to specific subsets of validators very difficult to achieve, and client teams have quickly closed the known bouncing, balancing and avalanche attack vectors with simple patches. + +34%, 51% or 66% attacks would likely require out-of-band social coordination to resolve. While this would likely be painful for the community, the ability for a community to respond out-of-band is a strong disincentive for an attacker. The Ethereum social layer is the ultimate backstop - a technically successful attack could still be neutered by the community agreeing to adopt an honest fork. There would be a race between the attacker and the Ethereum community - the billions of dollars spent on a 66% attack would probably be obliterated by a successful social coordination attack if it was delivered quickly enough, leaving the attacker with heavy bags of illiquid staked ether on a known dishonest chain ignored by the Ethereum community. The likelihood that this would end up being profitable for the attacker is sufficiently low as to be an effective deterrent. This is why investment in maintaining a cohesive social layer with tightly aligned values is so important. + +## Further Reading + +- [More detailed version of this page](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs) +- [Vitalik on settlement finality](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) +- [LMD GHOST paper](https://arxiv.org/abs/2003.03052) +- [Casper-FFG paper](https://arxiv.org/abs/1710.09437) +- [Gasper paper](https://arxiv.org/pdf/2003.03052.pdf) +- [Proposer weight boosting consensus specs](https://github.com/ethereum/consensus-specs/pull/2730) +- [Bouncing attacks on ethresear.ch](https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114) +- [SSLE research](https://ethresear.ch/t/secret-non-single-leader-election/11789) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Attestations + +A validator is expected to create, sign and broadcast an attestation during every epoch. This page outlines what these attestations look like and how they are processed and communicated between consensus clients. + +## What is an attestation? + +Every [epoch](/glossary/#epoch) (6.4 minutes) a validator proposes an attestation to the network. The attestation is for a specific slot in the epoch. The purpose of the attestation is to vote in favor of the validator's view of the chain, in particular the most recent justified block and the first block in the current epoch (known as `source` and `target` checkpoints). This information is combined for all participating validators, enabling the network to reach consensus about the state of the blockchain. + +The attestation contains the following components: + +- `aggregation_bits`: a bitlist of validators where the position maps to the validator index in their committee; the value (0/1) indicates whether the validator signed the `data` (i.e. whether they are active and agree with the block proposer) +- `data`: details relating to the attestation, as defined below +- `signature`: a BLS signature that aggregates the signatures of individual validators + +The first task for an attesting validator is to build the `data`. The `data` contains the following information: + +- `slot`: The slot number that the attestation refers to +- `index`: A number that identifies which committee the validator belongs to in a given slot +- `beacon_block_root`: Root hash of the block the validator sees at the head of the chain (the result of applying the fork-choice algorithm) +- `source`: Part of the finality vote indicating what the validators see as the most recent justified block +- `target`: Part of the finality vote indicating what the validators see as the first block in the current epoch + +Once the `data` is built, the validator can flip the bit in `aggregation_bits` corresponding to their own validator index from 0 to 1 to show that they participated. + +Finally, the validator signs the attestation and broadcasts it to the network. + +### Aggregated attestation + +There is a substantial overhead associated with passing this data around the network for every validator. Therefore, the attestations from individual validators are aggregated within subnets before being broadcast more widely. This includes aggregating signatures together so that an attestation that gets broadcast includes the consensus `data` and a single signature formed by combining the signatures of all the validators that agree with that `data`. This can be checked using `aggregation_bits` because this provides the index of each validator in their committee (whose ID is provided in `data`) which can be used to query individual signatures. + +In each epoch 16 validators in each subnet are selected to be the `aggregators`. The aggregators collect all the attestations they hear about over the gossip network that have equivalent `data` to their own. The sender of each matching attestation is recorded in the `aggregation_bits`. The aggregators then broadcast the attestation aggregate to the wider network. + +When a validator is selected to be a block proposer they package aggregate attestations from the subnets up to the latest slot in the new block. + +### Attestation inclusion lifecycle + +1. Generation +2. Propagation +3. Aggregation +4. Propagation +5. Inclusion + +The attestation lifecycle is outlined in the schematic below: + +![attestation lifecycle](./attestation_schematic.png) + +## Rewards + +Validators are rewarded for submitting attestations. The attestation reward depends on the participation flags (source, target and head), the base reward and the participation rate. + +Each of the participation flags can be either true or false, depending on the submitted attestation and its inclusion delay. + +The best scenario occurs when all three flags are true, in which case a validator would earn (per correct flag): + +`reward += base reward * flag weight * flag attesting rate / 64` + +The flag attesting rate is measured using the sum of effective balances of all attesting validators for the given flag compared the total active effective balance. + +### Base reward + +The base reward is calculated according to the number of attesting validators and their effective staked ether balances: + +`base reward = validator effective balance x 2^6 / SQRT(Effective balance of all active validators)` + +#### Inclusion delay + +At the time when the validators voted on the head of the chain (`block n`), `block n+1` was not proposed yet. Therefore attestations naturally get included **one block later** so all attestations who voted on `block n` being the chain head got included in `block n+1` and, the **inclusion delay** is 1. If the inclusion delay doubles to two slots, the attestation reward halves, because to calculate the attestation reward the base reward is multiplied by the reciprocal of the inclusion delay. + +### Attestation scenarios + +#### Missing Voting Validator + +Validators have a maximum of 1 epoch to submit their attestation. If the attestation was missed in epoch 0, they can submit it with an inclusion delay in epoch 1. + +#### Missing Aggregator + +There are 16 Aggregators per epoch in total. In addition, random validators subscribe to **two subnets for 256 epochs** and serve as a backup in case aggregators are missing. + +#### Missing block proposer + +Note that in some cases a lucky aggregator may also become the block proposer. If the attestation was not included because the block proposer has gone missing, the next block proposer would pick the aggregated attestation up and include it into the next block. However, the **inclusion delay** will increase by one. + +## Further reading + +- [Attestations in Vitalik's annotated consensus spec](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#attestationdata) +- [Attestations in eth2book.info](https://eth2book.info/capella/part3/containers/dependencies/#attestationdata) + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Block Proposal + +Blocks are the fundamental units of the blockchain. Blocks are discrete units of information that get passed between nodes, agreed upon and added to each node's database. This page explains how they are produced. + +## Prerequisites + +Block proposal is part of the proof-of-stake protocol. To help understand this page, we recommend you read about [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) and [block architecture](/developers/docs/blocks/). + +## Who produces blocks? + +Validator accounts propose blocks. Validator accounts are managed by node operators who run validator software as part of their execution and consensus clients and have deposited at least 32 ETH into the deposit contract. However, each validator is only occasionally responsible for proposing a block. Ethereum measures time in slots and epochs. Each slot is twelve seconds, and 32 slots (6.4 minutes) make up an epoch. Every slot is an opportunity to add a new block on Ethereum. + +### Random selection + +A single validator is pseudo-randomly chosen to propose a block in each slot. There is no such thing as true randomness in a blockchain because if each node generated genuinely random numbers, they couldn't come to consensus. Instead, the aim is to make the validator selection process unpredictable. The randomness is achieved on Ethereum using an algorithm called RANDAO that mixes a hash from the block proposer with a seed that gets updated every block. This value is used to select a specific validator from the total validator set. The validator selection is fixed two epochs in advance as a way to protect against certain kinds of seed manipulation. + +Although validators add to RANDAO in each slot, the global RANDAO value is only updated once per epoch. To compute the index of the next block proposer, the RANDAO value is mixed with the slot number to give a unique value in each slot. The probability of an individual validator being selected is not simply `1/N` (where `N` = total active validators). Instead, it is weighted by the effective ETH balance of each validator. The maximum effective balance is 32 ETH (this means that `balance 32 ETH` does not lead to higher weighting than `balance == 32 ETH`). + +Only one block proposer is selected in each slot. Under normal conditions, a single block producer creates and releases a single block in their dedicated slot. Creating two blocks for the same slot is a slashable offence, often known as "equivocation". + +## How is the block created? + +The block proposer is expected to broadcast a signed beacon block that builds on top of the most recent head of the chain according to the view of their own locally-run fork choice algorithm. The fork choice algorithm applies any queued attestations left over from the previous slot, then finds the block with the greatest accumulated weight of attestations in its history. That block is the parent of the new block created by the proposer. + +The block proposer creates a block by collecting data from its own local database and view of the chain. The contents of the block are shown in the snippet below: + +```rust +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data + graffiti: Bytes32 + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + sync_aggregate: SyncAggregate + execution_payload: ExecutionPayload +``` + +The `randao_reveal` field takes a verifiable random value that the block proposer creates by signing the current epoch number. `eth1_data` is a vote for the block proposer's view of the deposit contract, including the root of the deposit Merkle trie and the total number of deposits that enable new deposits to be verified. `graffiti` is an optional field that can be used to add a message to the block. `proposer_slashings` and `attester_slashings` are fields that contain proof that certain validators have committed slashable offenses according to the proposer's view of the chain. `deposits` is a list of new validator deposits that the block proposer is aware of, and `voluntary_exits` is a list of validators that wish to exit that the block proposer has heard about on the consensus layer gossip network. The `sync_aggregate` is a vector showing which validators were previously assigned to a sync committee (a subset of validators that serve light client data) and participated in signing data. + +The `execution_payload` enables information about transactions to be passed between the execution and consensus clients. The `execution_payload` is a block of execution data that gets nested inside a beacon block. The fields inside the `execution_payload` reflect the block structure outlined in the Ethereum yellow paper, except that there are no ommers and `prev_randao` exists in place of `difficulty`. The execution client has access to a local pool of transactions that it has heard about on its own gossip network. These transactions are executed locally to generate an updated state trie known as a post-state. The transactions are included in the `execution_payload` as a list called `transactions` and the post-state is provided in the `state-root` field. + +All of these data are collected in a beacon block, signed, and broadcast to the block proposer's peers, who propagate it on to their peers, etc. + +Read more about the [anatomy of blocks](/developers/docs/blocks). + +## What happens to the block? + +The block is added to the block proposer's local database and broadcast to peers over the consensus layer gossip network. When a validator receives the block, it verifies the data inside it, including checking that the block has the correct parent, corresponds to the correct slot, that the proposer index is the expected one, that the RANDAO reveal is valid and that the proposer is not slashed. The `execution_payload` is unbundled, and the validator's execution client re-executes the transactions in the list to check the proposed state change. Assuming the block passes all these checks, each validator adds the block to its own canonical chain. The process then starts again in the next slot. + +## Block rewards + +The block proposer receives payment for their work. There is a `base_reward` calculated as a function of the number of active validators and their effective balances. The block proposer then receives a fraction of `base_reward` for every valid attestation included in the block; the more validators attest to the block, the greater the block proposer's reward. There is also a reward for reporting validators that should be slashed, equal to `1/512 * effective balance` for each slashed validator. + +[More on rewards and penalties](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) + +## Further reading + +- [Introduction to blocks](/developers/docs/blocks/) +- [Introduction to proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Ethereum consensus specs](https://github.com/ethereum/consensus-specs) +- [Introduction to Gasper](/developers/docs/consensus-mechanisms/pos/) +- [Upgrading Ethereum](https://eth2book.info/) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Faqs + +## What is proof-of-stake + +Proof-of-stake is a class of algorithm that can provide security to blockchains by ensuring that assets of value are lost by attackers who act dishonestly. Proof-of-stake systems require a set of validators to make some asset available that can be destroyed if the validator engages in some provably dishonest behavior. Ethereum uses a proof-of-stake mechanism to secure the blockchain. + +## How does proof-of-stake compare to proof-of-work? + +Both proof-of-work and proof-of-stake are mechanisms that economically disincentivize malicious actors from spamming or defrauding the network. In both cases, nodes that actively participate in consensus put some asset "into the network" that they will lose if they misbehave. + +In proof-of-work, this asset is energy. The node, known as a miner, runs an algorithm that aims to compute a value faster than any other node. The fastest node has the right to propose a block to the chain. To change the history of the chain or dominate the block proposal, a miner would have to have so much computing power that they always win the race. This is prohibitively expensive and difficult to execute, protecting the chain from attacks. The energy required to "mine" using proof-of-work is a real-world asset that miners pay for. + +Proof-of-stake requires nodes, known as validators, to explicitly submit a crypto asset to a smart contract. If a validator misbehaves, this crypto can be destroyed because they are "staking" their assets directly into the chain instead of indirectly via energy expenditure. + +Proof-of-work is much more energy-hungry because electricity is burned in the mining process. Proof-of-stake, on the other hand, requires only a very small amount of energy - Ethereum validators can even run on a low-powered device such as Raspberry Pi. Ethereum's proof-of-stake mechanism is thought to be more secure than proof-of-work because the cost to attack is greater, and the consequences to an attacker are more severe. + +Proof-of-work versus proof-of-stake is a contentious topic. [Vitalik Buterin's blog](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-are-the-benefits-of-proof-of-stake-as-opposed-to-proof-of-work) and the debate between Justin Drake and Lyn Alden give a good summary of the arguments. + + + +## Is proof-of-stake energy efficient? + +Yes. Nodes on a proof-of-stake network use a tiny amount of energy. A third-party study concluded that the entire proof-of-stake Ethereum network consumes around 0.0026 TWh/yr - about 13,000x less than gaming in the US alone. + +[More on Ethereum's energy consumption](/energy-consumption/). + +## Is proof-of-stake secure? + +Ethereum's proof-of-stake is very secure. The mechanism was researched, developed, and tested rigorously over eight years before going live. The security guarantees are different from proof-of-work blockchains. In proof-of-stake, malicious validators can be actively punished ("slashed") and ejected from the validator set, costing a substantial amount of ETH. Under proof-of-work, an attacker can keep repeating their attack while they have sufficient hash power. It is also more costly to mount equivalent attacks on proof-of-stake Ethereum than under proof-of-work. To affect the liveness of the chain, at least 33% of the total staked ether on the network is required (except in the cases of very sophisticated attacks with an extremely low likelihood of success). To control the contents of future blocks, at least 51% of the total staked ETH is required, and to rewrite history, over 66% of the total stake is needed. The Ethereum protocol would destroy these assets in the 33% or 51% attack scenarios and by social consensus in the 66% attack scenario. + +- [More on defending Ethereum proof-of-stake from attackers](/developers/docs/consensus-mechanisms/pos/attack-and-defense) +- [More on proof-of-stake design](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) + +## Does proof-of-stake make Ethereum cheaper? + +No. The cost to send a transaction (gas fee) is determined by a dynamic fee market that increases with more network demand. The consensus mechanism does not directly influence this. + +[More on gas](/developers/docs/gas). + +## What are nodes, clients and validators? + +Nodes are computers connected to the Ethereum network. Clients are the software they run that turns the computer into a node. There are two types of clients: execution clients and consensus clients. Both are needed to create a node. A validator is an optional add-on to a consensus client that enables the node to participate in proof-of-stake consensus. This means creating and proposing blocks when selected and attesting to blocks they hear about on the network. To run a validator, the node operator must deposit 32 ETH into the deposit contract. + +- [More on nodes and clients](/developers/docs/nodes-and-clients) +- [More on staking](/staking) + +## Is proof-of-stake a new idea? + +No. A user on BitcoinTalk [proposed the basic idea of proof-of-stake](https://bitcointalk.org/index.php?topic=27787.0) as an upgrade to Bitcoin in 2011. It was eleven years before it was ready to implement on Ethereum Mainnet. Some other chains implemented proof-of-stake earlier than Ethereum, but not Ethereum's specific mechanism (known as Gasper). + +## What is special about Ethereum's proof-of-stake? + +Ethereum's proof-of-stake mechanism is unique in its design. It was not the first proof-of-stake mechanism to be designed and implemented, but it is the most robust. The proof-of-stake mechanism is known as "Casper". Casper defines how validators are selected to propose blocks, how and when attestations are made, how attestations are counted, the rewards and penalties given to validators, slashing conditions, failsafe mechanisms such as the inactivity leak, and the conditions for "finality". Finality is the condition that for a block to be considered a permanent part of the canonical chain it must have been voted for by at least 66% of the total staked ETH on the network. Researchers developed Casper specifically for Ethereum, and Ethereum is the first and only blockchain to have implemented it. + +In addition to Casper, Ethereum's proof-of-stake uses a fork choice algorithm called LMD-GHOST. This is required in case a condition arises where two blocks exist for the same slot. This creates two forks of the blockchain. LMD-GHOST picks the one that have the greatest "weight" of attestations. The weight is the number of attestations weighted by the effective balance of the validators. LMD-GHOST is unique to Ethereum. + +The combination of Casper and LMD_GHOST is known as Gasper. + +[More on Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) + +## What is slashing? + +Slashing is the term given to the destruction of some of a validator's stake and the ejection of the validator from the network. The amount of ETH lost in a slashing scales with the number of validators being slashed - this means colluding validators get punished more severely than individuals. + +[More on slashing](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties#slashing) + +## Why do validators need 32 ETH? + +Validators have to stake ETH so that they have something to lose if they misbehave. The reason why they have to stake 32 ETH specifically is to enable nodes to run on modest hardware. If the minimum ETH per validator were lower, then the number of validators and therefore the number of messages that must be processed in each slot would increase, meaning more powerful hardware would be required to run a node. + +## How are validators selected? + +A single validator is pseudo-randomly chosen to propose a block in each slot using an algorithm called RANDAO that mixes a hash from the block proposer with a seed that gets updated every block. This value is used to select a specific validator from the total validator set. The validator selection is fixed two epochs in advance. + +[More on validator selection](/developers/docs/consensus-mechanisms/pos/block-proposal) + +## What is stake grinding? + +Stake grinding is a category of attack on proof-of-stake networks where the attacker tries to bias the validator selection algorithm in favour of their own validators. Stake grinding attacks on RANDAO require about half the total staked ETH. + +[More on stake grinding](https://eth2book.info/altair/part2/building_blocks/randomness/#randao-biasability) + +## What is social slashing? + +Social slashing is the ability of the community to coordinate a fork of the blockchain in response to an attack. It enables the community to recover from an attacker finalizing a dishonest chain. Social slashing can also be used against censorship attacks. + +- [More on social slashing](https://ercwl.medium.com/the-case-for-social-slashing-59277ff4d9c7) +- [Vitalik Buterin on social slashing](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) + +## Will I get slashed? + +As a validator, it is very difficult to get slashed unless you deliberately engage in malicious behavior. Slashing is only implemented in very specific scenarios where validators propose multiple blocks for the same slot or contradict themselves with their attestations - these are very unlikely to arise accidentally. + +[More on slashing conditions](https://eth2book.info/altair/part2/incentives/slashing) + +## What is the nothing-at-stake problem? + +The nothing-at-stake problem is a conceptual issue with some proof-of-stake mechanisms where there are only rewards and no penalties. If there is nothing at stake, a pragmatic validator is equally happy to attest to any, or even multiple, forks of the blockchain, as this increases their rewards. Ethereum gets around this using finality conditions and slashing to ensure one canonical chain. + +[More on the nothing-at-stake problem](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed) + +## What is a fork choice algorithm? + +A fork choice algorithm implements rules determining which chain is the canonical one. Under optimal conditions, there is no need for a fork choice rule because there is only one block proposer per slot and one block to choose from. Occasionally, though, multiple blocks for the same slot or late-arriving information leads to multiple options for how blocks near the head of the chain are organized. In these cases, all clients must implement some rules identically to make sure they all pick the correct sequence of blocks. The fork-choice algorithm encodes these rules. + +Ethereum's fork-choice algorithm is called LMD-GHOST. It picks the fork with the greatest weight of attestations, meaning the one that most staked ETH has voted for. + +[More on LMD-GHOST](/developers/docs/consensus-mechanisms/pos/gasper/#fork-choice) + +## What is finality in proof-of-stake? + +Finality in proof-of-stake is the guarantee that a given block is a permanent part of the canonical chain and cannot be reverted unless there is a consensus failure in which an attacker burns 33% of the total staked ether. This is "crypto-economic" finality, as opposed to "probabilistic finality" which is relevant to proof-of-work blockchains. In probabilistic finality, there are no explicit finalized/non-finalized states for blocks - it simply becomes less and less likely that a block could be removed from the chain as it gets older, and users determine for themselves when they are sufficiently confident that a block is "safe". With crypto-economic finality, pairs of checkpoint blocks have to be voted for by 66% of the staked ether. If this condition is satisfied, blocks between those checkpoints are explicitly "finalized". + +[More on finality](/developers/docs/consensus-mechanisms/pos/#finality) + +## What is "weak subjectivity"? + +Weak subjectivity is a feature of proof-of-stake networks where social information is used to confirm the current state of the blockchain. New nodes or nodes rejoining the network after being offline for a long time can be given a recent state so that the node can see immediately whether they are on the correct chain. These states are known as "weak subjectivity checkpoints" and they can be obtained from other node operators out-of-band, or from block explorers, or from several public endpoints. + +[More on weak subjectivity](/developers/docs/consensus-mechanisms/pos/weak-subjectivity) + +## Is proof-of-stake censorship resistant? + +Censorship resistance is currently hard to prove. However, unlike proof-of-work, proof-of-stake offers the option to coordinate slashings to punish censoring validators. There are upcoming changes to the protocol that separate block builders from block proposers and implement lists of transactions that builders must include in each block. This proposal is known as proper-builder separation and helps to prevent validators from censoring transactions. + +[More on proposer-builder separation](https://notes.ethereum.org/@fradamt/H1TsYRfJc#Original-basic-scheme) + +## Can Ethereum's proof-of-stake system be 51% attacked? + +Yes. Proof-of-stake is vulnerable to 51% attacks, just like proof-of-work. Instead of the attacker requiring 51% of the network's hash power, the attacker requires 51% of the total staked ETH. An attacker that accumulates 51% of the total stake gets to control the fork-choice algorithm. This enables the attacker to censor certain transactions, do short-range reorgs and extract MEV by reordering blocks in their favor. + +[More on attacks on proof-of-stake](/developers/docs/consensus-mechanisms/pos/attack-and-defense) + +## What is social coordination, and why is it needed? + +Social coordination is a last line of defense for Ethereum that would allow an honest chain to be recovered from an attack that finalized dishonest blocks. In this case, the Ethereum community would have to coordinate "out-of-band" and agree to use an honest minority fork, slashing the attacker's validators in the process. This would require apps and exchanges to recognize the honest fork too. + +[Read more on social coordination](/developers/docs/consensus-mechanisms/pos/attack-and-defense#people-the-last-line-of-defense) + +## Do the rich get richer in proof-of-stake? + +The more ETH someone has to stake, the more validators they can run, and the more rewards they can accrue. The rewards scale linearly with the amount of staked ETH, and everyone gets the same percentage return. Proof-of-work enriches the rich more than proof-of-stake because richer miners that buy hardware at scale benefit from economies of scale, meaning the relationship between wealth and reward is non-linear. + +## Is proof-of-stake more centralized than proof-of-work? + +No, proof-of-work tends towards centralization because mining costs increase and price out individuals, then price out small companies, and so on. The current problem with proof-of-stake is the influence of liquid staking derivatives (LSDs). These are tokens representing ETH staked by some provider that anyone can swap on secondary markets without the actual ETH being unstaked. LSDs allow users to stake with less than 32 ETH, but they also create a centralization risk where a few big organizations can end up controlling much of the stake. This is why [solo staking](/staking/solo) is the best option for Ethereum. + +[More on stake centralization in LSDs](https://notes.ethereum.org/@djrtwo/risks-of-lsd) + +## Why can I only stake ETH? + +ETH is Ethereum's native currency. It is essential to have a single currency in which all stakes are denominated, both for accounting effective balances for weighting votes and security. ETH itself is a fundamental component of Ethereum rather than a smart contract. Incorporating other currencies would significantly increase the complexity and decrease the security of staking. + +## Is Ethereum the only proof-of-stake blockchain? + +No, there are several proof-of-stake blockchains. None are identical to Ethereum; Ethereum's proof-of-stake mechanism is unique. + +## What is The Merge? + +The Merge was the moment when Ethereum switched off its proof-of-work-based consensus mechanism and switched on its proof-of-stake-based consensus mechanism. The Merge happened on September 15, 2022. + +[More on The Merge](/roadmap/merge) + +## What are liveness and safety? + +Liveness and safety are the two fundamental security concerns for a blockchain. Liveness is the availability of a finalizing chain. If the chain stops finalizing or users are not able to access it easily, those are liveness failures. Extremely high cost of access could also be considered a liveness failure. Safety refers to how difficult it is to attack the chain - i.e. finalize conflicting checkpoints. + +[Read more in the Casper paper](https://arxiv.org/pdf/1710.09437.pdf) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Gasper + +Gasper is a combination of Casper the Friendly Finality Gadget (Casper-FFG) and the LMD-GHOST fork choice algorithm. Together these components form the consensus mechanism securing proof-of-stake Ethereum. Casper is the mechanism that upgrades certain blocks to "finalized" so that new entrants into the network can be confident that they are syncing the canonical chain. The fork choice algorithm uses accumulated votes to ensure that nodes can easily select the correct one when forks arise in the blockchain. + +**Note** that the original definition of Casper-FFG was updated slightly for inclusion in Gasper. On this page we consider the updated version. + +## Prerequisites + +To understand this material it is necessary to read the introductory page on [proof-of-stake](/developers/docs/consensus-mechanisms/pos/). + +## The role of Gasper + +Gasper sits on top of a proof-of-stake blockchain where nodes provide ether as a security deposit that can be destroyed if they are lazy or dishonest in proposing or validating blocks. Gasper is the mechanism defining how validators get rewarded and punished, decide which blocks to accept and reject, and which fork of the blockchain to build on. + +## What is finality? + +Finality is a property of certain blocks that means they cannot be reverted unless there has been a critical consensus failure and an attacker has destroyed at least 1/3 of the total staked ether. Finalized blocks can be thought of as information the blockchain is certain about. A block must pass through a two-step upgrade procedure for a block to be finalized: + +1. Two-thirds of the total staked ether must have voted in favor of that block's inclusion in the canonical chain. This condition upgrades the block to "justified". Justified blocks are unlikely to be reverted, but they can be under certain conditions. +2. When another block is justified on top of a justified block, it is upgraded to "finalized". Finalizing a block is a commitment to include the block in the canonical chain. It cannot be reverted unless an attacker destroys millions of ether (billions of $USD). + +These block upgrades do not happen in every slot. Instead, only epoch-boundary blocks can be justified and finalized. These blocks are known as "checkpoints". Upgrading considers pairs of checkpoints. A "supermajority link" must exist between two successive checkpoints (i.e. two-thirds of the total staked ether voting that checkpoint B is the correct descendant of checkpoint A) to upgrade the less recent checkpoint to finalized and the more recent block to justified. + +Because finality requires a two-thirds agreement that a block is canonical, an attacker cannot possibly create an alternative finalized chain without: + +1. Owning or manipulating two-thirds of the total staked ether. +2. Destroying at least one-third of the total staked ether. + +The first condition arises because two-thirds of the staked ether is required to finalize a chain. The second condition arises because if two-thirds of the total stake has voted in favor of both forks, then one-third must have voted on both. Double-voting is a slashing condition that would be maximally punished, and one-third of the total stake would be destroyed. As of May 2022, this requires an attacker to burn around $10 billion worth of ether. The algorithm that justifies and finalizes blocks in Gasper is a slightly modified form of [Casper the Friendly Finality Gadget (Casper-FFG)](https://arxiv.org/pdf/1710.09437.pdf). + +### Incentives and Slashing + +Validators get rewarded for honestly proposing and validating blocks. Ether is rewarded and added to their stake. On the other hand, validators that are absent and fail to act when called upon miss out on these rewards and sometimes lose a small portion of their existing stake. However, the penalties for being offline are small and, in most cases, amount to opportunity costs of missing rewards. However, some validator actions are very difficult to do accidentally and signify some malicious intent, such as proposing multiple blocks for the same slot, attesting to multiple blocks for the same slot, or contradicting previous checkpoint votes. These are "slashable" behaviors that are penalized more harshly—slashing results in some portion of the validator's stake being destroyed and the validator being removed from the network of validators. This process takes 36 days. On Day 1, there is an initial penalty of up to 1 ETH. Then the slashed validator's ether slowly drains away across the exit period, but on Day 18, they receive a "correlation penalty", which is larger when more validators are slashed around the same time. The maximum penalty is the entire stake. These rewards and penalties are designed to incentivize honest validators and disincentivize attacks on the network. + +### Inactivity Leak + +As well as security, Gasper also provides "plausible liveness". This is the condition that as long as two-thirds of the total staked ether is voting honestly and following the protocol, the chain will be able to finalize irrespective of any other activity (such as attacks, latency issues, or slashings). Put another way, one-third of the total staked ether must be somehow compromised to prevent the chain from finalizing. In Gasper, there is an additional line of defense against a liveness failure, known as the "inactivity leak". This mechanism activates when the chain has failed to finalize for more than four epochs. The validators that are not actively attesting to the majority chain have their stake gradually drained away until the majority regains two-thirds of the total stake, ensuring that liveness failures are only temporary. + +### Fork choice + +The original definition of Casper-FFG included a fork choice algorithm that imposed the rule: `follow the chain containing the justified checkpoint that has the greatest height` where height is defined as the greatest distance from the genesis block. In Gasper, the original fork choice rule is deprecated in favor of a more sophisticated algorithm called LMD-GHOST. It is important to realize that under normal conditions, a fork choice rule is unnecessary - there is a single block proposer for every slot, and honest validators attest to it. It is only in cases of large network asynchronicity or when a dishonest block proposer has equivocated that a fork choice algorithm is required. However, when those cases do arise, the fork choice algorithm is a critical defense that secures the correct chain. + +LMD-GHOST stands for "latest message-driven greedy heaviest observed sub-tree". This is a jargon-heavy way to define an algorithm that selects the fork with the greatest accumulated weight of attestations as the canonical one (greedy heaviest subtree) and that if multiple messages are received from a validator, only the latest one is considered (latest-message driven). Before adding the heaviest block to its canonical chain, every validator assesses each block using this rule. + +## Further Reading + +- [Gasper: Combining GHOST and Casper](https://arxiv.org/pdf/2003.03052.pdf) +- [Casper the Friendly Finality Gadget](https://arxiv.org/pdf/1710.09437.pdf) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos + +Proof-of-stake (PoS) underlies Ethereum's [consensus mechanism](/developers/docs/consensus-mechanisms/). Ethereum switched on its proof-of-stake mechanism in 2022 because it is more secure, less energy-intensive, and better for implementing new scaling solutions compared to the previous [proof-of-work](/developers/docs/consensus-mechanisms/pow) architecture. + +## Prerequisites + +To better understand this page, we recommend you first read up on [consensus mechanisms](/developers/docs/consensus-mechanisms/). + +## What is proof-of-stake (PoS)? + +Proof-of-stake is a way to prove that validators have put something of value into the network that can be destroyed if they act dishonestly. In Ethereum's proof-of-stake, validators explicitly stake capital in the form of ETH into a smart contract on Ethereum. The validator is then responsible for checking that new blocks propagated over the network are valid and occasionally creating and propagating new blocks themselves. If they try to defraud the network (for example by proposing multiple blocks when they ought to send one or sending conflicting attestations), some or all of their staked ETH can be destroyed. + +## Validators + +To participate as a validator, a user must deposit 32 ETH into the deposit contract and run three separate pieces of software: an execution client, a consensus client, and a validator client. On depositing their ETH, the user joins an activation queue that limits the rate of new validators joining the network. Once activated, validators receive new blocks from peers on the Ethereum network. The transactions delivered in the block are re-executed to check that the proposed changes to Ethereum's state are valid, and the block signature is checked. The validator then sends a vote (called an attestation) in favor of that block across the network. + +Whereas under proof-of-work, the timing of blocks is determined by the mining difficulty, in proof-of-stake, the tempo is fixed. Time in proof-of-stake Ethereum is divided into slots (12 seconds) and epochs (32 slots). One validator is randomly selected to be a block proposer in every slot. This validator is responsible for creating a new block and sending it out to other nodes on the network. Also in every slot, a committee of validators is randomly chosen, whose votes are used to determine the validity of the block being proposed. Dividing the validator set up into committees is important for keeping the network load manageable. Committees divide up the validator set so that every active validator attests in every epoch, but not in every slot. + +## How a Transaction Gets Executed in Ethereum PoS + +The following provides an end-to-end explanation of how a transaction gets executed in Ethereum proof-of-stake. + +1. A user creates and signs a [transaction](/developers/docs/transactions/) with their private key. This is usually handled by a wallet or a library such as [ethers.js](https://docs.ethers.org/v6/), [web3js](https://docs.web3js.org/), [web3py](https://web3py.readthedocs.io/en/v5/) etc but under the hood the user is making a request to a node using the Ethereum [JSON-RPC API](/developers/docs/apis/json-rpc/). The user defines the amount of gas that they are prepared to pay as a tip to a validator to encourage them to include the transaction in a block. The [tips](/developers/docs/gas/#priority-fee) get paid to the validator while the [base fee](/developers/docs/gas/#base-fee) gets burned. +2. The transaction is submitted to an Ethereum [execution client](/developers/docs/nodes-and-clients/#execution-client) which verifies its validity. This means ensuring that the sender has enough ETH to fulfill the transaction and they have signed it with the correct key. +3. If the transaction is valid, the execution client adds it to its local mempool (list of pending transactions) and also broadcasts it to other nodes over the execution layer gossip network. When other nodes hear about the transaction they add it to their local mempool too. Advanced users might refrain from broadcasting their transaction and instead forward it to specialized block builders such as [Flashbots Auction](https://docs.flashbots.net/flashbots-auction/overview). This allows them to organize the transactions in upcoming blocks for maximum profit ([MEV](/developers/docs/mev/#mev-extraction)). +4. One of the validator nodes on the network is the block proposer for the current slot, having previously been selected pseudo-randomly using RANDAO. This node is responsible for building and broadcasting the next block to be added to the Ethereum blockchain and updating the global state. The node is made up of three parts: an execution client, a consensus client and a validator client. The execution client bundles transactions from the local mempool into an "execution payload" and executes them locally to generate a state change. This information is passed to the consensus client where the execution payload is wrapped as part of a "beacon block" that also contains information about rewards, penalties, slashings, attestations etc. that enable the network to agree on the sequence of blocks at the head of the chain. The communication between the execution and consensus clients is described in more detail in [Connecting the Consensus and Execution Clients](/developers/docs/networking-layer/#connecting-clients). +5. Other nodes receive the new beacon block on the consensus layer gossip network. They pass it to their execution client where the transactions are re-executed locally to ensure the proposed state change is valid. The validator client then attests that the block is valid and is the logical next block in their view of the chain (meaning it builds on the chain with the greatest weight of attestations as defined in the [fork choice rules](/developers/docs/consensus-mechanisms/pos/#fork-choice)). The block is added to the local database in each node that attests to it. +6. The transaction can be considered "finalized" if it has become part of a chain with a "supermajority link" between two checkpoints. Checkpoints occur at the start of each epoch and they exist to account for the fact that only a subset of active validators attest in each slot, but all active validators attest across each epoch. Therefore, it is only between epochs that a 'supermajority link' can be demonstrated (this is where 66% of the total staked ETH on the network agrees on two checkpoints). + +More detail on finality can be found below. + +## Finality + +A transaction has "finality" in distributed networks when it is part of a block that can't change without a large amount of ETH getting burned. On proof-of-stake Ethereum, this is managed using "checkpoint" blocks. The first block in each epoch is a checkpoint. Validators vote for pairs of checkpoints that it considers to be valid. If a pair of checkpoints attracts votes representing at least two-thirds of the total staked ETH, the checkpoints are upgraded. The more recent of the two (target) becomes "justified". The earlier of the two is already justified because it was the "target" in the previous epoch. Now it is upgraded to "finalized". + +To revert a finalized block, an attacker would commit to losing at least one-third of the total supply of staked ETH. The exact reason for this is explained in this [Ethereum Foundation blog post](https://blog.ethereum.org/2016/05/09/on-settlement-finality/). Since finality requires a two-thirds majority, an attacker could prevent the network from reaching finality by voting with one-third of the total stake. There is a mechanism to defend against this: the [inactivity leak](https://eth2book.info/bellatrix/part2/incentives/inactivity). This activates whenever the chain fails to finalize for more than four epochs. The inactivity leak bleeds away the staked ETH from validators voting against the majority, allowing the majority to regain a two-thirds majority and finalize the chain. + +## Crypto-economic security + +Running a validator is a commitment. The validator is expected to maintain sufficient hardware and connectivity to participate in block validation and proposal. In return, the validator is paid in ETH (their staked balance increases). On the other hand, participating as a validator also opens new avenues for users to attack the network for personal gain or sabotage. To prevent this, validators miss out on ETH rewards if they fail to participate when called upon, and their existing stake can be destroyed if they behave dishonestly. Two primary behaviors can be considered dishonest: proposing multiple blocks in a single slot (equivocating) and submitting contradictory attestations. + +The amount of ETH slashed depends on how many validators are also being slashed at around the same time. This is known as the ["correlation penalty"](https://eth2book.info/bellatrix/part2/incentives/slashing#the-correlation-penalty), and it can be minor (~1% stake for a single validator slashed on their own) or can result in 100% of the validator's stake getting destroyed (mass slashing event). It is imposed halfway through a forced exit period that begins with an immediate penalty (up to 1 ETH) on Day 1, the correlation penalty on Day 18, and finally, ejection from the network on Day 36. They receive minor attestation penalties every day because they are present on the network but not submitting votes. This all means a coordinated attack would be very costly for the attacker. + +## Fork choice + +When the network performs optimally and honestly, there is only ever one new block at the head of the chain, and all validators attest to it. However, it is possible for validators to have different views of the head of the chain due to network latency or because a block proposer has equivocated. Therefore, consensus clients require an algorithm to decide which one to favor. The algorithm used in proof-of-stake Ethereum is called [LMD-GHOST](https://arxiv.org/pdf/2003.03052.pdf), and it works by identifying the fork that has the greatest weight of attestations in its history. + +## Proof-of-stake and security + +The threat of a [51% attack](https://www.investopedia.com/terms/1/51-attack.asp) still exists on proof-of-stake as it does on proof-of-work, but it's even riskier for the attackers. An attacker would need 51% of the staked ETH. They could then use their own attestations to ensure their preferred fork was the one with the most accumulated attestations. The 'weight' of accumulated attestations is what consensus clients use to determine the correct chain, so this attacker would be able to make their fork the canonical one. However, a strength of proof-of-stake over proof-of-work is that the community has flexibility in mounting a counter-attack. For example, the honest validators could decide to keep building on the minority chain and ignore the attacker's fork while encouraging apps, exchanges, and pools to do the same. They could also decide to forcibly remove the attacker from the network and destroy their staked ETH. These are strong economic defenses against a 51% attack. + +Beyond 51% attacks, bad actors might also attempt other types of malicious activities, such as: + +- long-range attacks (although the finality gadget neutralizes this attack vector) +- short range 'reorgs' (although proposer boosting and attestation deadlines mitigate this) +- bouncing and balancing attacks (also mitigated by proposer boosting, and these attacks have anyway only been demonstrated under idealized network conditions) +- avalanche attacks (neutralized by the fork choice algorithms rule of only considering the latest message) + +Overall, proof-of-stake, as it is implemented on Ethereum, has been demonstrated to be more economically secure than proof-of-work. + +## Pros and cons + +| Pros | Cons | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| Staking makes it easier for individuals to participate in securing the network, promoting decentralization. validator node can be run on a normal laptop. Staking pools allow users to stake without having 32 ETH. | Proof-of-stake is younger and less battle-tested compared to proof-of-work | +| Staking is more decentralized. Economies of scale do not apply in the same way that they do for PoW mining. | Proof-of-stake is more complex to implement than proof-of-work | +| Proof-of-stake offers greater crypto-economic security than proof-of-work | Users need to run three pieces of software to participate in Ethereum's proof-of-stake. | +| Less issuance of new ETH is required to incentivize network participants | | + +### Comparison to proof-of-work + +Ethereum originally used proof-of-work but switched to proof-of-stake in September 2022. PoS offers several advantages over PoW, such as: + +- better energy efficiency – there is no need to use lots of energy on proof-of-work computations +- lower barriers to entry, reduced hardware requirements – there is no need for elite hardware to stand a chance of creating new blocks +- reduced centralization risk – proof-of-stake should lead to more nodes securing the network +- because of the low energy requirement less ETH issuance is required to incentivize participation +- economic penalties for misbehavior make 51% style attacks more costly for an attacker compared to proof-of-work +- the community can resort to social recovery of an honest chain if a 51% attack were to overcome the crypto-economic defenses. + +## Further reading + +- [Proof of Stake FAQ](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html) _Vitalik Buterin_ +- [What is Proof of Stake](https://consensys.net/blog/blockchain-explained/what-is-proof-of-stake/) _ConsenSys_ +- [What Proof of Stake Is And Why It Matters](https://bitcoinmagazine.com/culture/what-proof-of-stake-is-and-why-it-matters-1377531463) _Vitalik Buterin_ +- [Why Proof of Stake (Nov 2020)](https://vitalik.eth.limo/general/2020/11/06/pos2020.html) _Vitalik Buterin_ +- [Proof of Stake: How I Learned to Love Weak Subjectivity](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) _Vitalik Buterin_ +- [Proof-of-stake Ethereum attack and defense](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs) +- [A Proof of Stake Design Philosophy](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) _Vitalik Buterin_ +- [Video: Vitalik buterin explains proof-of-stake to Lex Fridman](https://www.youtube.com/watch?v=3yrqBG-7EVE) + +## Related topics + +- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Keys + +Ethereum secures user assets using public-private key cryptography. The public key is used as the basis for an Ethereum address—that is, it is visible to the general public and used as a unique identifier. The private (or 'secret') key should only ever be accessible to an account owner. The private key is used to 'sign' transactions and data so that cryptography can prove that the holder approves some action of a specific private key. + +Ethereum's keys are generated using [elliptic-curve cryptography](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography). + +However, when Ethereum switched from [proof-of-work](/developers/docs/consensus-mechanisms/pow) to [proof-of-stake](/developers/docs/consensus-mechanisms/pos) a new type of key was added to Ethereum. The original keys still work exactly the same as before—there were no changes to the elliptic-curve-based keys securing accounts. However, users needed a new type of key for participating in proof-of-stake by staking ETH and running validators. This need arose from scalability challenges associated with many messages passing between large numbers of validators that required a cryptographic method that could easily be aggregated to reduce the amount of communication required for the network to come to consensus. + +This new type of key uses the [**Boneh-Lynn-Shacham (BLS)** signature scheme](https://wikipedia.org/wiki/BLS_digital_signature). BLS enables a very efficient aggregation of signatures but also allows reverse engineering of aggregated individual validator keys and is ideal for managing actions between validators. + +## The two types of validator keys + +Before the switch to proof-of-stake, Ethereum users only had a single elliptic-curve-based private key to access their funds. With the introduction of proof-of-stake, users that wished to be solo stakers also required a **validator key** and a **withdrawal key**. + +### The validator key + +The validator signing key consists of two elements: + +- Validator **private** key +- Validator **public** key + +The purpose of the validator private key is to sign onchain operations such as block proposals and attestations. Because of this, these keys must be held in a hot wallet. + +This flexibility has the advantage of moving validator signing keys very quickly from one device to another, however, if they have gotten lost or stolen, a thief may be able to **act maliciously** in a few ways: + +- Get the validator slashed by: + - Being a proposer and signing two different beacon blocks for the same slot + - Being an attester and signing an attestation that "surrounds" another one + - Being an attester and signing two different attestations having the same target +- Force a voluntary exit, which stops the validator from staking, and grants access to its ETH balance to the withdrawal key owner + +The **validator public key** is included in the transaction data when a user deposits ETH to the staking deposit contract. This is known as the _deposit data_ and it allows Ethereum to identify the validator. + +### Withdrawal credentials + +Every validator has a property known as _withdrawal credentials_. This 32-byte field begins with either a `0x00`, representing BLS withdrawal credentials, or a `0x01`, representing credentials that point to an execution address. + +Validators with `0x00` BLS keys must update these credentials to point to an execution address in order to activate excess balance payments or full withdrawal from staking. This can be done by providing an execution address in the deposit data during initial key generation, _OR_ by using the withdrawal key at a later time to sign and broadcast a `BLSToExecutionChange` message. + +### The withdrawal key + +The withdrawal key will be required to update withdrawal credentials to point to an execution address, if not set during initial deposit. This will enable excess balance payments to begin being processed, and will also allow users to fully withdraw their staked ETH. + +Just like the validator keys, the withdrawal keys also consist of two components: + +- Withdrawal **private** key +- Withdrawal **public** key + +Losing this key before updating withdrawal credentials to `0x01` type means losing access to the validator balance. The validator can still sign attestations and blocks since these actions require the validator's private key, however there is little to no incentive if the withdrawal keys are lost. + +Separating the validator keys from the Ethereum account keys enables multiple validators to be run by a single user. + +![validator key schematic](validator-key-schematic.png) + +**Note**: Exiting from staking duties and withdrawing a validator's balance currently requires signing a [voluntary exit message (VEM)](https://mirror.xyz/ladislaus.eth/wmoBbUBes2Wp1_6DvP6slPabkyujSU7MZOFOC3QpErs&1) with the validator key. However, [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) is a proposal that will allow a user to trigger a validator's exit and withdrawals its balance by signing exit messages with the withdrawal key in the future. This will reduce trust assumptions by enabling stakers who delegate ETH to [staking-as-a-service providers](https://ethereum.org/en/staking/saas/#what-is-staking-as-a-service) to remain in control of their funds. + +## Deriving keys from a seed phrase + +If every 32 ETH staked required a new set of 2 completely independent keys, key management would quickly become unwieldy, especially for users running multiple validators. Instead, multiple validator keys can be derived from a single common secret and storing that single secret allows access to multiple validator keys. + +[Mnemonics](https://en.bitcoinwiki.org/wiki/Mnemonic_phrase) and paths are prominent features that users often encounter when [they access](https://ethereum.stackexchange.com/questions/19055/what-is-the-difference-between-m-44-60-0-0-and-m-44-60-0) their wallets. The mnemonic is a sequence of words that act as an initial seed for a private key. When combined with additional data, the mnemonic generates a hash known as the 'master key'. This can be thought of as the root of a tree. Branches from this root can then be derived using a hierarchical path so that child nodes can exist as combinations of their parent node's hash and their index in the tree. Read about [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-19](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) standards for mnemonic-based key generation. + +These paths have the following structure, which will be familiar to users who have interacted with hardware wallets: + +``` +m/44'/60'/0'/0` +``` + +The slashes in this path separate components of the private key as follows: + +``` +master_key / purpose / coin_type / account / change / address_index +``` + +This logic enables users to attach as many validators as possible to a single **mnemonic phrase** because the tree root can be common, and differentiation can happen at the branches. The user can **derive any number of keys** from the mnemonic phrase. + +``` + [m / 0] + / + / +[m] - [m / 1] + \ + \ + [m / 2] +``` + +Each branch is separated by a `/` so `m/2` means start with the master key and follow branch 2. In the schematic below a single mnemonic phrase is used to store three withdrawal keys, each with two associated validators. + +![validator key logic](multiple-keys.png) + +## Further reading + +- [Ethereum Foundation blog post by Carl Beekhuizen](https://blog.ethereum.org/2020/05/21/keys/) +- [EIP-2333 BLS12-381 key generation](https://eips.ethereum.org/EIPS/eip-2333) +- [EIP-7002: Execution Layer Triggered Exits](https://research.2077.xyz/eip-7002-unpacking-improvements-to-staking-ux-post-merge) +- [Key management at scale](https://docs.ethstaker.cc/ethstaker-knowledge-base/scaled-node-operators/key-management-at-scale) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Pos Vs Pow + +When Ethereum launched, proof-of-stake still needed a lot of research and development before it could be trusted to secure Ethereum. Proof-of-work was a simpler mechanism that had already been proven by Bitcoin, meaning core developers could implement it right away to get Ethereum launched. It took a further eight years to develop proof-of-stake to the point where it could be implemented. + +This page explains the rationale behind Ethereum's switch to proof-of-stake from proof-of-work and the trade-offs involved. + +## Security + +Ethereum researchers consider proof-of-stake more secure than proof-of-work. However, it has only recently been implemented for the real Ethereum Mainnet and is less time-proven than proof-of-work. The following sections discuss the pros and cons of proof-of-stake's security model compared to proof-of-work. + +### Cost to attack + +In proof-of-stake, validators are required to escrow ("stake") at least 32 ETH in a smart contract. Ethereum can destroy staked ether to punish validators that misbehave. To come to consensus, at least 66% of the total staked ether has to vote in favour of a particular set of blocks. Blocks voted for by >=66% of the stake become "finalized", meaning they can't be removed or reorganized. + +Attacking the network can mean preventing the chain from finalizing or ensuring a certain organization of blocks in the canonical chain that somehow benefits an attacker. This requires the attacker to divert the path of honest consensus either by accumulating a large amount of ether and voting with it directly or tricking honest validators into voting in a particular way. Sophisticated, low-probability attacks that trick honest validators aside, the cost to attack Ethereum is the cost of the stake that an attacker has to accumulate to influence consensus in their favour. + +The lowest cost of attack is >33% of the total stake. An attacker holding >33% of the total stake can cause a finality delay simply by going offline. This is a relatively minor problem for the network as there is a mechanism known as the "inactivity leak" that leaks stake away from offline validators until the online majority represents 66% of the stake and can finalize the chain again. It is also theoretically possible for an attacker to cause double finality with a little over 33% of the total stake by creating two blocks instead of one when they are asked to be a block producer and then double-vote with all of their validators. Each fork only requires 50% of the remaining honest validators to see each block first, so if they manage to time their messages just right, they may be able to finalize both forks. This has a low likelihood of success, but if an attacker was able to cause double-finality, the Ethereum community would have to decide to follow one fork, in which case the attacker's validators would necessarily be slashed on the other. + +With >33% of the total stake, an attacker has a chance to have a minor (finality delay) or more severe (double finality) effect on the Ethereum network. With more than 14,000,000 ETH staked on the network and a representative price of $1000/ETH, the minimum cost to mount these attacks is `1000 x 14,000,000 x 0.33 = $4,620,000,000`. The attacker would lose this money through slashing and get ejected from the network. To attack again, they would have to accumulate >33% of the stake (again) and burn it (again). Each attempt to attack the network would cost >$4.6 billion (at $1000/ETH and 14M ETH staked). The attacker is also ejected from the network when they are slashed, and they have to join an activation queue to rejoin. This means the rate of a repeat attack is limited not only to the rate the attacker can accumulate >33% of the total stake but also the time it takes to onboard all their validators onto the network. Each time the attacker attacks, they get much poorer, and the rest of the community gets richer, thanks to the resulting supply shock. + +Other attacks, such as 51% attacks or finality reversion with 66% of the total stake, require substantially more ETH and are much more costly to the attacker. + +Compare this to proof-of-work. The cost of launching an attack on proof-of-work Ethereum was the cost of consistently owning >50% of the total network hash rate. This amounted to the hardware and running costs of sufficient computing power to outcompete other miners to compute proof-of-work solutions consistently. Ethereum was mostly mined using GPUs rather than ASICs, which kept the cost down (although had Ethereum stayed on proof-of-work, ASIC mining may have become more popular). An adversary would have to purchase a lot of hardware and pay for the electricity to run it to attack a proof-of-work Ethereum network, but the total cost would be less than the cost required to accumulate enough ETH to launch an attack. A 51% attack is ~[20x less](https://youtu.be/1m12zgJ42dI?t=1562) expensive on proof-of-work than proof-of-stake. If the attack was detected and the chain hard-forked to remove their changes, the attacker could repeatedly use the same hardware to attack the new fork. + +### Complexity + +Proof-of-stake is much more complex than proof-of-work. This could be a point in favour of proof-of-work as it is harder to introduce bugs or unintended effects into simpler protocols accidentally. However, the complexity has been tamed by years of research and development, simulations, and testnet implementations. The proof-of-stake protocol has been independently implemented by five separate teams (on each of the execution and consensus layers) in five programming languages, providing resilience against client bugs. + +To safely develop and test the proof-of-stake consensus logic, the Beacon Chain was launched two years before proof-of-stake was implemented on Ethereum Mainnet. The Beacon Chain acted as a sandbox for proof-of-stake testing, as it was a live blockchain implementing the proof-of-stake consensus logic but without touching real Ethereum transactions - effectively just coming to consensus on itself. Once this had been stable and bug-free for a sufficient time, the Beacon Chain was "merged" with Ethereum Mainnet. This all contributed to taming the complexity of proof-of-stake to the point that the risk of unintended consequences or client bugs was very low. + +### Attack surface + +Proof-of-stake is more complex than proof-of-work, which means there are more potential attack vectors to handle. Instead of one peer-to-peer network connecting clients, there are two, each implementing a separate protocol. Having one specific validator pre-selected to propose a block in each slot creates the potential for denial-of-service where large amounts of network traffic knock that specific validator offline. + +There are also ways that attackers can carefully time the release of their blocks or attestations so that they are received by a certain proportion of the honest network, influencing them to vote in certain ways. Finally, an attacker can simply accumulate sufficient ETH to stake and dominate the consensus mechanism. Each of these [attack vectors has associated defenses](/developers/docs/consensus-mechanisms/pos/attack-and-defense), but they do not exist to be defended under proof-of-work. + +## Decentralization + +Proof-of-stake is more decentralized than proof-of-work because mining hardware arms races tend to price out individuals and small organizations. While anyone can technically start mining with modest hardware, their likelihood of receiving any reward is vanishingly small compared to institutional mining operations. With proof-of-stake, the cost of staking and the percentage return on that stake are the same for everyone. It currently costs 32 ETH to run a validator. + +On the other hand, the invention of liquid staking derivatives has led to centralization concerns because a few large providers manage large amounts of staked ETH. This is problematic and needs to be corrected as soon as possible, but it is also more nuanced than it seems. Centralized staking providers do not necessarily have centralized control of validators - often it is just a way to create a central pool of ETH that many independent node operators can stake without every participant requiring 32 ETH of their own. + +The best option for Ethereum is for validators to be run locally on home computers, maximizing decentralization. This is why Ethereum resists changes that increase the hardware requirements for running a node/validator. + +## Sustainability + +Proof-of-stake is a carbon-cheap way to secure the blockchain. Under proof-of-work miners compete for the right to mine a block. Miners are more successful when they can perform calculations faster, incentivizing investment in hardware and energy consumption. This was observed for Ethereum before it switched to proof-of-stake. Shortly before the transition to proof-of-stake, Ethereum was consuming approximately 78 TWh/yr - as much as a small country. However, switching to proof-of-stake reduced this energy expenditure by ~99.98%. Proof-of-stake made Ethereum an energy-efficient, low carbon platform. + +[More on Ethereum's energy consumption](/energy-consumption) + +## Issuance + +Proof-of-stake Ethereum can pay for its security by issuing far fewer coins than proof-of-work Ethereum because validators do not have to pay high electricity costs. As a result, ETH can reduce its inflation or even become deflationary when large amounts of ETH are burned. Lower inflation levels mean Ethereum's security is cheaper than it was under proof-of-work. + +## More of a visual learner? + +Watch Justin Drake explain the benefits of proof-of-stake over proof-of-work: + + + +## Further reading + +- [Vitalik's proof-of-stake design philosophy](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) +- [Vitalik's proof-of-stake FAQs](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) +- ["Simply Explained" video on pos vs pow](https://www.youtube.com/watch?v=M3EFi_POhps) + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Rewards And Penalties + +Ethereum is secured using its native cryptocurrency, ether (ETH). Node operators that wish to participate in validating blocks and identifying the head of the chain, deposit ether into the [deposit contract](/staking/deposit-contract/) on Ethereum. They are then paid in ether to run validator software that checks the validity of new blocks received over the peer-to-peer network and apply the fork-choice algorithm to identify the head of the chain. + +There are two primary roles for a validator: 1) checking new blocks and “attesting” to them if they are valid, 2) proposing new blocks when selected at random from the total validator pool. If the validator fails to do either of these tasks when asked they miss out on an ether payout. Validators are also sometimes tasked with signature aggregation and participating in sync committees. + +There are also some actions that are very difficult to do accidentally and signify some malicious intent, such as proposing multiple blocks for the same slot or attesting to multiple blocks for the same slot. These are “slashable” behaviors that result in the validator having some amount of ether (up to 1 ETH) burned before the validator is removed from the network, which takes 36 days. The slashed validator’s ether slowly drains away across the exit period, but on Day 18 they receive a “correlation penalty” which is larger when more validators are slashed around the same time. The consensus mechanism’s incentive structure therefore pays for honesty and punishes bad actors. + +All rewards and penalties are applied once per epoch. + +Read on for more details... + +## Rewards and penalties + +### Rewards + +Validators receive rewards when they make votes that are consistent with the majority of other validators, when they propose blocks, and when they participate in sync committees. The value of the rewards in each epoch are calculated from a `base_reward`. This is the base unit that other rewards are calculated from. The `base_reward` represents the average reward received by a validator under optimal conditions per epoch. This is calculated from the validator's effective balance and the total number of active validators as follows: + +``` +base_reward = effective_balance * (base_reward_factor / (base_rewards_per_epoch * sqrt(sum(active_balance)))) +``` + +where `base_reward_factor` is 64, `base_rewards_per_epoch` is 4 and `sum(active balance)` is the total staked ether across all active validators. + +This means the base reward is proportional to the validator's effective balance and inversely proportional to the number of validators on the network. The more validators, the greater the overall issuance (as `sqrt(N)` but the smaller the `base_reward` per validator (as `1/sqrt(N)`). These factors influence the APR for a staking node. Read the rationale for this in [Vitalik's notes](https://notes.ethereum.org/@vbuterin/rkhCgQteN?type=view#Base-rewards). + +The total reward is then calculated as the sum of five components that each have a weighting that determines how much each component adds to the total reward. The components are: + +``` +1. source vote: the validator has made a timely vote for the correct source checkpoint +2. target vote: the validator has made a timely vote for the correct target checkpoint +3. head vote: the validator has made a timely vote for the correct head block +4. sync committee reward: the validator has participated in a sync committee +5. proposer reward: the validator has proposed a block in the correct slot +``` + +The weightings for each component are as follows: + +``` +TIMELY_SOURCE_WEIGHT uint64(14) +TIMELY_TARGET_WEIGHT uint64(26) +TIMELY_HEAD_WEIGHT uint64(14) +SYNC_REWARD_WEIGHT uint64(2) +PROPOSER_WEIGHT uint64(8) +``` + +These weights sum to 64. The reward is calculated as the sum of the applicable weights divided by 64. A validator that has made timely source, target and head votes, proposed a block and participated in a sync committee could receive `64/64 * base_reward == base_reward`. However, a validator is not usually a block proposer, so their maximum reward is `64-8 /64 * base_reward == 7/8 * base_reward`. Validators that are neither block proposers nor in a sync committee can receive `64-8-2 / 64 * base_reward == 6.75/8 * base_reward`. + +An additional reward is added to incentivize rapid attestations. This is the `inclusion_delay_reward`. This has a value equal to the `base_reward` multiplied by `1/delay` where `delay` is the number of slots separating the block proposal and attestation. For example, if the attestation is submitted within one slot of the block proposal the attestor receives `base_reward * 1/1 == base_reward`. If the attestation arrives in the next slot, the attestor receives `base_reward * 1/2` and so on. + +Block proposers receive `8 / 64 * base_reward` for **each valid attestation** included in the block, so the actual value of the reward scales with the number of attesting validators. Block proposers can also increase their reward by including evidence of misbehavior by other validators in their proposed block. These rewards are the "carrots" that encourage validator honesty. A block proposer which includes slashing will be rewarded with the `slashed_validators_effective_balance / 512`. + +### Penalties + +So far we have considered perfectly well-behaved validators, but what about validators that do not make timely head, source and target votes or do so slowly? + +The penalties for missing the target and source votes are equal to the rewards the attestor would have received had they submitted them. This means that instead of having the reward added to their balance, they have an equal value removed from their balance. There is no penalty for missing the head vote (i.e. head votes are only rewarded, never penalized). There is no penalty associated with the `inclusion_delay` - the reward will simply not be added to the validator's balance. There is also no penalty for failing to propose a block. + +Read more about rewards and penalties in the [consensus specs](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md). Rewards and penalties were adjusted in the Bellatrix upgrade - watch Danny Ryan and Vitalik discuss this in this [Peep an EIP video](https://www.youtube.com/watch?v=iaAEGs1DMgQ). + +## Slashing + +Slashing is a more severe action that results in the forceful removal of a validator from the network and an associated loss of their staked ether. There are three ways a validator can be slashed, all of which amount to the dishonest proposal or attestation of blocks: + +- By proposing and signing two different blocks for the same slot +- By attesting to a block that "surrounds" another one (effectively changing history) +- By "double voting" by attesting to two candidates for the same block + +If these actions are detected, the validator is slashed. This means that 0.0078125 is immediately burned for a 32 ETH validator (scaled linearly with active balance), then a 36 day removal period begins. During this removal period the validator's stake gradually bleeds away. At the mid-point (Day 18) an additional penalty is applied whose magnitude scales with the total staked ether of all slashed validators in the 36 days prior to the slashing event. This means that when more validators are slashed, the magnitude of the slash increases. The maximum slash is the full effective balance of all slashed validators (i.e. if there are lots of validators being slashed they could lose their entire stake). On the other hand, a single, isolated slashing event only burns a small portion of the validator's stake. This midpoint penalty that scales with the number of slashed validators is called the "correlation penalty". + +## Inactivity leak + +If the consensus layer has gone more than four epochs without finalizing, an emergency protocol called the "inactivity leak" is activated. The ultimate aim of the inactivity leak is to create the conditions required for the chain to recover finality. As explained above, finality requires a 2/3 majority of the total staked ether to agree on source and target checkpoints. If validators representing more than 1/3 of the total validators go offline or fail to submit correct attestations then it is not possible for a 2/3 supermajority to finalize checkpoints. The inactivity leak lets the stake belonging to the inactive validators gradually bleed away until they control less than 1/3 of the total stake, allowing the remaining active validators finalize the chain. However large the pool of inactive validators, the remaining active validators will eventually control >2/3 of the stake. The loss of stake is a strong incentive for inactive validators to reactivate as soon as possible! An inactivity leak scenario was encountered on the Medalla testnet when < 66% of active validators were able to come to consensus on the current head of the blockchain. The inactivity leak was activated and finality was eventually regained! + +The reward, penalty and slashing design of the consensus mechanism encourages individual validators to behave correctly. However, from these design choices emerges a system that strongly incentivizes equal distribution of validators across multiple clients, and should strongly disincentivize single-client dominance. + +## Further reading + +- [Upgrading Ethereum: The incentive layer](https://eth2book.info/altair/part2/incentives) +- [Incentives in Ethereum's hybrid Casper protocol](https://arxiv.org/pdf/1903.04205.pdf) +- [Vitalik's annotated spec](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#rewards-and-penalties-1) +- [Eth2 Slashing Prevention Tips](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) +- [EIP-7251 Explained: Increasing Maximum Effective Balance For Validators](https://research.2077.xyz/eip-7251_Increase_MAX_EFFECTIVE_BALANCE) +- [Analysis of slashing penalties under EIP-7251](https://ethresear.ch/t/slashing-penalty-analysis-eip-7251/16509) + +_Sources_ + +- _[https://benjaminion.xyz/eth2-annotated-spec/phase0/beacon-chain/](https://benjaminion.xyz/eth2-annotated-spec/phase0/beacon-chain/)_ + +--- + +## Developers > Docs > Consensus Mechanisms > Pos > Weak Subjectivity + +Subjectivity in blockchains refers to reliance upon social information to agree on the current state. There may be multiple valid forks that are chosen from according to information gathered from other peers on the network. The converse is objectivity which refers to chains where there is only one possible valid chain that all nodes will necessarily agree upon by applying their coded rules. There is also a third state, known as weak subjectivity. This refers to a chain that can progress objectively after some initial seed of information is retrieved socially. + +## Prerequisites + +To understand this page it is necessary to first understand the fundamentals of [proof-of-stake](/developers/docs/consensus-mechanisms/pos/). + +## What problems does weak subjectivity solve? + +Subjectivity is inherent to proof-of-stake blockchains because selecting the correct chain from multiple forks is done by counting historical votes. This exposes the blockchain to several attack vectors, including long-range attacks whereby nodes that participated very early in the chain maintain an alternative fork that they release much later to their own advantage. Alternatively, if 33% of validators withdraw their stake but continue to attest and produce blocks, they might generate an alternative fork that conflicts with the canonical chain. New nodes or nodes that have been offline for a long time might not be aware that these attacking validators have withdrawn their funds, so attackers could trick them into following an incorrect chain. Ethereum can solve these attack vectors by imposing constraints that diminish the subjective aspects of the mechanism—and therefore trust assumptions—to the bare minimum. + +## Weak subjectivity checkpoints + +Weak subjectivity is implemented in proof-of-stake Ethereum by using "weak subjectivity checkpoints". These are state roots that all nodes on the network agree belong in the canonical chain. They serve the same "universal truth" purpose as genesis blocks, except that they do not sit at the genesis position in the blockchain. The fork choice algorithm trusts that the blockchain state defined in that checkpoint is correct and that it independently and objectively verifies the chain from that point onwards. The checkpoints act as "revert limits" because blocks located before weak-subjectivity checkpoints cannot be changed. This undermines long-range attacks simply by defining long-range forks to be invalid as part of the mechanism design. Ensuring that the weak subjectivity checkpoints are separated by a smaller distance than the validator withdrawal period ensures that a validator that forks the chain is slashed at least some threshold amount before they can withdraw their stake and that new entrants cannot be tricked onto incorrect forks by validators whose stake has been withdrawn. + +## Difference between weak subjectivity checkpoints and finalized blocks + +Finalized blocks and weak subjectivity checkpoints are treated differently by Ethereum nodes. If a node becomes aware of two competing finalized blocks, then it is torn between the two - it has no way to identify automatically which is the canonical fork. This is symptomatic of a consensus failure. In contrast, a node simply rejects any block that conflicts with its weak subjectivity checkpoint. From the node's perspective, the weak subjectivity checkpoint represents an absolute truth that cannot be undermined by new knowledge from its peers. + +## How weak is weak? + +The subjective aspect of Ethereum's proof-of-stake is the requirement for a recent state (weak subjectivity checkpoint) from a trusted source to sync from. The risk of getting a bad weak subjectivity checkpoint is very low because they can be checked against several independent public sources such as block explorers or multiple nodes. However, there is always some degree of trust required to run any software application, for example, trusting that the software developers have produced honest software. + +A weak subjectivity checkpoint may even come as part of the client software. Arguably an attacker can corrupt the checkpoint in the software and can just as easily corrupt the software itself. There is no real crypto-economic route around this problem, but the impact of untrustworthy developers is minimized in Ethereum by having multiple independent client teams, each building equivalent software in different languages, all with a vested interest in maintaining an honest chain. Block explorers may also provide weak subjectivity checkpoints or a way to cross-reference checkpoints obtained from elsewhere against an additional source. + +Finally, checkpoints can be requested from other nodes; perhaps another Ethereum user that runs a full node can provide a checkpoint that validators can then verify against data from a block explorer. Overall, trusting the provider of a weak subjectivity checkpoint can be considered as problematic as trusting the client developers. The overall trust required is low. It is important to note that these considerations only become important in the very unlikely event that a majority of validators conspire to produce an alternate fork of the blockchain. Under any other circumstances, there is only one Ethereum chain to choose from. + +## Further Reading + +- [Weak subjectivity in Eth2](https://notes.ethereum.org/@adiasg/weak-subjectvity-eth2) +- [Vitalik: How I learned to love weak subjectivity](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) +- [Weak subjectivity (Teku docs)](https://docs.teku.consensys.net/en/latest/Concepts/Weak-Subjectivity/) +- [Phase-0 Weak subjectivity guide](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/weak-subjectivity.md) +- [Analysis of weak subjectivity in Ethereum 2.0](https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf) + +--- + +## Developers > Docs > Consensus Mechanisms > Pow + +The Ethereum network began by using a consensus mechanism that involved **[Proof-of-work (PoW)](/developers/docs/consensus-mechanisms/pow)**. This allowed the nodes of the Ethereum network to agree on the state of all information recorded on the Ethereum blockchain and prevented certain kinds of economic attacks. However, Ethereum switched off proof-of-work in 2022 and started using [proof-of-stake](/developers/docs/consensus-mechanisms/pos) instead. + + + Proof-of-work has now been deprecated. Ethereum no longer uses proof-of-work as part of its consensus mechanism. Instead, it uses proof-of-stake. Read more on proof-of-stake and staking. + + +## Prerequisites + +To better understand this page, we recommend you first read up on [transactions](/developers/docs/transactions/), [blocks](/developers/docs/blocks/), and [consensus mechanisms](/developers/docs/consensus-mechanisms/). + +## What is Proof-of-work (PoW)? + +Nakamoto consensus, which utilizes proof-of-work, is the mechanism that once allowed the decentralized Ethereum network to come to consensus (i.e. all nodes agree) on things like account balances and the order of transactions. This prevented users from "double spending" their coins and ensured that the Ethereum chain was tremendously difficult to attack or manipulate. These security properties now come from proof-of-stake instead using the consensus mechanism known as [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/). + +## Proof-of-work and mining + +Proof-of-work is the underlying algorithm that sets the difficulty and rules for the work miners do on proof-of-work blockchains. Mining is the "work" itself. It's the act of adding valid blocks to the chain. This is important because the chain's length helps the network follow the correct fork of the blockchain. The more "work" done, the longer the chain, and the higher the block number, the more certain the network can be of the current state of things. + +[More on mining](/developers/docs/consensus-mechanisms/pow/mining/) + +## How did Ethereum's proof-of-work work? + +Ethereum transactions are processed into blocks. In the now-deprecated proof-of-work Ethereum, each block contained: + +- block difficulty – for example: 3,324,092,183,262,715 +- mixHash – for example: `0x44bca881b07a6a09f83b130798072441705d9a665c5ac8bdf2f39a3cdf3bee29` +- nonce – for example: `0xd3ee432b4fb3d26b` + +This block data was directly related to proof-of-work. + +### The work in proof-of-work + +The proof-of-work protocol, Ethash, required miners to go through an intense race of trial and error to find the nonce for a block. Only blocks with a valid nonce could be added to the chain. + +When racing to create a block, a miner repeatedly put a dataset, that could only be obtained by downloading and running the full chain (as a miner does), through a mathematical function. The dataset was used to generate a mixHash below a target that is dictated by the block difficulty. The best way to do this is through trial and error. + +The difficulty determined the target for the hash. The lower the target, the smaller the set of valid hashes. Once generated, this was incredibly easy for other miners and clients to verify. Even if one transaction were to change, the hash would be completely different, signalling fraud. + +Hashing makes fraud easy to spot. But proof-of-work as a process was also a big deterrent to attacking the chain. + +### Proof-of-work and security + +Miners were incentivized to do this work on the main Ethereum chain. There was little incentive for a subset of miners to start their own chain—it undermines the system. Blockchains rely on having a single state as a source of truth. + +The objective of proof-of-work was to extend the chain. The longest chain was most believable as the valid one because it had the most computational work done to generate it. Within Ethereum's PoW system, it was nearly impossible to create new blocks that erase transactions, create fake ones, or maintain a second chain. That's because a malicious miner would have needed to always solve the block nonce faster than everyone else. + +To consistently create malicious yet valid blocks, a malicious miner would have needed over 51% of the network mining power to beat everyone else. That amount of "work" requires a lot of expensive computing power and the energy spent might even have outweighed the gains made in an attack. + +### Proof-of-work economics + +Proof-of-work was also responsible for issuing new currency into the system and incentivizing miners to do the work. + +Since the [Constantinople upgrade](/history/#constantinople), miners who successfully create a block were rewarded with two freshly minted ETH and part of the transaction fees. Ommer blocks also compensated 1.75 ETH. Ommer blocks were valid blocks created by a miner practically at the same time as another miner created the canonical block, which was ultimately determined by which chain was built on top of first. Ommer blocks usually happened due to network latency. + +## Finality + +A transaction has "finality" on Ethereum when it's part of a block that can't change. + +Because miners worked in a decentralized way, two valid blocks could be mined at the same time. This creates a temporary fork. Eventually, one of these chains became the accepted chain after subsequent blocks were mined and added to it, making it longer. + +To complicate things further, transactions rejected on the temporary fork may not have been included in the accepted chain. This means it could get reversed. So finality refers to the time you should wait before considering a transaction irreversible. Under the previous proof-of-work Ethereum, the more blocks were mined on top of a specific block `N`, the higher confidence that the transactions in `N` were successful and would not be reverted. Now, with proof-of-stake, finalization is an explicit, rather than probabilistic, property of a block. + +## Proof-of-work energy-usage + +A major criticism of proof-of-work is the amount of energy output required to keep the network safe. To maintain security and decentralization, Ethereum on proof-of-work consumed large amounts of energy. Shortly before switching to proof-of-stake, Ethereum miners were collectively consuming about 70 TWh/yr (about the same as the Czech Republic - according to [digiconomist](https://digiconomist.net/) on 18-July-2022). + +## Pros and cons + +| Pros | Cons | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| Proof-of-work is neutral. You don't need ETH to get started and block rewards allow you to go from 0ETH to a positive balance. With [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) you need ETH to start with. | Proof-of-work uses up so much energy that it's bad for the environment. | +| Proof-of-work is a tried and tested consensus mechanism that has kept Bitcoin and Ethereum secure and decentralized for many years. | If you want to mine, you need such specialized equipment that it's a big investment to start. | +| Compared to proof-of-stake it's relatively easy to implement. | Due to increasing computation needed, mining pools could potentially dominate the mining game, leading to centralization and security risks. | + +## Compared to proof-of-stake + +At a high level, proof-of-stake has the same end goal as proof-of-work: to help the decentralized network reach consensus securely. But it has some differences in process and personnel: + +- Proof-of-stake switches out the importance of computational power for staked ETH. +- Proof-of-stake replaces miners with validators. Validators stake their ETH to activate the ability to create new blocks. +- Validators don't compete to create blocks, instead they are chosen at random by an algorithm. +- Finality is clearer: at certain checkpoints, if 2/3 validators agree on the state of the block it is considered final. Validators must bet their entire stake on this, so if they try to collude down the line, they'll lose their entire stake. + +[More on proof-of-stake](/developers/docs/consensus-mechanisms/pos/) + +## More of a visual learner? + + + +## Further Reading + +- [Majority attack](https://en.bitcoin.it/wiki/Majority_attack) +- [On settlement finality](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) + +### Videos + +- [A technical explanation of proof-of-work protocols](https://youtu.be/9V1bipPkCTU) + +## Related Topics + +- [Mining](/developers/docs/consensus-mechanisms/pow/mining/) +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos/) +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) + +--- + +## Developers > Docs > Consensus Mechanisms > Pow > Mining + +Proof-of-work is no longer underlying Ethereum's consensus mechanism, meaning mining has been switched off. Instead, Ethereum is secured by validators who stake ETH. You can start staking your ETH today. Read more on The Merge, proof-of-stake, and staking. This page is for historical interest only. + + +## Prerequisites + +To better understand this page, we recommend you first read up on [transactions](/developers/docs/transactions/), [blocks](/developers/docs/blocks/) and [proof-of-work](/developers/docs/consensus-mechanisms/pow/). + +## What is Ethereum mining? + +Mining is the process of creating a block of transactions to be added to the Ethereum blockchain in Ethereum's now-deprecated proof-of-work architecture. + +The word mining originates in the context of the gold analogy for cryptocurrencies. Gold or precious metals are scarce, so are digital tokens, and the only way to increase the total volume in a proof-of-work system is through mining. In proof-of-work Ethereum, the only mode of issuance was via mining. Unlike gold or precious metals however, Ethereum mining was also the way to secure the network by creating, verifying, publishing and propagating blocks in the blockchain. + +Mining ether = Securing the Network + +Mining is the lifeblood of any proof-of-work blockchain. Ethereum miners - computers running software - used their time and computation power to process transactions and produce blocks prior to the transition to proof-of-stake. + +## Why do miners exist? + +In decentralized systems like Ethereum, we need to ensure that everyone agrees on the order of transactions. Miners helped this happen by solving computationally difficult puzzles to produce blocks, securing the network from attacks. + +[More on proof-of-work](/developers/docs/consensus-mechanisms/pow/) + +Anyone was previously able to mine on the Ethereum network using their computer. However, not everyone could mine ether (ETH) profitably. In most cases, miners had to purchase dedicated computer hardware, and have access to inexpensive energy sources. The average computer was unlikely to earn enough block rewards to cover the associated costs of mining. + +### Cost of mining + +- Potential costs of the hardware necessary to build and maintain a mining rig +- Electrical cost of powering the mining rig +- If you were mining in a pool, these pools typically charged a flat % fee of each block generated by the pool +- Potential cost of equipment to support mining rig (ventilation, energy monitoring, electrical wiring, etc.) + +To further explore mining profitability, use a mining calculator, such as the one [Etherscan](https://etherscan.io/ether-mining-calculator) provides. + +## How Ethereum transactions were mined + +The following provides an overview of how transactions were mined in Ethereum proof-of-work. An analogous description of this process for Ethereum proof-of-stake can be found [here](/developers/docs/consensus-mechanisms/pos/#transaction-execution-ethereum-pos). + +1. A user writes and signs a [transaction](/developers/docs/transactions/) request with the private key of some [account](/developers/docs/accounts/). +2. The user broadcasts the transaction request to the entire Ethereum network from some [node](/developers/docs/nodes-and-clients/). +3. Upon hearing about the new transaction request, each node in the Ethereum network adds the request to their local mempool, a list of all transaction requests they’ve heard about that have not yet been committed to the blockchain in a block. +4. At some point, a mining node aggregates several dozen or hundred transaction requests into a potential [block](/developers/docs/blocks/), in a way that maximizes the [transaction fees](/developers/docs/gas/) they earn while still staying under the block gas limit. The mining node then: + 1. Verifies the validity of each transaction request (i.e. no one is trying to transfer ether out of an account they haven’t produced a signature for, the request is not malformed, etc.), and then executes the code of the request, altering the state of their local copy of the EVM. The miner awards the transaction fee for each such transaction request to their own account. + 2. Begins the process of producing the proof-of-work “certificate of legitimacy” for the potential block, once all transaction requests in the block have been verified and executed on the local EVM copy. +5. Eventually, a miner will finish producing a certificate for a block which includes our specific transaction request. The miner then broadcasts the completed block, which includes the certificate and a checksum of the claimed new EVM state. +6. Other nodes hear about the new block. They verify the certificate, execute all transactions on the block themselves (including the transaction originally broadcasted by our user), and verify that the checksum of their new EVM state after the execution of all transactions matches the checksum of the state claimed by the miner’s block. Only then do these nodes append this block to the tail of their blockchain, and accept the new EVM state as the canonical state. +7. Each node removes all transactions in the new block from their local mempool of unfulfilled transaction requests. +8. New nodes joining the network download all blocks in sequence, including the block containing our transaction of interest. They initialize a local EVM copy (which starts as a blank-state EVM), and then go through the process of executing every transaction in every block on top of their local EVM copy, verifying state checksums at each block along the way. + +Every transaction is mined (included in a new block and propagated for the first time) once, but executed and verified by every participant in the process of advancing the canonical EVM state. This highlights one of the central mantras of blockchain: **Don’t trust, verify**. + +## Ommer (uncle) blocks + +Block mining on proof-of-work was probabilistic, meaning sometimes two valid blocks were published simultaneously due to network latency. In this case, the protocol had to determine the longest (and therefore most "valid") chain while ensuring fairness towards miners by partially rewarding the unincluded valid block proposed. This encouraged further decentralization of the network as smaller miners, who might face greater latency, could still generate returns via [ommer](/glossary/#ommer) block rewards. + +The term "ommer" is the preferred gender-neutral term for the sibling of a parent block, but this is also sometimes referred to as an "uncle". **Since Ethereum's move to proof-of-stake, ommer blocks are no longer mined** as only one proposer is elected in each slot. You can see this change by viewing the [historical chart](https://ycharts.com/indicators/ethereum_uncle_rate) of the ommer blocks mined. + +## A visual demo + +Watch Austin walk you through mining and the proof-of-work blockchain. + + + +## The mining algorithm + +Ethereum Mainnet only ever used one mining algorithm - ['Ethash'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/). Ethash was the successor to an original R&D algorithm known as ['Dagger-Hashimoto'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/). + +[More on mining algorithms](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/). + +## Related topics + +- [Gas](/developers/docs/gas/) +- [EVM](/developers/docs/evm/) +- [Proof-of-work](/developers/docs/consensus-mechanisms/pow/) + +--- + +## Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms > Dagger Hashimoto + +Dagger-Hashimoto was the original research implementation and specification for Ethereum's mining algorithm. Dagger-Hashimoto was superseded by [Ethash](#ethash). Mining was switched off completely at [The Merge](/roadmap/merge/) on 15th September 2022. Since then, Ethereum has been secured using a [proof-of-stake](/developers/docs/consensus-mechanisms/pos) mechanism instead. This page is for historical interest - the information here is no longer relevant for post-Merge Ethereum. + +## Prerequisites + +To better understand this page, we recommend you first read up on [proof-of-work consensus](/developers/docs/consensus-mechanisms/pow), [mining](/developers/docs/consensus-mechanisms/pow/mining), and [mining algorithms](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms). + +## Dagger-Hashimoto + +Dagger-Hashimoto aims to satisfy two goals: + +1. **ASIC-resistance**: the benefit from creating specialized hardware for the algorithm should be as small as possible +2. **Light client verifiability**: a block should be efficiently verifiable by a light client. + +With an additional modification, we also specify how to fulfill a third goal if desired, but at the cost of additional complexity: + +**Full chain storage**: mining should require storage of the complete blockchain state (due to the irregular structure of the Ethereum state trie, we anticipate that some pruning will be possible, particularly of some often-used contracts, but we want to minimize this). + +## DAG Generation + +The code for the algorithm will be defined in Python below. First, we give `encode_int` for marshaling unsigned ints of specified precision to strings. Its inverse is also given: + +```python +NUM_BITS = 512 + +def encode_int(x): + "Encode an integer x as a string of 64 characters using a big-endian scheme" + o = '' + for _ in range(NUM_BITS / 8): + o = chr(x % 256) + o + x //= 256 + return o + +def decode_int(s): + "Unencode an integer x from a string using a big-endian scheme" + x = 0 + for c in s: + x *= 256 + x += ord(c) + return x +``` + +We next assume that `sha3` is a function that takes an integer and outputs an integer, and `dbl_sha3` is a double-sha3 function; if converting this reference code into an implementation use: + +```python +from pyethereum import utils +def sha3(x): + if isinstance(x, (int, long)): + x = encode_int(x) + return decode_int(utils.sha3(x)) + +def dbl_sha3(x): + if isinstance(x, (int, long)): + x = encode_int(x) + return decode_int(utils.sha3(utils.sha3(x))) +``` + +### Parameters + +The parameters used for the algorithm are: + +```python +SAFE_PRIME_512 = 2**512 - 38117 # Largest Safe Prime less than 2**512 + +params = +``` + +`P` in this case is a prime chosen such that `log₂(P)` is just slightly less than 512, which corresponds to the 512 bits we have been using to represent our numbers. Note that only the latter half of the DAG actually needs to be stored, so the de-facto RAM requirement starts at 1 GB and grows by 441 MB per year. + +### Dagger graph building + +The dagger graph building primitive is defined as follows: + +```python +def produce_dag(params, seed, length): + P = params["P"] + picker = init = pow(sha3(seed), params["w"], P) + o = [init] + for i in range(1, length): + x = picker = (picker * init) % P + for _ in range(params["k"]): + x ^= o[x % i] + o.append(pow(x, params["w"], P)) + return o +``` + +Essentially, it starts off a graph as a single node, `sha3(seed)`, and from there starts sequentially adding on other nodes based on random previous nodes. When a new node is created, a modular power of the seed is computed to randomly select some indices less than `i` (using `x % i` above), and the values of the nodes at those indices are used in a calculation to generate a new a value for `x`, which is then fed into a small proof of work function (based on XOR) to ultimately generate the value of the graph at index `i`. The rationale behind this particular design is to force sequential access of the DAG; the next value of the DAG that will be accessed cannot be determined until the current value is known. Finally, modular exponentiation hashes the result further. + +This algorithm relies on several results from number theory. See the appendix below for a discussion. + +## Light client evaluation + +The above graph construction intends to allow each node in the graph to be reconstructed by computing a subtree of only a small number of nodes and requiring only a small amount of auxiliary memory. Note that with k=1, the subtree is only a chain of values going up to the first element in the DAG. + +The light client computing function for the DAG works as follows: + +```python +def quick_calc(params, seed, p): + w, P = params["w"], params["P"] + cache = {} + + def quick_calc_cached(p): + if p in cache: + pass + elif p == 0: + cache[p] = pow(sha3(seed), w, P) + else: + x = pow(sha3(seed), (p + 1) * w, P) + for _ in range(params["k"]): + x ^= quick_calc_cached(x % p) + cache[p] = pow(x, w, P) + return cache[p] + + return quick_calc_cached(p) +``` + +Essentially, it is simply a rewrite of the above algorithm that removes the loop of computing the values for the entire DAG and replaces the earlier node lookup with a recursive call or a cache lookup. Note that for `k=1` the cache is unnecessary, although a further optimization actually precomputes the first few thousand values of the DAG and keeps that as a static cache for computations; see the appendix for a code implementation of this. + +## Double buffer of DAGs + +In a full client, a [_double buffer_](https://wikipedia.org/wiki/Multiple_buffering) of 2 DAGs produced by the above formula is used. The idea is that DAGs are produced every `epochtime` number of blocks according to the params above. Instead of the client using the latest DAG produced, it uses the one previous. The benefit of this is that it allows the DAGs to be replaced over time without needing to incorporate a step where miners must suddenly recompute all of the data. Otherwise, there is the potential for an abrupt temporary slowdown in chain processing at regular intervals and dramatically increasing centralization. Thus 51% attack risks within those few minutes before all data are recomputed. + +The algorithm used to generate the set of DAGs used to compute the work for a block is as follows: + +```python +def get_prevhash(n): + from pyethereum.blocks import GENESIS_PREVHASH + from pyethereum import chain_manager + if n > i + transaction = shifted_A % len(list_of_transactions) + txid_mix ^= list_of_transactions[transaction] = 2**64: + nonce = 0 + return nonce +``` + +Here is the verification algorithm: + +```python +def verify(daggerset, params, block, nonce): + result = hashimoto(daggerset, get_dagsize(params, block), + params, decode_int(block.prevhash), nonce) + return result * params["diff"] xᵐ mod P ≡ 1 +Given these definitions, we have: + +> Observation 1. Let `x` be a member of the multiplicative group `ℤ/Pℤ` for a safe prime `P`. If `x mod P ≠ 1 mod P` and `x mod P ≠ P-1 mod P`, then the order of `x` is either `P-1` or `(P-1)/2`. + +_Proof_. Since `P` is a safe prime, then by [Lagrange's Theorem][lagrange] we have that the order of `x` is either `1`, `2`, `(P-1)/2`, or `P-1`. + +The order of `x` cannot be `1`, since by Fermat's Little Theorem we have: + +xP-1 mod P ≡ 1 + +Hence `x` must be a multiplicative identity of `ℤ/nℤ`, which is unique. Since we assumed that `x ≠ 1` by assumption, this is not possible. + +The order of `x` cannot be `2` unless `x = P-1`, since this would violate that `P` is prime. + +From the above proposition, we can recognize that iterating `(picker * init) % P` will have a cycle length of at least `(P-1)/2`. This is because we selected `P` to be a safe prime approximately equal to be a higher power of two, and `init` is in the interval `[2,2**256+1]`. Given the magnitude of `P`, we should never expect a cycle from modular exponentiation. + +When we are assigning the first cell in the DAG (the variable labeled `init`), we compute `pow(sha3(seed) + 2, 3, P)`. At first glance, this does not guarantee that the result is neither `1` nor `P-1`. However, since `P-1` is a safe prime, we have the following additional assurance, which is a corollary of Observation 1: + +> Observation 2. Let `x` be a member of the multiplicative group `ℤ/Pℤ` for a safe prime `P`, and let `w` be a natural number. If `x mod P ≠ 1 mod P` and `x mod P ≠ P-1 mod P`, as well as `w mod P ≠ P-1 mod P` and `w mod P ≠ 0 mod P`, then `xʷ mod P ≠ 1 mod P` and `xʷ mod P ≠ P-1 mod P` + +### Modular exponentiation as a hash function + +For certain values of `P` and `w`, the function `pow(x, w, P)` may have many collisions. For instance, `pow(x,9,19)` only takes on values ``. + +Given that `P` is prime, then an appropriate `w` for a modular exponentiation hashing function can be chosen using the following result: + +> Observation 3. Let `P` be a prime; `w` and `P-1` are relatively prime if and only if for all `a` and `b` in `ℤ/Pℤ`:`aʷ mod P ≡ bʷ mod P` if and only if `a mod P ≡ b mod P` + +Thus, given that `P` is prime and `w` is relatively prime to `P-1`, we have that `|| = P`, implying that the hashing function has the minimal collision rate possible. + +In the special case that `P` is a safe prime as we have selected, then `P-1` only has factors 1, 2, `(P-1)/2` and `P-1`. Since `P` > 7, we know that 3 is relatively prime to `P-1`, hence `w=3` satisfies the above proposition. + +## More efficient cache-based evaluation algorithm + +```python +def quick_calc(params, seed, p): + cache = produce_dag(params, seed, params["cache_size"]) + return quick_calc_cached(cache, params, p) + +def quick_calc_cached(cache, params, p): + P = params["P"] + if p < len(cache): + return cache[p] + else: + x = pow(cache[0], p + 1, P) + for _ in range(params["k"]): + x ^= quick_calc_cached(cache, params, x % p) + return pow(x, params["w"], P) + +def quick_hashimoto(seed, dagsize, params, header, nonce): + cache = produce_dag(params, seed, params["cache_size"]) + return quick_hashimoto_cached(cache, dagsize, params, header, nonce) + +def quick_hashimoto_cached(cache, dagsize, params, header, nonce): + m = dagsize // 2 + mask = 2**64 - 1 + mix = sha3(encode_int(nonce) + header) + for _ in range(params["accesses"]): + mix ^= quick_calc_cached(cache, params, m + (mix & mask) % m) + return dbl_sha3(mix) +``` + +--- + +## Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms > Ethash + +Ethash was Ethereum's proof-of-work mining algorithm. Proof-of-work has now been **switched off entirely** and Ethereum is now secured using proof-of-stake instead. Read more on The Merge, proof-of-stake and staking. This page is for historical interest! + + +[Ethash](https://github.com/ethereum/wiki/wiki/Ethash) is a modified version of the [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto) algorithm. Ethash proof-of-work is [memory hard](https://wikipedia.org/wiki/Memory-hard_function), which was thought to make the algorithm ASIC resistant. Ethash ASICs were eventually developed but GPU mining was still a viable option until proof-of-work was switched off. Ethash is still used to mine other coins on other non-Ethereum proof-of-work networks. + +## How does Ethash work? + +Memory hardness is achieved with a proof of work algorithm that requires choosing subsets of a fixed resource dependent on the nonce and block header. This resource (a few gigabytes in size) is called a DAG. The DAG is changed every 30000 blocks, a ~125-hour window called an epoch (roughly 5.2 days) and takes a while to generate. Since the DAG only depends on block height, it can be pre-generated, but if it's not the client needs to wait until the end of this process to produce a block. If clients do not pre-generate and cache DAGs ahead of time the network may experience massive block delay on each epoch transition. Note that the DAG does not need to be generated for verifying the proof-of-work essentially allowing for verification with both low CPU and small memory. + +The general route that the algorithm takes is as follows: + +1. There exists a **seed** which can be computed for each block by scanning through the block headers up until that point. +2. From the seed, one can compute a **16 MB pseudorandom cache**. Light clients store the cache. +3. From the cache, we can generate a **1 GB dataset**, with the property that each item in the dataset depends on only a small number of items from the cache. Full clients and miners store the dataset. The dataset grows linearly with time. +4. Mining involves grabbing random slices of the dataset and hashing them together. Verification can be done with low memory by using the cache to regenerate the specific pieces of the dataset that you need, so you only need to store the cache. + +The large dataset is updated once every 30000 blocks, so the vast majority of a miner's effort will be reading the dataset, not making changes to it. + +## Definitions + +We employ the following definitions: + +``` +WORD_BYTES = 4 # bytes in word +DATASET_BYTES_INIT = 2**30 # bytes in dataset at genesis +DATASET_BYTES_GROWTH = 2**23 # dataset growth per epoch +CACHE_BYTES_INIT = 2**24 # bytes in cache at genesis +CACHE_BYTES_GROWTH = 2**17 # cache growth per epoch +CACHE_MULTIPLIER=1024 # Size of the DAG relative to the cache +EPOCH_LENGTH = 30000 # blocks per epoch +MIX_BYTES = 128 # width of mix +HASH_BYTES = 64 # hash length in bytes +DATASET_PARENTS = 256 # number of parents of each dataset element +CACHE_ROUNDS = 3 # number of rounds in cache production +ACCESSES = 64 # number of accesses in hashimoto loop +``` + +### The use of 'SHA3' + +Ethereum's development coincided with the development of the SHA3 standard, and the +standards process made a late change in the padding of the finalized hash algorithm, so that Ethereum's +"sha3_256" and "sha3_512" hashes are not standard sha3 hashes, but a variant often referred +to as "Keccak-256" and "Keccak-512" in other contexts. See discussion, e.g. [here](https://eips.ethereum.org/EIPS/eip-1803), [here](http://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use), or [here](http://bitcoin.stackexchange.com/questions/42055/what-is-the-approach-to-calculate-an-ethereum-address-from-a-256-bit-private-key/42057#42057). + +Please keep that in mind as "sha3" hashes are referred to in the description of the algorithm below. + +## Parameters + +The parameters for Ethash's cache and dataset depend on the block number. The cache size and dataset size both grow linearly; however, we always take the highest prime below the linearly growing threshold in order to reduce the risk of accidental regularities leading to cyclic behavior. + +```python +def get_cache_size(block_number): + sz = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number // EPOCH_LENGTH) + sz -= HASH_BYTES + while not isprime(sz / HASH_BYTES): + sz -= 2 * HASH_BYTES + return sz + +def get_full_size(block_number): + sz = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number // EPOCH_LENGTH) + sz -= MIX_BYTES + while not isprime(sz / MIX_BYTES): + sz -= 2 * MIX_BYTES + return sz +``` + +Tables of dataset and cache size values are provided in the appendix. + +## Cache generation + +Now, we specify the function for producing a cache: + +```python +def mkcache(cache_size, seed): + n = cache_size // HASH_BYTES + + # Sequentially produce the initial dataset + o = [sha3_512(seed)] + for i in range(1, n): + o.append(sha3_512(o[-1])) + + # Use a low-round version of randmemohash + for _ in range(CACHE_ROUNDS): + for i in range(n): + v = o[i][0] % n + o[i] = sha3_512(map(xor, o[(i-1+n) % n], o[v])) + + return o +``` + +The cache production process involves first sequentially filling up 32 MB of memory, then performing two passes of Sergio Demian Lerner's _RandMemoHash_ algorithm from [_Strict Memory Hard Hashing Functions_ (2014)](http://www.hashcash.org/papers/memohash.pdf). The output is a set of 524288 64-byte values. + +## Data aggregation function + +We use an algorithm inspired by the [FNV hash](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) in some cases as a non-associative substitute for XOR. Note that we multiply the prime with the full 32-bit input, in contrast with the FNV-1 spec which multiplies the prime with one byte (octet) in turn. + +```python +FNV_PRIME = 0x01000193 + +def fnv(v1, v2): + return ((v1 * FNV_PRIME) ^ v2) % 2**32 +``` + +Please note, even the yellow paper specifies fnv as v1\*(FNV_PRIME ^ v2), all current implementations consistently use the above definition. + +## Full dataset calculation + +Each 64-byte item in the full 1 GB dataset is computed as follows: + +```python +def calc_dataset_item(cache, i): + n = len(cache) + r = HASH_BYTES // WORD_BYTES + # initialize the mix + mix = copy.copy(cache[i % n]) + mix[0] ^= i + mix = sha3_512(mix) + # fnv it with a lot of random cache nodes based on i + for j in range(DATASET_PARENTS): + cache_index = fnv(i ^ j, mix[j % r]) + mix = map(fnv, mix, cache[cache_index % n]) + return sha3_512(mix) +``` + +Essentially, we combine data from 256 pseudorandomly selected cache nodes, and hash that to compute the dataset node. The entire dataset is then generated by: + +```python +def calc_dataset(full_size, cache): + return [calc_dataset_item(cache, i) for i in range(full_size // HASH_BYTES)] +``` + +## Main loop + +Now, we specify the main "hashimoto"-like loop, where we aggregate data from the full dataset in order to produce our final value for a particular header and nonce. In the code below, `header` represents the SHA3-256 _hash_ of the RLP representation of a _truncated_ block header, that is, of a header excluding the fields **mixHash** and **nonce**. `nonce` is the eight bytes of a 64 bit unsigned integer in big-endian order. So `nonce[::-1]` is the eight-byte little-endian representation of that value: + +```python +def hashimoto(header, nonce, full_size, dataset_lookup): + n = full_size / HASH_BYTES + w = MIX_BYTES // WORD_BYTES + mixhashes = MIX_BYTES / HASH_BYTES + # combine header+nonce into a 64 byte seed + s = sha3_512(header + nonce[::-1]) + # start the mix with replicated s + mix = [] + for _ in range(MIX_BYTES / HASH_BYTES): + mix.extend(s) + # mix in random dataset nodes + for i in range(ACCESSES): + p = fnv(i ^ s[0], mix[i % w]) % (n // mixhashes) * mixhashes + newdata = [] + for j in range(MIX_BYTES / HASH_BYTES): + newdata.extend(dataset_lookup(p + j)) + mix = map(fnv, mix, newdata) + # compress mix + cmix = [] + for i in range(0, len(mix), 4): + cmix.append(fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])) + return + +def hashimoto_light(full_size, cache, header, nonce): + return hashimoto(header, nonce, full_size, lambda x: calc_dataset_item(cache, x)) + +def hashimoto_full(full_size, dataset, header, nonce): + return hashimoto(header, nonce, full_size, lambda x: dataset[x]) +``` + +Essentially, we maintain a "mix" 128 bytes wide, and repeatedly sequentially fetch 128 bytes from the full dataset and use the `fnv` function to combine it with the mix. 128 bytes of sequential access are used so that each round of the algorithm always fetches a full page from RAM, minimizing translation lookaside buffer misses which ASICs would theoretically be able to avoid. + +If the output of this algorithm is below the desired target, then the nonce is valid. Note that the extra application of `sha3_256` at the end ensures that there exists an intermediate nonce which can be provided to prove that at least a small amount of work was done; this quick outer PoW verification can be used for anti-DDoS purposes. It also serves to provide statistical assurance that the result is an unbiased, 256-bit number. + +## Mining + +The mining algorithm is defined as follows: + +```python +def mine(full_size, dataset, header, difficulty): + # zero-pad target to compare with hash on the same digit + target = zpad(encode_int(2**256 // difficulty), 64)[::-1] + from random import randint + nonce = randint(0, 2**64) + while hashimoto_full(full_size, dataset, header, nonce) > target: + nonce = (nonce + 1) % 2**64 + return nonce +``` + +## Defining the seed hash + +In order to compute the seed hash that would be used to mine on top of a given block, we use the following algorithm: + +```python + def get_seedhash(block): + s = '\x00' * 32 + for i in range(block.number // EPOCH_LENGTH): + s = serialize_hash(sha3_256(s)) + return s +``` + +Note that for smooth mining and verifying, we recommend pre-computing future seedhashes and datasets in a separate thread. + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Appendix + +The following code should be prepended if you are interested in running the above python spec as code. + +```python +import sha3, copy + +# Assumes little endian bit ordering (same as Intel architectures) +def decode_int(s): + return int(s[::-1].encode('hex'), 16) if s else 0 + +def encode_int(s): + a = "%x" % s + return '' if s == 0 else ('0' * (len(a) % 2) + a).decode('hex')[::-1] + +def zpad(s, length): + return s + '\x00' * max(0, length - len(s)) + +def serialize_hash(h): + return ''.join([zpad(encode_int(x), 4) for x in h]) + +def deserialize_hash(h): + return [decode_int(h[i:i+WORD_BYTES]) for i in range(0, len(h), WORD_BYTES)] + +def hash_words(h, sz, x): + if isinstance(x, list): + x = serialize_hash(x) + y = h(x) + return deserialize_hash(y) + +def serialize_cache(ds): + return ''.join([serialize_hash(h) for h in ds]) + +serialize_dataset = serialize_cache + +# sha3 hash function, outputs 64 bytes +def sha3_512(x): + return hash_words(lambda v: sha3.sha3_512(v).digest(), 64, x) + +def sha3_256(x): + return hash_words(lambda v: sha3.sha3_256(v).digest(), 32, x) + +def xor(a, b): + return a ^ b + +def isprime(x): + for i in range(2, int(x**0.5)): + if x % i == 0: + return False + return True +``` + +### Data Sizes + +The following lookup tables provide approximately 2048 tabulated epochs of data sizes and cache sizes. + +```python +def get_datasize(block_number): + return data_sizes[block_number // EPOCH_LENGTH] + +def get_cachesize(block_number): + return cache_sizes[block_number // EPOCH_LENGTH] + +data_sizes = [ +1073739904, 1082130304, 1090514816, 1098906752, 1107293056, +1115684224, 1124070016, 1132461952, 1140849536, 1149232768, +1157627776, 1166013824, 1174404736, 1182786944, 1191180416, +1199568512, 1207958912, 1216345216, 1224732032, 1233124736, +1241513344, 1249902464, 1258290304, 1266673792, 1275067264, +1283453312, 1291844992, 1300234112, 1308619904, 1317010048, +1325397376, 1333787776, 1342176128, 1350561664, 1358954368, +1367339392, 1375731584, 1384118144, 1392507008, 1400897408, +1409284736, 1417673344, 1426062464, 1434451072, 1442839168, +1451229056, 1459615616, 1468006016, 1476394112, 1484782976, +1493171584, 1501559168, 1509948032, 1518337664, 1526726528, +1535114624, 1543503488, 1551892096, 1560278656, 1568669056, +1577056384, 1585446272, 1593831296, 1602219392, 1610610304, +1619000192, 1627386752, 1635773824, 1644164224, 1652555648, +1660943488, 1669332608, 1677721216, 1686109312, 1694497664, +1702886272, 1711274624, 1719661184, 1728047744, 1736434816, +1744829056, 1753218944, 1761606272, 1769995904, 1778382464, +1786772864, 1795157888, 1803550592, 1811937664, 1820327552, +1828711552, 1837102976, 1845488768, 1853879936, 1862269312, +1870656896, 1879048064, 1887431552, 1895825024, 1904212096, +1912601216, 1920988544, 1929379456, 1937765504, 1946156672, +1954543232, 1962932096, 1971321728, 1979707264, 1988093056, +1996487552, 2004874624, 2013262208, 2021653888, 2030039936, +2038430848, 2046819968, 2055208576, 2063596672, 2071981952, +2080373632, 2088762752, 2097149056, 2105539712, 2113928576, +2122315136, 2130700672, 2139092608, 2147483264, 2155872128, +2164257664, 2172642176, 2181035392, 2189426048, 2197814912, +2206203008, 2214587264, 2222979712, 2231367808, 2239758208, +2248145024, 2256527744, 2264922752, 2273312128, 2281701248, +2290086272, 2298476672, 2306867072, 2315251072, 2323639168, +2332032128, 2340420224, 2348808064, 2357196416, 2365580416, +2373966976, 2382363008, 2390748544, 2399139968, 2407530368, +2415918976, 2424307328, 2432695424, 2441084288, 2449472384, +2457861248, 2466247808, 2474637184, 2483026816, 2491414144, +2499803776, 2508191872, 2516582272, 2524970368, 2533359232, +2541743488, 2550134144, 2558525056, 2566913408, 2575301504, +2583686528, 2592073856, 2600467328, 2608856192, 2617240448, +2625631616, 2634022016, 2642407552, 2650796416, 2659188352, +2667574912, 2675965312, 2684352896, 2692738688, 2701130624, +2709518464, 2717907328, 2726293376, 2734685056, 2743073152, +2751462016, 2759851648, 2768232832, 2776625536, 2785017728, +2793401984, 2801794432, 2810182016, 2818571648, 2826959488, +2835349376, 2843734144, 2852121472, 2860514432, 2868900992, +2877286784, 2885676928, 2894069632, 2902451584, 2910843008, +2919234688, 2927622784, 2936011648, 2944400768, 2952789376, +2961177728, 2969565568, 2977951616, 2986338944, 2994731392, +3003120256, 3011508352, 3019895936, 3028287104, 3036675968, +3045063808, 3053452928, 3061837696, 3070228352, 3078615424, +3087003776, 3095394944, 3103782272, 3112173184, 3120562048, +3128944768, 3137339264, 3145725056, 3154109312, 3162505088, +3170893184, 3179280256, 3187669376, 3196056704, 3204445568, +3212836736, 3221224064, 3229612928, 3238002304, 3246391168, +3254778496, 3263165824, 3271556224, 3279944576, 3288332416, +3296719232, 3305110912, 3313500032, 3321887104, 3330273152, +3338658944, 3347053184, 3355440512, 3363827072, 3372220288, +3380608384, 3388997504, 3397384576, 3405774208, 3414163072, +3422551936, 3430937984, 3439328384, 3447714176, 3456104576, +3464493952, 3472883584, 3481268864, 3489655168, 3498048896, +3506434432, 3514826368, 3523213952, 3531603584, 3539987072, +3548380288, 3556763264, 3565157248, 3573545344, 3581934464, +3590324096, 3598712704, 3607098752, 3615488384, 3623877248, +3632265856, 3640646528, 3649043584, 3657430144, 3665821568, +3674207872, 3682597504, 3690984832, 3699367808, 3707764352, +3716152448, 3724541056, 3732925568, 3741318016, 3749706368, +3758091136, 3766481536, 3774872704, 3783260032, 3791650432, +3800036224, 3808427648, 3816815488, 3825204608, 3833592704, +3841981568, 3850370432, 3858755968, 3867147904, 3875536256, +3883920512, 3892313728, 3900702592, 3909087872, 3917478784, +3925868416, 3934256512, 3942645376, 3951032192, 3959422336, +3967809152, 3976200064, 3984588416, 3992974976, 4001363584, +4009751168, 4018141312, 4026530432, 4034911616, 4043308928, +4051695488, 4060084352, 4068472448, 4076862848, 4085249408, +4093640576, 4102028416, 4110413696, 4118805632, 4127194496, +4135583104, 4143971968, 4152360832, 4160746112, 4169135744, +4177525888, 4185912704, 4194303616, 4202691968, 4211076736, +4219463552, 4227855488, 4236246656, 4244633728, 4253022848, +4261412224, 4269799808, 4278184832, 4286578048, 4294962304, +4303349632, 4311743104, 4320130432, 4328521088, 4336909184, +4345295488, 4353687424, 4362073472, 4370458496, 4378852736, +4387238528, 4395630208, 4404019072, 4412407424, 4420790656, +4429182848, 4437571456, 4445962112, 4454344064, 4462738048, +4471119232, 4479516544, 4487904128, 4496289664, 4504682368, +4513068416, 4521459584, 4529846144, 4538232704, 4546619776, +4555010176, 4563402112, 4571790208, 4580174464, 4588567936, +4596957056, 4605344896, 4613734016, 4622119808, 4630511488, +4638898816, 4647287936, 4655675264, 4664065664, 4672451968, +4680842624, 4689231488, 4697620352, 4706007424, 4714397056, +4722786176, 4731173248, 4739562368, 4747951744, 4756340608, +4764727936, 4773114496, 4781504384, 4789894784, 4798283648, +4806667648, 4815059584, 4823449472, 4831835776, 4840226176, +4848612224, 4857003392, 4865391488, 4873780096, 4882169728, +4890557312, 4898946944, 4907333248, 4915722368, 4924110976, +4932499328, 4940889728, 4949276032, 4957666432, 4966054784, +4974438016, 4982831488, 4991221376, 4999607168, 5007998848, +5016386432, 5024763776, 5033164672, 5041544576, 5049941888, +5058329728, 5066717056, 5075107456, 5083494272, 5091883904, +5100273536, 5108662144, 5117048192, 5125436032, 5133827456, +5142215296, 5150605184, 5158993024, 5167382144, 5175769472, +5184157568, 5192543872, 5200936064, 5209324928, 5217711232, +5226102656, 5234490496, 5242877312, 5251263872, 5259654016, +5268040832, 5276434304, 5284819328, 5293209728, 5301598592, +5309986688, 5318374784, 5326764416, 5335151488, 5343542144, +5351929472, 5360319872, 5368706944, 5377096576, 5385484928, +5393871232, 5402263424, 5410650496, 5419040384, 5427426944, +5435816576, 5444205952, 5452594816, 5460981376, 5469367936, +5477760896, 5486148736, 5494536832, 5502925952, 5511315328, +5519703424, 5528089984, 5536481152, 5544869504, 5553256064, +5561645696, 5570032768, 5578423936, 5586811264, 5595193216, +5603585408, 5611972736, 5620366208, 5628750464, 5637143936, +5645528192, 5653921408, 5662310272, 5670694784, 5679082624, +5687474048, 5695864448, 5704251008, 5712641408, 5721030272, +5729416832, 5737806208, 5746194304, 5754583936, 5762969984, +5771358592, 5779748224, 5788137856, 5796527488, 5804911232, +5813300608, 5821692544, 5830082176, 5838468992, 5846855552, +5855247488, 5863636096, 5872024448, 5880411008, 5888799872, +5897186432, 5905576832, 5913966976, 5922352768, 5930744704, +5939132288, 5947522432, 5955911296, 5964299392, 5972688256, +5981074304, 5989465472, 5997851008, 6006241408, 6014627968, +6023015552, 6031408256, 6039796096, 6048185216, 6056574848, +6064963456, 6073351808, 6081736064, 6090128768, 6098517632, +6106906496, 6115289216, 6123680896, 6132070016, 6140459648, +6148849024, 6157237376, 6165624704, 6174009728, 6182403712, +6190792064, 6199176064, 6207569792, 6215952256, 6224345216, +6232732544, 6241124224, 6249510272, 6257899136, 6266287744, +6274676864, 6283065728, 6291454336, 6299843456, 6308232064, +6316620928, 6325006208, 6333395584, 6341784704, 6350174848, +6358562176, 6366951296, 6375337856, 6383729536, 6392119168, +6400504192, 6408895616, 6417283456, 6425673344, 6434059136, +6442444672, 6450837376, 6459223424, 6467613056, 6476004224, +6484393088, 6492781952, 6501170048, 6509555072, 6517947008, +6526336384, 6534725504, 6543112832, 6551500672, 6559888768, +6568278656, 6576662912, 6585055616, 6593443456, 6601834112, +6610219648, 6618610304, 6626999168, 6635385472, 6643777408, +6652164224, 6660552832, 6668941952, 6677330048, 6685719424, +6694107776, 6702493568, 6710882176, 6719274112, 6727662976, +6736052096, 6744437632, 6752825984, 6761213824, 6769604224, +6777993856, 6786383488, 6794770816, 6803158144, 6811549312, +6819937664, 6828326528, 6836706176, 6845101696, 6853491328, +6861880448, 6870269312, 6878655104, 6887046272, 6895433344, +6903822208, 6912212864, 6920596864, 6928988288, 6937377152, +6945764992, 6954149248, 6962544256, 6970928768, 6979317376, +6987709312, 6996093824, 7004487296, 7012875392, 7021258624, +7029652352, 7038038912, 7046427776, 7054818944, 7063207808, +7071595136, 7079980928, 7088372608, 7096759424, 7105149824, +7113536896, 7121928064, 7130315392, 7138699648, 7147092352, +7155479168, 7163865728, 7172249984, 7180648064, 7189036672, +7197424768, 7205810816, 7214196608, 7222589824, 7230975104, +7239367552, 7247755904, 7256145536, 7264533376, 7272921472, +7281308032, 7289694848, 7298088832, 7306471808, 7314864512, +7323253888, 7331643008, 7340029568, 7348419712, 7356808832, +7365196672, 7373585792, 7381973888, 7390362752, 7398750592, +7407138944, 7415528576, 7423915648, 7432302208, 7440690304, +7449080192, 7457472128, 7465860992, 7474249088, 7482635648, +7491023744, 7499412608, 7507803008, 7516192384, 7524579968, +7532967296, 7541358464, 7549745792, 7558134656, 7566524032, +7574912896, 7583300992, 7591690112, 7600075136, 7608466816, +7616854912, 7625244544, 7633629824, 7642020992, 7650410368, +7658794112, 7667187328, 7675574912, 7683961984, 7692349568, +7700739712, 7709130368, 7717519232, 7725905536, 7734295424, +7742683264, 7751069056, 7759457408, 7767849088, 7776238208, +7784626816, 7793014912, 7801405312, 7809792128, 7818179968, +7826571136, 7834957184, 7843347328, 7851732352, 7860124544, +7868512384, 7876902016, 7885287808, 7893679744, 7902067072, +7910455936, 7918844288, 7927230848, 7935622784, 7944009344, +7952400256, 7960786048, 7969176704, 7977565312, 7985953408, +7994339968, 8002730368, 8011119488, 8019508096, 8027896192, +8036285056, 8044674688, 8053062272, 8061448832, 8069838464, +8078227328, 8086616704, 8095006592, 8103393664, 8111783552, +8120171392, 8128560256, 8136949376, 8145336704, 8153726848, +8162114944, 8170503296, 8178891904, 8187280768, 8195669632, +8204058496, 8212444544, 8220834176, 8229222272, 8237612672, +8246000768, 8254389376, 8262775168, 8271167104, 8279553664, +8287944064, 8296333184, 8304715136, 8313108352, 8321497984, +8329885568, 8338274432, 8346663296, 8355052928, 8363441536, +8371828352, 8380217984, 8388606592, 8396996224, 8405384576, +8413772672, 8422161536, 8430549376, 8438939008, 8447326592, +8455715456, 8464104832, 8472492928, 8480882048, 8489270656, +8497659776, 8506045312, 8514434944, 8522823808, 8531208832, +8539602304, 8547990656, 8556378752, 8564768384, 8573154176, +8581542784, 8589933952, 8598322816, 8606705024, 8615099264, +8623487872, 8631876992, 8640264064, 8648653952, 8657040256, +8665430656, 8673820544, 8682209152, 8690592128, 8698977152, +8707374464, 8715763328, 8724151424, 8732540032, 8740928384, +8749315712, 8757704576, 8766089344, 8774480768, 8782871936, +8791260032, 8799645824, 8808034432, 8816426368, 8824812928, +8833199488, 8841591424, 8849976448, 8858366336, 8866757248, +8875147136, 8883532928, 8891923328, 8900306816, 8908700288, +8917088384, 8925478784, 8933867392, 8942250368, 8950644608, +8959032704, 8967420544, 8975809664, 8984197504, 8992584064, +9000976256, 9009362048, 9017752448, 9026141312, 9034530688, +9042917504, 9051307904, 9059694208, 9068084864, 9076471424, +9084861824, 9093250688, 9101638528, 9110027648, 9118416512, +9126803584, 9135188096, 9143581312, 9151969664, 9160356224, +9168747136, 9177134464, 9185525632, 9193910144, 9202302848, +9210690688, 9219079552, 9227465344, 9235854464, 9244244864, +9252633472, 9261021824, 9269411456, 9277799296, 9286188928, +9294574208, 9302965888, 9311351936, 9319740032, 9328131968, +9336516736, 9344907392, 9353296768, 9361685888, 9370074752, +9378463616, 9386849408, 9395239808, 9403629184, 9412016512, +9420405376, 9428795008, 9437181568, 9445570688, 9453960832, +9462346624, 9470738048, 9479121536, 9487515008, 9495903616, +9504289664, 9512678528, 9521067904, 9529456256, 9537843584, +9546233728, 9554621312, 9563011456, 9571398784, 9579788672, +9588178304, 9596567168, 9604954496, 9613343104, 9621732992, +9630121856, 9638508416, 9646898816, 9655283584, 9663675776, +9672061312, 9680449664, 9688840064, 9697230464, 9705617536, +9714003584, 9722393984, 9730772608, 9739172224, 9747561088, +9755945344, 9764338816, 9772726144, 9781116544, 9789503872, +9797892992, 9806282624, 9814670464, 9823056512, 9831439232, +9839833984, 9848224384, 9856613504, 9865000576, 9873391232, +9881772416, 9890162816, 9898556288, 9906940544, 9915333248, +9923721088, 9932108672, 9940496512, 9948888448, 9957276544, +9965666176, 9974048384, 9982441088, 9990830464, 9999219584, +10007602816, 10015996544, 10024385152, 10032774016, 10041163648, +10049548928, 10057940096, 10066329472, 10074717824, 10083105152, +10091495296, 10099878784, 10108272256, 10116660608, 10125049216, +10133437312, 10141825664, 10150213504, 10158601088, 10166991232, +10175378816, 10183766144, 10192157312, 10200545408, 10208935552, +10217322112, 10225712768, 10234099328, 10242489472, 10250876032, +10259264896, 10267656064, 10276042624, 10284429184, 10292820352, +10301209472, 10309598848, 10317987712, 10326375296, 10334763392, +10343153536, 10351541632, 10359930752, 10368318592, 10376707456, +10385096576, 10393484672, 10401867136, 10410262144, 10418647424, +10427039104, 10435425664, 10443810176, 10452203648, 10460589952, +10468982144, 10477369472, 10485759104, 10494147712, 10502533504, +10510923392, 10519313536, 10527702656, 10536091264, 10544478592, +10552867712, 10561255808, 10569642368, 10578032768, 10586423168, +10594805632, 10603200128, 10611588992, 10619976064, 10628361344, +10636754048, 10645143424, 10653531776, 10661920384, 10670307968, +10678696832, 10687086464, 10695475072, 10703863168, 10712246144, +10720639616, 10729026688, 10737414784, 10745806208, 10754190976, +10762581376, 10770971264, 10779356288, 10787747456, 10796135552, +10804525184, 10812915584, 10821301888, 10829692288, 10838078336, +10846469248, 10854858368, 10863247232, 10871631488, 10880023424, +10888412032, 10896799616, 10905188992, 10913574016, 10921964672, +10930352768, 10938742912, 10947132544, 10955518592, 10963909504, +10972298368, 10980687488, 10989074816, 10997462912, 11005851776, +11014241152, 11022627712, 11031017344, 11039403904, 11047793024, +11056184704, 11064570752, 11072960896, 11081343872, 11089737856, +11098128256, 11106514816, 11114904448, 11123293568, 11131680128, +11140065152, 11148458368, 11156845696, 11165236864, 11173624192, +11182013824, 11190402688, 11198790784, 11207179136, 11215568768, +11223957376, 11232345728, 11240734592, 11249122688, 11257511296, +11265899648, 11274285952, 11282675584, 11291065472, 11299452544, +11307842432, 11316231296, 11324616832, 11333009024, 11341395584, +11349782656, 11358172288, 11366560384, 11374950016, 11383339648, +11391721856, 11400117376, 11408504192, 11416893568, 11425283456, +11433671552, 11442061184, 11450444672, 11458837888, 11467226752, +11475611776, 11484003968, 11492392064, 11500780672, 11509169024, +11517550976, 11525944448, 11534335616, 11542724224, 11551111808, +11559500672, 11567890304, 11576277376, 11584667008, 11593056128, +11601443456, 11609830016, 11618221952, 11626607488, 11634995072, +11643387776, 11651775104, 11660161664, 11668552576, 11676940928, +11685330304, 11693718656, 11702106496, 11710496128, 11718882688, +11727273088, 11735660416, 11744050048, 11752437376, 11760824704, +11769216128, 11777604736, 11785991296, 11794381952, 11802770048, +11811157888, 11819548544, 11827932544, 11836324736, 11844713344, +11853100928, 11861486464, 11869879936, 11878268032, 11886656896, +11895044992, 11903433088, 11911822976, 11920210816, 11928600448, +11936987264, 11945375872, 11953761152, 11962151296, 11970543488, +11978928512, 11987320448, 11995708288, 12004095104, 12012486272, +12020875136, 12029255552, 12037652096, 12046039168, 12054429568, +12062813824, 12071206528, 12079594624, 12087983744, 12096371072, +12104759936, 12113147264, 12121534592, 12129924992, 12138314624, +12146703232, 12155091584, 12163481216, 12171864704, 12180255872, +12188643968, 12197034112, 12205424512, 12213811328, 12222199424, +12230590336, 12238977664, 12247365248, 12255755392, 12264143488, +12272531584, 12280920448, 12289309568, 12297694592, 12306086528, +12314475392, 12322865024, 12331253632, 12339640448, 12348029312, +12356418944, 12364805248, 12373196672, 12381580928, 12389969024, +12398357632, 12406750592, 12415138432, 12423527552, 12431916416, +12440304512, 12448692352, 12457081216, 12465467776, 12473859968, +12482245504, 12490636672, 12499025536, 12507411584, 12515801728, +12524190592, 12532577152, 12540966272, 12549354368, 12557743232, +12566129536, 12574523264, 12582911872, 12591299456, 12599688064, +12608074624, 12616463488, 12624845696, 12633239936, 12641631616, +12650019968, 12658407296, 12666795136, 12675183232, 12683574656, +12691960192, 12700350592, 12708740224, 12717128576, 12725515904, +12733906816, 12742295168, 12750680192, 12759071872, 12767460736, +12775848832, 12784236928, 12792626816, 12801014656, 12809404288, +12817789312, 12826181504, 12834568832, 12842954624, 12851345792, +12859732352, 12868122496, 12876512128, 12884901248, 12893289088, +12901672832, 12910067584, 12918455168, 12926842496, 12935232896, +12943620736, 12952009856, 12960396928, 12968786816, 12977176192, +12985563776, 12993951104, 13002341504, 13010730368, 13019115392, +13027506304, 13035895168, 13044272512, 13052673152, 13061062528, +13069446272, 13077838976, 13086227072, 13094613632, 13103000192, +13111393664, 13119782528, 13128157568, 13136559232, 13144945024, +13153329536, 13161724288, 13170111872, 13178502784, 13186884736, +13195279744, 13203667072, 13212057472, 13220445824, 13228832128, +13237221248, 13245610624, 13254000512, 13262388352, 13270777472, +13279166336, 13287553408, 13295943296, 13304331904, 13312719488, +13321108096, 13329494656, 13337885824, 13346274944, 13354663808, +13363051136, 13371439232, 13379825024, 13388210816, 13396605056, +13404995456, 13413380224, 13421771392, 13430159744, 13438546048, +13446937216, 13455326848, 13463708288, 13472103808, 13480492672, +13488875648, 13497269888, 13505657728, 13514045312, 13522435712, +13530824576, 13539210112, 13547599232, 13555989376, 13564379008, +13572766336, 13581154432, 13589544832, 13597932928, 13606320512, +13614710656, 13623097472, 13631477632, 13639874944, 13648264064, +13656652928, 13665041792, 13673430656, 13681818496, 13690207616, +13698595712, 13706982272, 13715373184, 13723762048, 13732150144, +13740536704, 13748926592, 13757316224, 13765700992, 13774090112, +13782477952, 13790869376, 13799259008, 13807647872, 13816036736, +13824425344, 13832814208, 13841202304, 13849591424, 13857978752, +13866368896, 13874754688, 13883145344, 13891533184, 13899919232, +13908311168, 13916692096, 13925085056, 13933473152, 13941866368, +13950253696, 13958643584, 13967032192, 13975417216, 13983807616, +13992197504, 14000582272, 14008973696, 14017363072, 14025752192, +14034137984, 14042528384, 14050918016, 14059301504, 14067691648, +14076083584, 14084470144, 14092852352, 14101249664, 14109635968, +14118024832, 14126407552, 14134804352, 14143188608, 14151577984, +14159968384, 14168357248, 14176741504, 14185127296, 14193521024, +14201911424, 14210301824, 14218685056, 14227067264, 14235467392, +14243855488, 14252243072, 14260630144, 14269021568, 14277409408, +14285799296, 14294187904, 14302571392, 14310961792, 14319353728, +14327738752, 14336130944, 14344518784, 14352906368, 14361296512, +14369685376, 14378071424, 14386462592, 14394848128, 14403230848, +14411627392, 14420013952, 14428402304, 14436793472, 14445181568, +14453569664, 14461959808, 14470347904, 14478737024, 14487122816, +14495511424, 14503901824, 14512291712, 14520677504, 14529064832, +14537456768, 14545845632, 14554234496, 14562618496, 14571011456, +14579398784, 14587789184, 14596172672, 14604564608, 14612953984, +14621341312, 14629724288, 14638120832, 14646503296, 14654897536, +14663284864, 14671675264, 14680061056, 14688447616, 14696835968, +14705228416, 14713616768, 14722003328, 14730392192, 14738784128, +14747172736, 14755561088, 14763947648, 14772336512, 14780725376, +14789110144, 14797499776, 14805892736, 14814276992, 14822670208, +14831056256, 14839444352, 14847836032, 14856222848, 14864612992, +14872997504, 14881388672, 14889775744, 14898165376, 14906553472, +14914944896, 14923329664, 14931721856, 14940109696, 14948497024, +14956887424, 14965276544, 14973663616, 14982053248, 14990439808, +14998830976, 15007216768, 15015605888, 15023995264, 15032385152, +15040768384, 15049154944, 15057549184, 15065939072, 15074328448, +15082715008, 15091104128, 15099493504, 15107879296, 15116269184, +15124659584, 15133042304, 15141431936, 15149824384, 15158214272, +15166602368, 15174991232, 15183378304, 15191760512, 15200154496, +15208542592, 15216931712, 15225323392, 15233708416, 15242098048, +15250489216, 15258875264, 15267265408, 15275654528, 15284043136, +15292431488, 15300819584, 15309208192, 15317596544, 15325986176, +15334374784, 15342763648, 15351151744, 15359540608, 15367929728, +15376318336, 15384706432, 15393092992, 15401481856, 15409869952, +15418258816, 15426649984, 15435037568, 15443425664, 15451815296, +15460203392, 15468589184, 15476979328, 15485369216, 15493755776, +15502146944, 15510534272, 15518924416, 15527311232, 15535699072, +15544089472, 15552478336, 15560866688, 15569254528, 15577642624, +15586031488, 15594419072, 15602809472, 15611199104, 15619586432, +15627975296, 15636364928, 15644753792, 15653141888, 15661529216, +15669918848, 15678305152, 15686696576, 15695083136, 15703474048, +15711861632, 15720251264, 15728636288, 15737027456, 15745417088, +15753804928, 15762194048, 15770582656, 15778971008, 15787358336, +15795747712, 15804132224, 15812523392, 15820909696, 15829300096, +15837691264, 15846071936, 15854466944, 15862855808, 15871244672, +15879634816, 15888020608, 15896409728, 15904799104, 15913185152, +15921577088, 15929966464, 15938354816, 15946743424, 15955129472, +15963519872, 15971907968, 15980296064, 15988684928, 15997073024, +16005460864, 16013851264, 16022241152, 16030629248, 16039012736, +16047406976, 16055794816, 16064181376, 16072571264, 16080957824, +16089346688, 16097737856, 16106125184, 16114514816, 16122904192, +16131292544, 16139678848, 16148066944, 16156453504, 16164839552, +16173236096, 16181623424, 16190012032, 16198401152, 16206790528, +16215177344, 16223567744, 16231956352, 16240344704, 16248731008, +16257117824, 16265504384, 16273898624, 16282281856, 16290668672, +16299064192, 16307449216, 16315842176, 16324230016, 16332613504, +16341006464, 16349394304, 16357783168, 16366172288, 16374561664, +16382951296, 16391337856, 16399726208, 16408116352, 16416505472, +16424892032, 16433282176, 16441668224, 16450058624, 16458448768, +16466836864, 16475224448, 16483613056, 16492001408, 16500391808, +16508779648, 16517166976, 16525555328, 16533944192, 16542330752, +16550719616, 16559110528, 16567497088, 16575888512, 16584274816, +16592665472, 16601051008, 16609442944, 16617832064, 16626218624, +16634607488, 16642996096, 16651385728, 16659773824, 16668163712, +16676552576, 16684938112, 16693328768, 16701718144, 16710095488, +16718492288, 16726883968, 16735272832, 16743661184, 16752049792, +16760436608, 16768827008, 16777214336, 16785599104, 16793992832, +16802381696, 16810768768, 16819151744, 16827542656, 16835934848, +16844323712, 16852711552, 16861101952, 16869489536, 16877876864, +16886265728, 16894653056, 16903044736, 16911431296, 16919821696, +16928207488, 16936592768, 16944987776, 16953375616, 16961763968, +16970152832, 16978540928, 16986929536, 16995319168, 17003704448, +17012096896, 17020481152, 17028870784, 17037262208, 17045649536, +17054039936, 17062426496, 17070814336, 17079205504, 17087592064, +17095978112, 17104369024, 17112759424, 17121147776, 17129536384, +17137926016, 17146314368, 17154700928, 17163089792, 17171480192, +17179864192, 17188256896, 17196644992, 17205033856, 17213423488, +17221811072, 17230198912, 17238588032, 17246976896, 17255360384, +17263754624, 17272143232, 17280530048, 17288918912, 17297309312, +17305696384, 17314085504, 17322475136, 17330863744, 17339252096, +17347640192, 17356026496, 17364413824, 17372796544, 17381190016, +17389583488, 17397972608, 17406360704, 17414748544, 17423135872, +17431527296, 17439915904, 17448303232, 17456691584, 17465081728, +17473468288, 17481857408, 17490247552, 17498635904, 17507022464, +17515409024, 17523801728, 17532189824, 17540577664, 17548966016, +17557353344, 17565741184, 17574131584, 17582519168, 17590907008, +17599296128, 17607687808, 17616076672, 17624455808, 17632852352, +17641238656, 17649630848, 17658018944, 17666403968, 17674794112, +17683178368, 17691573376, 17699962496, 17708350592, 17716739968, +17725126528, 17733517184, 17741898112, 17750293888, 17758673024, +17767070336, 17775458432, 17783848832, 17792236928, 17800625536, +17809012352, 17817402752, 17825785984, 17834178944, 17842563968, +17850955648, 17859344512, 17867732864, 17876119424, 17884511872, +17892900224, 17901287296, 17909677696, 17918058112, 17926451072, +17934843776, 17943230848, 17951609216, 17960008576, 17968397696, +17976784256, 17985175424, 17993564032, 18001952128, 18010339712, +18018728576, 18027116672, 18035503232, 18043894144, 18052283264, +18060672128, 18069056384, 18077449856, 18085837184, 18094225792, +18102613376, 18111004544, 18119388544, 18127781248, 18136170368, +18144558976, 18152947328, 18161336192, 18169724288, 18178108544, +18186498944, 18194886784, 18203275648, 18211666048, 18220048768, +18228444544, 18236833408, 18245220736] + +cache_sizes = [ +16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, +17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, +18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, +19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, +20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, +21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, +22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, +23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, +24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, +25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, +25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, +26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, +27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, +28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, +29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, +30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, +31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, +32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, +33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, +34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, +35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, +36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, +36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, +37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, +38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, +39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, +40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, +41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, +42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, +43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, +44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, +45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, +46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, +47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, +47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, +48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, +49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, +50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, +51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, +52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, +53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, +54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, +55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, +56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, +57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, +58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, +58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, +59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, +60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, +61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, +62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, +63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, +64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, +65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, +66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, +67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, +68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, +69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, +69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, +70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, +71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, +72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, +73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, +74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, +75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, +76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, +77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, +78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, +79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, +80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, +81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, +81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, +82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, +83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, +84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, +85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, +86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, +87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, +88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, +89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, +90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, +91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, +92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, +92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, +93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, +94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, +95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, +96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, +97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, +98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, +99352384, 99482816, 99614272, 99745472, 99876416, 100007104, +100138048, 100267072, 100401088, 100529984, 100662592, 100791872, +100925248, 101056064, 101187392, 101317952, 101449408, 101580608, +101711296, 101841728, 101973824, 102104896, 102235712, 102366016, +102498112, 102628672, 102760384, 102890432, 103021888, 103153472, +103284032, 103415744, 103545152, 103677248, 103808576, 103939648, +104070976, 104201792, 104332736, 104462528, 104594752, 104725952, +104854592, 104988608, 105118912, 105247808, 105381184, 105511232, +105643072, 105774784, 105903296, 106037056, 106167872, 106298944, +106429504, 106561472, 106691392, 106822592, 106954304, 107085376, +107216576, 107346368, 107478464, 107609792, 107739712, 107872192, +108003136, 108131392, 108265408, 108396224, 108527168, 108657344, +108789568, 108920384, 109049792, 109182272, 109312576, 109444928, +109572928, 109706944, 109837888, 109969088, 110099648, 110230976, +110362432, 110492992, 110624704, 110755264, 110886208, 111017408, +111148864, 111279296, 111410752, 111541952, 111673024, 111803456, +111933632, 112066496, 112196416, 112328512, 112457792, 112590784, +112715968, 112852672, 112983616, 113114944, 113244224, 113376448, +113505472, 113639104, 113770304, 113901376, 114031552, 114163264, +114294592, 114425536, 114556864, 114687424, 114818624, 114948544, +115080512, 115212224, 115343296, 115473472, 115605184, 115736128, +115867072, 115997248, 116128576, 116260288, 116391488, 116522944, +116652992, 116784704, 116915648, 117046208, 117178304, 117308608, +117440192, 117569728, 117701824, 117833024, 117964096, 118094656, +118225984, 118357312, 118489024, 118617536, 118749632, 118882112, +119012416, 119144384, 119275328, 119406016, 119537344, 119668672, +119798464, 119928896, 120061376, 120192832, 120321728, 120454336, +120584512, 120716608, 120848192, 120979136, 121109056, 121241408, +121372352, 121502912, 121634752, 121764416, 121895744, 122027072, +122157632, 122289088, 122421184, 122550592, 122682944, 122813888, +122945344, 123075776, 123207488, 123338048, 123468736, 123600704, +123731264, 123861952, 123993664, 124124608, 124256192, 124386368, +124518208, 124649024, 124778048, 124911296, 125041088, 125173696, +125303744, 125432896, 125566912, 125696576, 125829056, 125958592, +126090304, 126221248, 126352832, 126483776, 126615232, 126746432, +126876608, 127008704, 127139392, 127270336, 127401152, 127532224, +127663552, 127794752, 127925696, 128055232, 128188096, 128319424, +128449856, 128581312, 128712256, 128843584, 128973632, 129103808, +129236288, 129365696, 129498944, 129629888, 129760832, 129892288, +130023104, 130154048, 130283968, 130416448, 130547008, 130678336, +130807616, 130939456, 131071552, 131202112, 131331776, 131464384, +131594048, 131727296, 131858368, 131987392, 132120256, 132250816, +132382528, 132513728, 132644672, 132774976, 132905792, 133038016, +133168832, 133299392, 133429312, 133562048, 133692992, 133823296, +133954624, 134086336, 134217152, 134348608, 134479808, 134607296, +134741056, 134872384, 135002944, 135134144, 135265472, 135396544, +135527872, 135659072, 135787712, 135921472, 136052416, 136182848, +136313792, 136444864, 136576448, 136707904, 136837952, 136970048, +137099584, 137232064, 137363392, 137494208, 137625536, 137755712, +137887424, 138018368, 138149824, 138280256, 138411584, 138539584, +138672832, 138804928, 138936128, 139066688, 139196864, 139328704, +139460032, 139590208, 139721024, 139852864, 139984576, 140115776, +140245696, 140376512, 140508352, 140640064, 140769856, 140902336, +141032768, 141162688, 141294016, 141426496, 141556544, 141687488, +141819584, 141949888, 142080448, 142212544, 142342336, 142474432, +142606144, 142736192, 142868288, 142997824, 143129408, 143258944, +143392448, 143523136, 143653696, 143785024, 143916992, 144045632, +144177856, 144309184, 144440768, 144570688, 144701888, 144832448, +144965056, 145096384, 145227584, 145358656, 145489856, 145620928, +145751488, 145883072, 146011456, 146144704, 146275264, 146407232, +146538176, 146668736, 146800448, 146931392, 147062336, 147193664, +147324224, 147455936, 147586624, 147717056, 147848768, 147979456, +148110784, 148242368, 148373312, 148503232, 148635584, 148766144, +148897088, 149028416, 149159488, 149290688, 149420224, 149551552, +149683136, 149814976, 149943616, 150076352, 150208064, 150338624, +150470464, 150600256, 150732224, 150862784, 150993088, 151125952, +151254976, 151388096, 151519168, 151649728, 151778752, 151911104, +152042944, 152174144, 152304704, 152435648, 152567488, 152698816, +152828992, 152960576, 153091648, 153222976, 153353792, 153484096, +153616192, 153747008, 153878336, 154008256, 154139968, 154270912, +154402624, 154533824, 154663616, 154795712, 154926272, 155057984, +155188928, 155319872, 155450816, 155580608, 155712064, 155843392, +155971136, 156106688, 156237376, 156367424, 156499264, 156630976, +156761536, 156892352, 157024064, 157155008, 157284416, 157415872, +157545536, 157677248, 157810496, 157938112, 158071744, 158203328, +158334656, 158464832, 158596288, 158727616, 158858048, 158988992, +159121216, 159252416, 159381568, 159513152, 159645632, 159776192, +159906496, 160038464, 160169536, 160300352, 160430656, 160563008, +160693952, 160822208, 160956352, 161086784, 161217344, 161349184, +161480512, 161611456, 161742272, 161873216, 162002752, 162135872, +162266432, 162397888, 162529216, 162660032, 162790976, 162922048, +163052096, 163184576, 163314752, 163446592, 163577408, 163707968, +163839296, 163969984, 164100928, 164233024, 164364224, 164494912, +164625856, 164756672, 164887616, 165019072, 165150016, 165280064, +165412672, 165543104, 165674944, 165805888, 165936832, 166067648, +166198336, 166330048, 166461248, 166591552, 166722496, 166854208, +166985408, 167116736, 167246656, 167378368, 167508416, 167641024, +167771584, 167903168, 168034112, 168164032, 168295744, 168427456, +168557632, 168688448, 168819136, 168951616, 169082176, 169213504, +169344832, 169475648, 169605952, 169738048, 169866304, 169999552, +170131264, 170262464, 170393536, 170524352, 170655424, 170782016, +170917696, 171048896, 171179072, 171310784, 171439936, 171573184, +171702976, 171835072, 171966272, 172097216, 172228288, 172359232, +172489664, 172621376, 172747712, 172883264, 173014208, 173144512, +173275072, 173407424, 173539136, 173669696, 173800768, 173931712, +174063424, 174193472, 174325696, 174455744, 174586816, 174718912, +174849728, 174977728, 175109696, 175242688, 175374272, 175504832, +175636288, 175765696, 175898432, 176028992, 176159936, 176291264, +176422592, 176552512, 176684864, 176815424, 176946496, 177076544, +177209152, 177340096, 177470528, 177600704, 177731648, 177864256, +177994816, 178126528, 178257472, 178387648, 178518464, 178650176, +178781888, 178912064, 179044288, 179174848, 179305024, 179436736, +179568448, 179698496, 179830208, 179960512, 180092608, 180223808, +180354752, 180485696, 180617152, 180748096, 180877504, 181009984, +181139264, 181272512, 181402688, 181532608, 181663168, 181795136, +181926592, 182057536, 182190016, 182320192, 182451904, 182582336, +182713792, 182843072, 182976064, 183107264, 183237056, 183368384, +183494848, 183631424, 183762752, 183893824, 184024768, 184154816, +184286656, 184417984, 184548928, 184680128, 184810816, 184941248, +185072704, 185203904, 185335616, 185465408, 185596352, 185727296, +185859904, 185989696, 186121664, 186252992, 186383552, 186514112, +186645952, 186777152, 186907328, 187037504, 187170112, 187301824, +187429184, 187562048, 187693504, 187825472, 187957184, 188087104, +188218304, 188349376, 188481344, 188609728, 188743616, 188874304, +189005248, 189136448, 189265088, 189396544, 189528128, 189660992, +189791936, 189923264, 190054208, 190182848, 190315072, 190447424, +190577984, 190709312, 190840768, 190971328, 191102656, 191233472, +191364032, 191495872, 191626816, 191758016, 191888192, 192020288, +192148928, 192282176, 192413504, 192542528, 192674752, 192805952, +192937792, 193068608, 193198912, 193330496, 193462208, 193592384, +193723456, 193854272, 193985984, 194116672, 194247232, 194379712, +194508352, 194641856, 194772544, 194900672, 195035072, 195166016, +195296704, 195428032, 195558592, 195690304, 195818176, 195952576, +196083392, 196214336, 196345792, 196476736, 196607552, 196739008, +196869952, 197000768, 197130688, 197262784, 197394368, 197523904, +197656384, 197787584, 197916608, 198049472, 198180544, 198310208, +198442432, 198573632, 198705088, 198834368, 198967232, 199097792, +199228352, 199360192, 199491392, 199621696, 199751744, 199883968, +200014016, 200146624, 200276672, 200408128, 200540096, 200671168, +200801984, 200933312, 201062464, 201194944, 201326144, 201457472, +201588544, 201719744, 201850816, 201981632, 202111552, 202244032, +202374464, 202505152, 202636352, 202767808, 202898368, 203030336, +203159872, 203292608, 203423296, 203553472, 203685824, 203816896, +203947712, 204078272, 204208192, 204341056, 204472256, 204603328, +204733888, 204864448, 204996544, 205125568, 205258304, 205388864, +205517632, 205650112, 205782208, 205913536, 206044736, 206176192, +206307008, 206434496, 206569024, 206700224, 206831168, 206961856, +207093056, 207223616, 207355328, 207486784, 207616832, 207749056, +207879104, 208010048, 208141888, 208273216, 208404032, 208534336, +208666048, 208796864, 208927424, 209059264, 209189824, 209321792, +209451584, 209582656, 209715136, 209845568, 209976896, 210106432, +210239296, 210370112, 210501568, 210630976, 210763712, 210894272, +211024832, 211156672, 211287616, 211418176, 211549376, 211679296, +211812032, 211942592, 212074432, 212204864, 212334016, 212467648, +212597824, 212727616, 212860352, 212991424, 213120832, 213253952, +213385024, 213515584, 213645632, 213777728, 213909184, 214040128, +214170688, 214302656, 214433728, 214564544, 214695232, 214826048, +214956992, 215089088, 215219776, 215350592, 215482304, 215613248, +215743552, 215874752, 216005312, 216137024, 216267328, 216399296, +216530752, 216661696, 216790592, 216923968, 217054528, 217183168, +217316672, 217448128, 217579072, 217709504, 217838912, 217972672, +218102848, 218233024, 218364736, 218496832, 218627776, 218759104, +218888896, 219021248, 219151936, 219281728, 219413056, 219545024, +219675968, 219807296, 219938624, 220069312, 220200128, 220331456, +220461632, 220592704, 220725184, 220855744, 220987072, 221117888, +221249216, 221378368, 221510336, 221642048, 221772736, 221904832, +222031808, 222166976, 222297536, 222428992, 222559936, 222690368, +222820672, 222953152, 223083968, 223213376, 223345984, 223476928, +223608512, 223738688, 223869376, 224001472, 224132672, 224262848, +224394944, 224524864, 224657344, 224788288, 224919488, 225050432, +225181504, 225312704, 225443776, 225574592, 225704768, 225834176, +225966784, 226097216, 226229824, 226360384, 226491712, 226623424, +226754368, 226885312, 227015104, 227147456, 227278528, 227409472, +227539904, 227669696, 227802944, 227932352, 228065216, 228196288, +228326464, 228457792, 228588736, 228720064, 228850112, 228981056, +229113152, 229243328, 229375936, 229505344, 229636928, 229769152, +229894976, 230030272, 230162368, 230292416, 230424512, 230553152, +230684864, 230816704, 230948416, 231079616, 231210944, 231342016, +231472448, 231603776, 231733952, 231866176, 231996736, 232127296, +232259392, 232388672, 232521664, 232652608, 232782272, 232914496, +233043904, 233175616, 233306816, 233438528, 233569984, 233699776, +233830592, 233962688, 234092224, 234221888, 234353984, 234485312, +234618304, 234749888, 234880832, 235011776, 235142464, 235274048, +235403456, 235535936, 235667392, 235797568, 235928768, 236057152, +236190272, 236322752, 236453312, 236583616, 236715712, 236846528, +236976448, 237108544, 237239104, 237371072, 237501632, 237630784, +237764416, 237895232, 238026688, 238157632, 238286912, 238419392, +238548032, 238681024, 238812608, 238941632, 239075008, 239206336, +239335232, 239466944, 239599168, 239730496, 239861312, 239992384, +240122816, 240254656, 240385856, 240516928, 240647872, 240779072, +240909632, 241040704, 241171904, 241302848, 241433408, 241565248, +241696192, 241825984, 241958848, 242088256, 242220224, 242352064, +242481856, 242611648, 242744896, 242876224, 243005632, 243138496, +243268672, 243400384, 243531712, 243662656, 243793856, 243924544, +244054592, 244187072, 244316608, 244448704, 244580032, 244710976, +244841536, 244972864, 245104448, 245233984, 245365312, 245497792, +245628736, 245759936, 245889856, 246021056, 246152512, 246284224, +246415168, 246545344, 246675904, 246808384, 246939584, 247070144, +247199552, 247331648, 247463872, 247593536, 247726016, 247857088, +247987648, 248116928, 248249536, 248380736, 248512064, 248643008, +248773312, 248901056, 249036608, 249167552, 249298624, 249429184, +249560512, 249692096, 249822784, 249954112, 250085312, 250215488, +250345792, 250478528, 250608704, 250739264, 250870976, 251002816, +251133632, 251263552, 251395136, 251523904, 251657792, 251789248, +251919424, 252051392, 252182464, 252313408, 252444224, 252575552, +252706624, 252836032, 252968512, 253099712, 253227584, 253361728, +253493056, 253623488, 253754432, 253885504, 254017216, 254148032, +254279488, 254410432, 254541376, 254672576, 254803264, 254933824, +255065792, 255196736, 255326528, 255458752, 255589952, 255721408, +255851072, 255983296, 256114624, 256244416, 256374208, 256507712, +256636096, 256768832, 256900544, 257031616, 257162176, 257294272, +257424448, 257555776, 257686976, 257818432, 257949632, 258079552, +258211136, 258342464, 258473408, 258603712, 258734656, 258867008, +258996544, 259127744, 259260224, 259391296, 259522112, 259651904, +259784384, 259915328, 260045888, 260175424, 260308544, 260438336, +260570944, 260700992, 260832448, 260963776, 261092672, 261226304, +261356864, 261487936, 261619648, 261750592, 261879872, 262011968, +262143424, 262274752, 262404416, 262537024, 262667968, 262799296, +262928704, 263061184, 263191744, 263322944, 263454656, 263585216, +263716672, 263847872, 263978944, 264108608, 264241088, 264371648, +264501184, 264632768, 264764096, 264895936, 265024576, 265158464, +265287488, 265418432, 265550528, 265681216, 265813312, 265943488, +266075968, 266206144, 266337728, 266468032, 266600384, 266731072, +266862272, 266993344, 267124288, 267255616, 267386432, 267516992, +267648704, 267777728, 267910592, 268040512, 268172096, 268302784, +268435264, 268566208, 268696256, 268828096, 268959296, 269090368, +269221312, 269352256, 269482688, 269614784, 269745856, 269876416, +270007616, 270139328, 270270272, 270401216, 270531904, 270663616, +270791744, 270924736, 271056832, 271186112, 271317184, 271449536, +271580992, 271711936, 271843136, 271973056, 272105408, 272236352, +272367296, 272498368, 272629568, 272759488, 272891456, 273022784, +273153856, 273284672, 273415616, 273547072, 273677632, 273808448, +273937088, 274071488, 274200896, 274332992, 274463296, 274595392, +274726208, 274857536, 274988992, 275118656, 275250496, 275382208, +275513024, 275643968, 275775296, 275906368, 276037184, 276167872, +276297664, 276429376, 276560576, 276692672, 276822976, 276955072, +277085632, 277216832, 277347008, 277478848, 277609664, 277740992, +277868608, 278002624, 278134336, 278265536, 278395328, 278526784, +278657728, 278789824, 278921152, 279052096, 279182912, 279313088, +279443776, 279576256, 279706048, 279838528, 279969728, 280099648, +280230976, 280361408, 280493632, 280622528, 280755392, 280887104, +281018176, 281147968, 281278912, 281411392, 281542592, 281673152, +281803712, 281935552, 282066496, 282197312, 282329024, 282458816, +282590272, 282720832, 282853184, 282983744, 283115072, 283246144, +283377344, 283508416, 283639744, 283770304, 283901504, 284032576, +284163136, 284294848, 284426176, 284556992, 284687296, 284819264, +284950208, 285081536] +``` + +--- + +## Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms + +Proof-of-work is no longer underlying Ethereum's consensus mechanism, meaning mining has been switched off. Instead, Ethereum is secured by validators who stake ETH. You can start staking your ETH today. Read more on The Merge, proof-of-stake, and staking. This page is for historical interest only. + + +Ethereum mining used an algorithm known as Ethash. The fundamental idea of the algorithm is that a miner tries to find a nonce input using brute force computation so that the resulting hash is smaller than a threshold determined by the calculated difficulty. This difficulty level can be dynamically adjusted, allowing block production to happen at a regular interval. + +## Prerequisites + +To better understand this page, we recommend you first read up on [proof-of-work consensus](/developers/docs/consensus-mechanisms/pow) and [mining](/developers/docs/consensus-mechanisms/pow/mining). + +## Dagger Hashimoto + +Dagger Hashimoto was a precursor research algorithm for Ethereum mining that Ethash superseded. It was an amalgamation of two different algorithms: Dagger and Hashimoto. It was only ever a research implementation and was superseded by Ethash by the time Ethereum Mainnet launched. + +[Dagger](http://www.hashcash.org/papers/dagger.html) involves the generation of a [Directed Acyclic Graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph), random slices of which get hashed together. The core principle is that each nonce only requires a small portion of a large total data tree. Recomputing the subtree for each nonce is prohibitive for mining - hence the need to store the tree - but okay for a single nonce’s worth of verification. Dagger was designed to be an alternative to existing algorithms like Scrypt, which are memory-hard but difficult to verify when their memory-hardness increases to genuinely secure levels. However, Dagger was vulnerable to shared memory hardware acceleration and dropped in favor of other avenues of research. + +[Hashimoto](http://diyhpl.us/%7Ebryan/papers2/bitcoin/meh/hashimoto.pdf) is an algorithm that adds ASIC-resistance by being I/O bound (i.e. memory reads are the limiting factor in the mining process). The theory is that RAM is more available than computation; billions of dollars worth of research have already investigated optimizing RAM for different use cases, which often involve near-random access patterns (hence “random access memory”). As a result, existing RAM is likely to be moderately close to optimal for evaluating the algorithm. Hashimoto uses the blockchain as a source of data, simultaneously satisfying (1) and (3) above. + +Dagger-Hashimoto used amended versions of the Dagger and Hashimoto algorithms. The difference between Dagger Hashimoto and Hashimoto is that, instead of using the blockchain as a data source, Dagger Hashimoto uses a custom-generated data set, which updates based on block data every N blocks. The data set is generated using the Dagger algorithm, allowing for efficiently calculating a subset specific to every nonce for the light client verification algorithm. The difference between Dagger Hashimoto and Dagger is that, unlike in the original Dagger, the dataset used to query the block is semi-permanent, only being updated at occasional intervals (e.g. once per week). This means that the portion of the effort of generating the dataset is close to zero, so Sergio Lerner’s arguments regarding shared memory speedups become negligible. + +More on [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto). + +## Ethash + +Ethash was the mining algorithm that was actually used on the real Ethereum Mainnet under the now deprecated proof-of-work architecture. Ethash was effectively a new name given to a specific version of Dagger-Hashimoto after the algorithm got significantly updated, whilst still inheriting the fundamental principles of its predecessor. Ethereum Mainnet only ever used Ethash - Dagger Hashimoto was an R&D version of the mining algorithm that was superseded before mining started on Ethereum Mainnet. + +[More on Ethash](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash). + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Dapps + +A decentralized application (dapp) is an application built on a decentralized network that combines a [smart contract](/developers/docs/smart-contracts/) and a frontend user interface. On Ethereum, smart contracts are accessible and transparent – like open APIs – so your dapp can even include a smart contract that someone else has written. + +## Prerequisites + +Before learning about dapps, you should cover the [blockchain basics](/developers/docs/intro-to-ethereum/) and read about the Ethereum network and how it's decentralized. + +## Definition of a dapp + +A dapp has its backend code running on a decentralized peer-to-peer network. Contrast this with an app where the backend code is running on centralized servers. + +A dapp can have frontend code and user interfaces written in any language (just like an app) to make calls to its backend. Furthermore, its frontend can get hosted on decentralized storage such as [IPFS](https://ipfs.io/). + +- **Decentralized** - dapps operate on Ethereum, an open public decentralized platform where no one person or group has control +- **Deterministic** - dapps perform the same function irrespective of the environment in which they get executed +- **Turing complete** - dapps can perform any action given the required resources +- **Isolated** - dapps are executed in a virtual environment known as Ethereum Virtual Machine so that if the smart contract has a bug, it won’t hamper the normal functioning of the blockchain network + +### On smart contracts + +To introduce dapps, we need to introduce smart contracts – a dapp's backend for lack of a better term. For a detailed overview, head to our section on [smart contracts](/developers/docs/smart-contracts/). + +A smart contract is code that lives on the Ethereum blockchain and runs exactly as programmed. Once smart contracts are deployed on the network you can't change them. Dapps can be decentralized because they are controlled by the logic written into the contract, not an individual or company. This also means you need to design your contracts very carefully and test them thoroughly. + +## Benefits of dapp development + +- **Zero downtime** – Once the smart contract is deployed on the blockchain, the network as a whole will always be able to serve clients looking to interact with the contract. Malicious actors, therefore, cannot launch denial-of-service attacks targeted towards individual dapps. +- **Privacy** – You don’t need to provide real-world identity to deploy or interact with a dapp. +- **Resistance to censorship** – No single entity on the network can block users from submitting transactions, deploying dapps, or reading data from the blockchain. +- **Complete data integrity** – Data stored on the blockchain is immutable and indisputable, thanks to cryptographic primitives. Malicious actors cannot forge transactions or other data that has already been made public. +- **Trustless computation/verifiable behavior** – Smart contracts can be analyzed and are guaranteed to execute in predictable ways, without the need to trust a central authority. This is not true in traditional models; for example, when we use online banking systems, we must trust that financial institutions will not misuse our financial data, tamper with records, or get hacked. + +## Drawbacks of dapp development + +- **Maintenance** – Dapps can be harder to maintain because the code and data published to the blockchain are harder to modify. It’s hard for developers to make updates to their dapps (or the underlying data stored by a dapp) once they are deployed, even if bugs or security risks are identified in an old version. +- **Performance overhead** – There is a huge performance overhead, and scaling is really hard. To achieve the level of security, integrity, transparency, and reliability that Ethereum aspires to, every node runs and stores every transaction. On top of this, proof-of-stake consensus takes time as well. +- **Network congestion** – When one dapp uses too many computational resources, the entire network gets backed up. Currently, the network can only process about 10-15 transactions per second; if transactions are being sent in faster than this, the pool of unconfirmed transactions can quickly balloon. +- **User experience** – It may be harder to engineer user-friendly experiences because the average end-user might find it too difficult to set up a tool stack necessary to interact with the blockchain in a truly secure fashion. +- **Centralization** – User-friendly and developer-friendly solutions built on top of the base layer of Ethereum might end up looking like centralized services anyways. For example, such services may store keys or other sensitive information server-side, serve a frontend using a centralized server, or run important business logic on a centralized server before writing to the blockchain. Centralization eliminates many (if not all) of the advantages of blockchain over the traditional model. + +## More of a visual learner? + + + +## Tools for creating dapps + +**Scaffold-ETH _- Quickly experiment with Solidity using a frontend that adapts to your smart contract._** + +- [GitHub](https://github.com/scaffold-eth/scaffold-eth-2) +- [Example dapp](https://punkwallet.io/) + +**Create Eth App _- Create Ethereum-powered apps with one command._** + +- [GitHub](https://github.com/paulrberg/create-eth-app) + +**One Click Dapp _- FOSS tool for generating dapp frontends from an [ABI](/glossary/#abi)._** + +- [oneclickdapp.com](https://oneclickdapp.com) +- [GitHub](https://github.com/oneclickdapp/oneclickdapp-v1) + +**Etherflow _- FOSS tool for Ethereum developers to test their node, and compose & debug RPC calls from the browser._** + +- [etherflow.quiknode.io](https://etherflow.quiknode.io/) +- [GitHub](https://github.com/abunsen/etherflow) + +**thirdweb _- SDKs in every language, smart contracts, tools, and infrastructure for web3 development._** + +- [Homepage](https://thirdweb.com/) +- [Documentation](https://portal.thirdweb.com/) +- [GitHub](https://github.com/thirdweb-dev/) + +**Crossmint _- Enterprise-grade web3 development platform to deploy smart contracts, enable credit-card and cross chain payments, and use APIs to create, distribute, sell, store, and edit NFTs._** + +- [crossmint.com](https://www.crossmint.com) +- [Documentation](https://docs.crossmint.com) +- [Discord](https://discord.com/invite/crossmint) + +## Further reading + +- [Explore dapps](/dapps) +- [The Architecture of a Web 3.0 application](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ +- [A 2021 guide to decentralized applications](https://limechain.tech/blog/what-are-dapps-the-2021-guide/) - _LimeChain_ +- [What Are Decentralized Apps?](https://www.gemini.com/cryptopedia/decentralized-applications-defi-dapps) - _Gemini_ +- [Popular dapps](https://www.alchemy.com/dapps) - _Alchemy_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related Topics + +- [Introduction to the Ethereum stack](/developers/docs/ethereum-stack/) +- [Development frameworks](/developers/docs/frameworks/) + +--- + +## Developers > Docs > Data And Analytics > Block Explorers + +Block explorers are your portal to Ethereum's data. You can use them to see real-time data on blocks, transactions, validators, accounts, and other onchain activity. + +## Prerequisites + +You should understand the basic concepts of Ethereum so you can make sense of the data that a block explorer gives you. Start with [an intro to Ethereum](/developers/docs/intro-to-ethereum/). + +## Services + +- [Etherscan](https://etherscan.io/) -_Also available in Chinese, Korean, Russian, and Japanese_ +- [3xpl](https://3xpl.com/ethereum) +- [Beaconcha.in](https://beaconcha.in/) +- [Blockchair](https://blockchair.com/ethereum) -_Also available in Spanish, French, Italian, Dutch, Portuguese, Russian, Chinese, and Farsi_ +- [Blockscout](https://eth.blockscout.com/) +- [Chainlens](https://www.chainlens.com/) +- [DexGuru Block Explorer](https://ethereum.dex.guru/) +- [Etherchain](https://www.etherchain.org/) +- [Ethernow](https://www.ethernow.xyz/) +- [Ethplorer](https://ethplorer.io/) -_Also available in Chinese, Spanish, French, Turkish, Russian, Korean and Vietnamese_ +- [EthVM](https://www.ethvm.com/) +- [OKLink](https://www.oklink.com/eth) +- [Ethseer](https://ethseer.io) + +## Open source tools + +- [Otterscan](https://otterscan.io/) +- [lazy-etherscan](https://github.com/woxjro/lazy-etherscan) + +## Data + +Ethereum is transparent by design so everything is verifiable. Block explorers provide an interface for getting this information. And this is for both the main Ethereum network and the testnets, should you need that data. Data is divided into execution data and consensus data. The execution data refers to the transactions that have been executed in a specific block. The consensus data refers to the blocks themselves and the validators who proposed them. + +Here's a summary of the types of data you can get from a block explorer. + +### Execution data + +New blocks are added to Ethereum every 12 seconds (unless a block proposer misses its turn), so a near-constant stream of data gets added to block explorers. Blocks contain a lot of important data that you may find useful: + +**Standard data** + +- Block height - The block number and length of the blockchain (in blocks) on creation of the current block +- Timestamp - The time at which a block was proposed +- Transactions - The number of transactions included within the block +- Fee recipient - The address that received gas fee tips from transactions +- Block Reward - The amount of ETH awarded to the validator who proposed the block +- Size - The size of the data within the block (measured in bytes) +- Gas used - The total units of gas used by the transactions in the block +- Gas limit - The total gas limits set by the transactions in the block +- Base fee per gas - The minimum multiplier required for a transaction to be included in a block +- Burnt fees - How much ETH is burned in the block +- Extra data - Any extra data the builder has included in the block + +**Advanced data** + +- Hash - The cryptographic hash that represents the block header (the unique identifier of the block) +- Parent hash - The hash of the block that came before the current block +- StateRoot - The root hash of Merkle trie which stores the entire state of the system + +### Gas + +Not only will block explorers give you data about Gas usage in transactions and blocks, but some will give you information on the network's current gas prices. This will help you understand network usage, submit safe transactions and not overspend on gas. Look out for APIs that can help you get this information into your product's interface. Gas-specific data covers: + +- Estimated units of gas needed for a safe but slow transaction (+ estimated price and duration) +- Estimated units of gas needed for an average transaction (+ estimated price and duration) +- Estimated units of gas needed for a fast transaction (+ estimated price and duration) +- Average confirmation time based on gas price +- Contracts that are consuming gas - in other words, popular products that are seeing lots of usage on the network +- Accounts that are spending gas - in other words, frequent network users + +### Transactions + +Block explorers have become a common place for people to track the progress of their transactions. That's because the level of detail you can get provides extra certainty. Transaction data includes: + +**Standard data** + +- Transaction hash - A hash generated when the transaction is submitted +- Status - An indication of whether the transaction is pending, failed or a success +- Block - The block in which the transaction has been included +- Timestamp - The time at which a transaction was included in a block proposed by a validator +- From - The address of the account that submitted the transaction +- To - The address of the recipient or smart contract that the transaction interacts with +- Tokens transferred - A list of tokens that were transferred as part of the transaction +- Value - The total ETH value being transferred +- Transaction fee - The amount paid to the validator to process the transaction (calculated by gas price\*gas used) + +**Advanced data** + +- Gas limit - The maximum numbers of gas units this transaction can consume +- Gas used - The actual amount of gas units the transaction consumed +- Gas price - The price set per gas unit +- Nonce - The transaction number for the `from` address (bear in mind this starts at 0 so a nonce of `100` would actually be the 101st transaction submitted by this account) +- Input data - Any extra information required by the transaction + +### Accounts + +There's a lot of data that you can access about an account. This is why it's often recommended to use multiple accounts so that your assets and value can't be easily tracked. There are also some solutions being developed to make transactions and account activity more private. But here's the data that's available for accounts: + +**User accounts** + +- Account address - The public address you can use to send funds to +- ETH balance - The amount of ETH associated with that account +- Total ETH value - The value of the ETH +- Tokens - The tokens associated with the account and their value +- Transaction history - A list of all the transactions where this account was either the sender or the recipient + +**Smart contracts** + +Smart contract accounts have all the data that a user account will have, but some block explorers will even display some code information too. Examples include: + +- Contract creator - The address that deployed the contract to Mainnet +- Creation transaction - The transaction that included the deployment to Mainnet +- Source code - The solidity or vyper code of the smart contract +- Contract ABI - The Application Binary Interface of the contract—the calls the contract makes and the data received +- Contract creation code - The compiled bytecode of the smart contract—created when you compile a smart contract written in Solidity or Vyper, etc. +- Contract events - A history of the methods called in the smart contract—basically a way to see how the contract is being used and how often + +### Tokens + +Tokens are a type of contract so they'll have similar data to a smart contract. But because they have value and can be traded they have additional data points: + +- Type - Whether they're an ERC-20, ERC-721 or another token standard +- Price - If they're an ERC-20 they'll have a current market value +- Market cap - If they're an ERC-20 they'll have a market cap (calculated by price\*total supply) +- Total supply - The number of tokens in circulation +- Holders - The number of addresses that hold the token +- Transfers - The number of times the token has been transferred between accounts +- Transaction history - A history of all the transactions including the token +- Contract address - The address of the token that was deployed to Mainnet +- Decimals - ERC-20 tokens are divisible and have decimal places + +### Network + +Some block data is concerned about the health of Ethereum more holistically. + +- Total transactions - The number of transactions since Ethereum was created +- Transactions per second - The number of transactions processable within a second +- ETH price - The current valuations of 1 ETH +- Total ETH supply - Number of ETH in circulation—remember new ETH is created with the creation of every block in the form of block rewards +- Market cap - Calculation of price\*supply + +## Consensus layer data + +### Epoch + +For security reasons, randomized committees of validators are created at the end of every epoch (every 6.4 minutes). Epoch data includes: + +- Epoch number +- Finalized status - Whether the epoch has been finalized (Yes/No) +- Time - The time the epoch ended +- Attestations - The number of attestations in the epoch (votes for blocks within slots) +- Deposits - The number of ETH deposits included in the epoch (validators must stake ETH to become validators) +- Slashings - Number of penalties given to proposers of blocks or attestors +- Voting participation - The amount of staked ETH used to attest blocks +- Validators - Number of validators active for the epoch +- Average Validator balance - Average balance for active validators +- Slots - Number of slots included in the epoch (slots include one valid block) + +### Slot + +Slots are opportunities for block creation, the data available for each slot includes: + +- Epoch - The epoch in which the slot is valid +- Slot number +- Status - The status of the slot (Proposed/Missed) +- Time - The slot timestamp +- Proposer - The validator that proposed the block for the slot +- Block root - The hash-tree-root of the BeaconBlock +- Parent root - The hash of the block that came before +- State root - The hash-tree-root of the BeaconState +- Signature +- Randao reveal +- Graffiti - A block proposer can include 32 byte long message to its block proposal +- Execution Data + - Block hash + - Deposit count + - Deposit root +- Attestations - Number of attestations for the block in this slot +- Deposits - The number of deposits during this slot +- Voluntary exits - The number of validators that left during the slot +- Slashings - Number of penalties given to proposers of blocks or attestors +- Votes - The validators that voted for the block in this slot + +### Blocks + +Proof-of-stake divides time into slots and epochs. So that means new data! + +- Proposer - The validator that was algorithmically chosen to propose the new block +- Epoch - The epoch in which the block was proposed +- Slot - The slot in which the block was proposed +- Attestations - The number of attestation included in the slot—attestations are like votes that indicate the block is ready to go to the Beacon Chain + +### Validators + +Validators are responsible for proposing blocks and attesting to them within slots. + +- Validator number - Unique number that represents the validator +- Current balance - The validator's balance including rewards +- Effective balance - The validator's balance that is used for staking +- Income - The rewards or penalties received by the validator +- Status - Whether the validator is currently online and active or not +- Attestation effectiveness - The average time it takes for the validator's attestations to be included in the chain +- Eligibility for activation - Date (and epoch) when the validator became available to validate +- Active since - Date (and epoch) when the validator became active +- Proposed blocks - The block that the validator has proposed +- Attestations - The attestations that the validator has provided +- Deposits - The from address, transaction hash, block number, timestamp, amount and status of the staking deposit made by the validator + +### Attestations + +Attestations are "yes" votes to include blocks in the chain. Their data relates to a record of the attestation and the validators who attested + +- Slot - The slot in which the attestation took place +- Committee index - The index of the committee at the given slot +- Aggregation bits - Represents the aggregated attestation of all participating validators in the attestation +- Validators - The validators that provided attestations +- Beacon block root - Points to the block to which validators are attesting +- Source - Points to the latest justified epoch +- Target - Points to the latest epoch boundary +- Signature + +### Network + +The consensus layer top-level data includes the following: + +- Current epoch +- Current slot +- Active validators - Number of active validators +- Pending validators - Number of validators waiting for to be made active +- Staked ETH - Amount of ETH staked in the network +- Average balance - Average ETH balance of validators + +## Block explorers + +- [Etherscan](https://etherscan.io/) - a block explorer you can use to fetch data for Ethereum Mainnet and Testnet +- [3xpl](https://3xpl.com/ethereum) - an ad-free open-source Ethereum explorer which allows downloading its datasets +- [Beaconcha.in](https://beaconcha.in/) - an open source block explorer for Ethereum Mainnet and Testnet +- [Blockchair](https://blockchair.com/ethereum) - the most private Ethereum explorer. Also for sorting and filtering (mempool) data +- [Etherchain](https://www.etherchain.org/) - a block explorer for the Ethereum Mainnet +- [Ethplorer](https://ethplorer.io/) - a block explorer with a focus on tokens for the Ethereum Mainnet and the Kovan testnet +- [Ethernow](https://www.ethernow.xyz/) - a real-time transaction explorer that enables you to see the Ethereum Mainnet pre-chain layer + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Transactions](/developers/docs/transactions/) +- [Accounts](/developers/docs/accounts/) +- [Networks](/developers/docs/networks/) + +--- + +## Developers > Docs > Data And Analytics + +## Introduction + +As utilization of the network continues to grow, an increasing amount of valuable information will exist in the onchain data. As the volume of data rapidly increases, calculating and aggregating this information to report upon or drive a dapp can become a time and process heavy endeavor. + +Leveraging existing data providers can expedite development, produce more accurate results, and reduce ongoing maintenance efforts. This will enable a team to concentrate on the core functionality their project is trying to provide. + +## Prerequisites + +You should understand the basic concept of [Block Explorers](/developers/docs/data-and-analytics/block-explorers/) in order to better understand using them in the data analytics context. In addition, familiarize yourself with the concept of an [index](/glossary/#index) to understand the benefits they add to a system design. + +In terms of architectural fundamentals, understanding what an [API](https://www.wikipedia.org/wiki/API) and [REST](https://www.wikipedia.org/wiki/Representational_state_transfer) are, even in theory. + +## Block explorers + +Many [Block Explorers](/developers/docs/data-and-analytics/block-explorers/) offer [RESTful](https://www.wikipedia.org/wiki/Representational_state_transfer) [API](https://www.wikipedia.org/wiki/API) gateways that will provide developers visibility into real-time data on blocks, transactions, validators, accounts, and other onchain activity. + +Developers can then process and transform this data to give their users unique insights and interactions with the [blockchain](/glossary/#blockchain). For example, [Etherscan](https://etherscan.io) provides execution and consensus data for every 12s slot. + +## The Graph + +[The Graph](https://thegraph.com/) is an indexing protocol that provides an easy way to query blockchain data through open APIs known as subgraphs. + +With The Graph, developers can benefit from: + +- Decentralized indexing: Enables indexing blockchain data through multiple indexers, thus eliminating any single point of failure +- GraphQL queries: Provides a powerful GraphQL interface for querying indexed data, making data retrieval super simple +- Customization: Define your own logic for transforming & storing blockchain data, and reuse subgraphs published by other developers on The Graph Network + +Follow this [quick-start](https://thegraph.com/docs/en/quick-start/) guide to create, deploy, and query a subgraph within 5 minutes. + +## Client diversity + +[Client diversity](/developers/docs/nodes-and-clients/client-diversity/) is important for the overall health of the Ethereum network because it provides resilience to bugs and exploits. There are now several client diversity dashboards including [clientdiversity.org](https://clientdiversity.org/), [rated.network](https://www.rated.network), [supermajority.info](https://supermajority.info//) and [Ethernodes](https://ethernodes.org/). + +## Dune Analytics + +[Dune Analytics](https://dune.com/) pre-processes blockchain data into relational database (DuneSQL) tables, allows users to query blockchain data using SQL and build dashboards based on query results. Onchain data are organized into 4 raw tables: `blocks`, `transactions`, (event) `logs` and (call) `traces`. Popular contracts and protocols have been decoded, and each has its own set of event and call tables. Those event and call tables are processed further and organized into abstraction tables by the type of protocols, for example, dex, lending, stablecoins, etc. + +## SQD + +[SQD](https://sqd.dev/) is a decentralized hyper-scalable data platform optimized for providing efficient, permissionless access to large volumes of data. It currently serves historical on-chain data, including event logs, transaction receipts, traces, and per-transaction state diffs. SQD offers a powerful toolkit for creating custom data extraction and processing pipelines, achieving an indexing speed of up to 150k blocks per second. + +To get started, visit the [documentation](https://docs.sqd.dev/) or see [EVM examples](https://github.com/subsquid-labs/squid-evm-examples) of what you can build with SQD. + +## SubQuery Network + +[SubQuery](https://subquery.network/) is a leading data indexer that gives developers fast, reliable, decentralized, and customized APIs for their web3 projects. SubQuery empower developers from over 165+ ecosystems (including Ethereum) with rich indexed data to build an intuitive and immersive experiences for their users. The SubQuery Network powers your unstoppable apps with a resilient and decentralized infrastructure network. Use SubQuery's blockchain developer toolkit to build the web3 applications of the future, without spending time building a custom backend for data processing activities. + +To start, visit the [Ethereum quick start guide](https://academy.subquery.network/quickstart/quickstart_chains/ethereum-gravatar.html) to start indexing Ethereum blockchain data in minutes in a local Docker environment for testing before going live on a [SubQuery's managed service](https://managedservice.subquery.network/) or on [SubQuery's decentralised network](https://app.subquery.network/dashboard). + +## Ethernow - Mempool Data Program + +[Blocknative](https://www.blocknative.com/) provides open access to its Ethereum historical [mempool data archive](https://www.ethernow.xyz/mempool-data-archive). This enables researchers and community good projects to explore the pre-chain layer of Ethereum Mainnet. The data set is actively maintained and represents the most comprehensive historical record of mempool transaction events within the Ethereum ecosystem. Learn more at [Ethernow](https://www.ethernow.xyz/). + +## EVM Query Language + +EVM Query Language (EQL) is an SQL-like language designed to query EVM (Ethereum Virtual Machine) chains. EQL's ultimate goal is to support complex relational queries on EVM chain first-class citizens (blocks, accounts, and transactions) while providing developers and researchers with an ergonomic syntax for everyday use. With EQL, developers can fetch blockchain data using familiar SQL-like syntax and eliminate the need for complex boilerplate code. EQL supports standard blockchain data requests (e.g., retrieving an account's nonce and balance on Ethereum or fetching the current block size and timestamp) and is continually adding support for more complex requests and featuresets. + +## Further Reading + +- [Exploring Crypto Data I: Data Flow Architectures](https://research.2077.xyz/exploring-crypto-data-1-data-flow-architectures) +- [Graph Network Overview](https://thegraph.com/docs/en/about/) +- [Graph Query Playground](https://thegraph.com/explorer/subgraph/graphprotocol/graph-network-mainnet?version=current) +- [API code examples on EtherScan](https://etherscan.io/apis#contracts) +- [Beaconcha.in Beacon Chain explorer](https://beaconcha.in) +- [Dune Basics](https://docs.dune.com/#dune-basics) +- [SubQuery Ethereum Quick Start Guide](https://academy.subquery.network/indexer/quickstart/quickstart_chains/ethereum-gravatar.html) +- [SQD Network Overview](https://docs.sqd.dev/) +- [EVM Query Language](https://eql.sh/blog/alpha-release-notes) + +--- + +## Developers > Docs > Data Availability > Blockchain Data Storage Strategies + +There are multiple ways to store information either directly on the blockchain, or in a manner that is secured by the blockchain: + +- EIP-4844 blobs +- Calldata +- Offchain with L1 mechanisms +- Contract "code" +- Events +- EVM storage + +The choice of which method to use is based on several criteria: + +- The source of the information. Information in calldata cannot come directly from the blockchain itself. +- The destination of the information. Calldata is available only in the transaction it initiates. Events are not accessible onchain at all. +- How much hassle is acceptable? Computers that run a full-scale node can perform more processing than a light client in an application running in a browser. +- Is it necessary to facilitate easy access to the information from every node? +- The security requirements. + +## The security requirements + +In general, information security consists of three attributes: + +- _Confidentiality_, unauthorized entities are not allowed to read the information. This is important in many cases, but not here. _There are no secrets on the blockchain_. Blockchains work because anybody can verify the state transitions, so it is impossible to use them to store secrets directly. There are ways to store confidential information on the blockchain, but they all rely on some offchain component to store at least a key. + +- _Integrity_, the information is correct, it cannot be changed by unauthorized entities, or in unauthorized ways (for example, transferring [ERC-20 tokens](https://eips.ethereum.org/EIPS/eip-20#events) without a `Transfer` event). On the blockchain, every node verifies every state change, which ensures integrity. + +- _Availability_, the information is available to any authorized entity. On the blockchain, this is usually achieved by having the information available on every [full node](https://ethereum.org/developers/docs/nodes-and-clients#full-node). + +The different solutions here all have excellent integrity, because hashes are posted on L1. However, they do have different availability guarantees. + +## Prerequisites + +You should have a good understanding of [blockchain fundamentals](/developers/docs/intro-to-ethereum/). This page also assumes the reader is familiar with [blocks](/developers/docs/blocks/), [transactions](/developers/docs/transactions/), and other relevant topics. + +## EIP-4844 blobs + +Starting with [the Dencun hardfork](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md) the Ethereum blockchain includes [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), which adds to Ethereum data blobs with a limited lifetime (initially about [18 days](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/p2p-interface.md#configuration)). These blobs are priced separately from the [execution gas](/developers/docs/gas), although using a similar mechanism. They are a cheap way to post temporary data. + +The main use case for EIP-4844 blobs is for rollups to publish their transactions. [Optimistic rollups](/developers/docs/scaling/optimistic-rollups) need to publish the transactions on their blockchains. Those transactions have to be available to anybody during the [challenge period](https://docs.optimism.io/connect/resources/glossary#challenge-period) to enable [validators](https://docs.optimism.io/connect/resources/glossary#validator) to fix the mistake if the rollup's [sequencer](https://docs.optimism.io/connect/resources/glossary#sequencer) posts an incorrect state root. + +However, once the challenge period has passed and the state root is finalized, the remaining purpose for knowing these transactions is to replicate the chain's current state. This state is also available from chain nodes, with a lot less processing required. So transaction information should still be preserved in a few places, such as [block explorers](/developers/docs/data-and-analytics/block-explorers), but there is no need to pay for the level of censorship resistance Ethereum provides. + +[Zero-knowledge rollups](/developers/docs/scaling/zk-rollups/#data-availability) also post their transaction data to enable other nodes to replicate the existing state and verify validity proofs, but again that is a short-term requirement. + +At writing posting on EIP-4844 costs one wei (10-18 ETH) per byte, which is negligible compared to [the 21,000 execution gas that any transaction, including one that posts blobs, costs](https://eth.blockscout.com/tx/0xf6cfaf0431c73dd1d96369a5e6707d64f463ccf477a4131265397f1d81466929?tab=index). You can see the current EIP-4844 price on [blobscan.com](https://blobscan.com/blocks). + +Here are the addresses to see the blobs posted by some famous rollups. + +| Rollup | Mailbox address | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | +| [Optimism](https://www.optimism.io/) | [`0xFF00000000000000000000000000000000000010`](https://blobscan.com/address/0xFF00000000000000000000000000000000000010) | +| [Arbitrum](https://arbitrum.io/) | [`0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6`](https://blobscan.com/address/0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6) | +| [Base](https://base.org/) | [`0xFF00000000000000000000000000000000008453`](https://blobscan.com/address/0xFF00000000000000000000000000000000008453) | + +## Calldata + +Calldata refers to the bytes sent as part of the transaction. It is stored as part of the permanent record of the blockchain in the block which includes that transaction. + +This is the cheapest method to permanently put data in the blockchain. The cost per byte is either 4 execution gas (if the byte is zero) or 16 gas (any other value). If the data is compressed, which is standard practice, then every byte value is equally likely, so the average cost is approximately 15.95 gas per byte. + +At the time of writing, the prices are 12 gwei/gas and 2300 $/ETH, which means the cost is approximately 45 cents per kilobyte. Because this was the cheapest method prior to EIP-4844, this is the method rollups used to store transaction information, which need to be available for [fault challenges](https://docs.optimism.io/stack/protocol/overview#fault-proofs), but do not need to be accessible directly onchain. + +Here are the addresses to see the transactions posted by some famous rollups. + +| Rollup | Mailbox address | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| [Optimism](https://www.optimism.io/) | [`0xFF00000000000000000000000000000000000010`](https://eth.blockscout.com/address/0xFF00000000000000000000000000000000000010) | +| [Arbitrum](https://arbitrum.io/) | [`0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6`](https://eth.blockscout.com/address/0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6) | +| [Base](https://base.org/) | [`0xFF00000000000000000000000000000000008453`](https://eth.blockscout.com/address/0xFF00000000000000000000000000000000008453) | + +## Offchain with L1 mechanisms + +Depending on your security tradeoffs, it might be acceptable to put the information elsewhere and use a mechanism that ensures the data is available when needed. There are two requirements for this to work: + +1. Post a [hash](https://en.wikipedia.org/wiki/Cryptographic_hash_function) of the data on the blockchain, called an _input commitment_. This can be a single 32-byte word, so it is not expensive. As long as the input commitment is available, integrity is assured because it's not feasible to find any other data that would hash to the same value. So if incorrect data is provided, it can be detected. + +2. Have a mechanism that ensures availability. For example, in [Redstone](https://redstone.xyz/docs/what-is-redstone) any node can submit an availability challenge. If the sequencer does not respond onchain by the deadline, the input commitment is discarded, so the information is considered never to have been posted. + +This is acceptable for an optimistic rollup because we are already relying on having at least one honest verifier for the state root. Such an honest verifier will also make sure it has the data to process blocks, and issue an availability challenge if the information is not available offchain. This type of optimistic rollup is called [plasma](/developers/docs/scaling/plasma/). + +## Contract code + +Information that only needs to be written once, never gets overwritten, and needs to be available onchain can be stored as contract code. This means that we create a "smart contract" with the data and then use [`EXTCODECOPY`](https://www.evm.codes/#3c?fork=shanghai) to read the information. The advantage is that copying code is relatively cheap. + +Other than the cost of memory expansion, `EXTCODECOPY` costs 2600 gas for the first access to a contract (when it is "cold") and 100 gas for subsequent copies from the same contract plus 3 gas per 32 byte word. Compared with calldata, which costs 15.95 per byte, this is cheaper starting at about 200 bytes. Based on [the formula for memory expansion costs](https://www.evm.codes/about#memoryexpansion), at long as you don't need more than 4MB of memory, the memory expansion cost is smaller than the cost of adding calldata. + +Of course, this is just the cost to _read_ the data. To create the contract costs approximately 32,000 gas + 200 gas/byte. This method is only economical when the same information needs to be read many times in different transactions. + +Contract code can be nonsensical, as long as it doesn't start with `0xEF`. Contracts that start with `0xEF` are interpreted as [ethereum object format](https://notes.ethereum.org/@ipsilon/evm-object-format-overview), which has much stricter requirements. + +## Events + +[Events](https://docs.alchemy.com/docs/solidity-events) are emitted by smart contracts, and read by offchain software. +Their advantage is that offchain code can listen for events. The cost is [gas](https://www.evm.codes/#a0?fork=cancun), 375 plus 8 gas per byte of data. At 12 gwei/gas and 2300 $/ETH, this translates to one cent plus 22 cents per kilobyte. + +## Storage + +Smart contracts have access to [persistent storage](https://docs.alchemy.com/docs/smart-contract-storage-layout#what-is-storage-memory). However, it is very expensive. Writing a 32 byte word to a previously empty storage slot can [cost 22,100 gas](https://www.evm.codes/#55?fork=cancun). At 12 gwei/gas and 2300 $/ETH, this is about 61 cents per write operation, or $19.5 per kilobyte. + +This is the most expensive form of storage in Ethereum. + +## Summary + +This table summarizes the difference options, their advantages and disadvantages. + +| Storage type | Source of data | Availability guarantee | Onchain availability | Additional limitations | +| --------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------- | +| EIP-4844 blobs | Offchain | Ethereum guarantee for [~18 days](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/p2p-interface.md#configuration) | Only hash is available | | +| Calldata | Offchain | Ethereum guarantee forever (part of the blockchain) | Only available if written to a contract, and at that transaction | +| Offchain with L1 mechanisms | Offchain | "One honest verifier" guarantee during the challenge period | Hash only | Guaranteed by the challenge mechanism, only during the challenge period | +| Contract code | Onchain or offchain | Ethereum guarantee forever (part of the blockchain) | Yes | Written to a "random" address, cannot start with `0xEF` | +| Events | Onchain | Ethereum guarantee forever (part of the blockchain) | No | +| Storage | Onchain | Ethereum guarantee forever (part of the blockchain and the present state until overwritten) | Yes | + +--- + +## Developers > Docs > Data Availability + +"Don't trust, verify" is a common maxim in Ethereum. The idea is that your node can independently verify that the information it receives is correct by executing all the transactions in the blocks they receive from peers to ensure that the changes proposed precisely match those computed independently by the node. This means nodes do not have to trust that the senders of the block are honest. This is not possible if data is missing. + +**Data availability** refers to the confidence a user can have that the data required to verify a block is really available to all network participants. For full nodes on Ethereum layer 1 this is relatively simple; the full node downloads a copy of all the data in each block - the data _has_ to be available for the downloading to be possible. A block with missing data would be discarded rather than being added to the blockchain. This is "onchain data availability" and it is a feature of monolithic blockchains. Full nodes cannot be tricked into accepting invalid transactions because they download and execute every transaction for themselves. However, for modular blockchains, layer 2 rollups and light clients, the data availability landscape is more complex, requiring some more sophisticated verification procedures. + +## Prerequisites + +You should have a good understanding of [blockchain fundamentals](/developers/docs/intro-to-ethereum/), especially [consensus mechanisms](/developers/docs/consensus-mechanisms/). This page also assumes the reader is familiar with [blocks](/developers/docs/blocks/), [transactions](/developers/docs/transactions/), [nodes](/developers/docs/nodes-and-clients/), [scaling solutions](/developers/docs/scaling/), and other relevant topics. + +## The data availability problem + +The data availability problem is the need to prove to the whole network that the summarized form of some transaction data that is being added to the blockchain really represents a set of valid transactions, but doing so without requiring all nodes to download all data. The full transaction data is necessary for independently verifying blocks, but requiring all nodes to download all transaction data is a barrier to scaling. Solutions to the data availability problem aim to provide sufficient assurances that the full transaction data was made available for verification to network participants that do not download and store the data for themselves. + +[Light nodes](/developers/docs/nodes-and-clients/light-clients) and [Layer 2 rollups](/developers/docs/scaling) are important examples of network participants that require strong data availability assurances but cannot download and process transaction data for themselves. Avoiding downloading transaction data is what makes light nodes light and enables rollups to be effective scaling solutions. + +Data availability is also a critical concern for future ["stateless"](/roadmap/statelessness) Ethereum clients that do not need to download and store state data in order to verify blocks. The stateless clients still need to be certain that the data is available _somewhere_ and that it has been processed correctly. + +## Data availability solutions + +### Data availability sampling (DAS) + +Data Availability Sampling (DAS) is a way for the network to check that data is available without putting too much strain on any individual node. Each node (including non-staking nodes) downloads some small, randomly selected subset of the total data. Successfully downloading the samples confirms with high confidence that all of the data is available. This relies upon data erasure coding, which expands a given dataset with redundant information (the way this is done is to fit a function known as a _polynomial_ over the data and evaluating that polynomial at additional points). This allows the original data to be recovered from the redundant data when necessary. A consequence of this data creation is that if _any_ of the original data is unavailable, _half_ of the expanded data will be missing! The amount of data samples downloaded by each node can be tuned so that it is _extremely_ likely that at least one of the data fragments sampled by each client will be missing _if_ less than half the data is really available. + +DAS will be used to ensure rollup operators make their transaction data available after [Full Danksharding](/roadmap/danksharding/#what-is-danksharding) has been implemented. Ethereum nodes will randomly sample the transaction data provided in blobs using the redundancy scheme explained above to ensure that all the data exists. The same technique could also be employed to ensure block producers are making all their data available to secure light clients. Similarly, under [proposer-builder separation](/roadmap/pbs), only the block builder would be required to process an entire block - other validators would verify using data availability sampling. + +### Data availability committees + +Data Availability Committees (DACs) are trusted parties that provide, or attest to, data availability. DACs can be used instead of, [or in combination with](https://hackmd.io/@vbuterin/sharding_proposal#Why-not-use-just-committees-and-not-DAS) DAS. The security guarantees that come with committees depends on the specific set up. Ethereum uses randomly sampled subsets of validators to attest to data availability for light nodes, for example. + +DACs are also used by some validiums. The DAC is a trusted set of nodes that stores copies of data offline. The DAC is required to make the data available in the event of a dispute. Members of the DAC also publish onchain attestations to prove that the said data is indeed available. Some validiums replace DACs with a proof-of-stake (PoS) validator system. Here, anyone can become a validator and store data offchain. However, they must provide a “bond”, which is deposited in a smart contract. In the event of malicious behavior, such as the validator withholding data, the bond can be slashed. Proof-of-stake data availability committees are considerably more secure than regular DACs because they directly incentivize honest behavior. + +## Data availability and light nodes + +[Light nodes](/developers/docs/nodes-and-clients/light-clients) need to validate the correctness of the block headers they receive without downloading the block data. The cost of this lightness is the inability to independently verify the block headers by re-executing transactions locally in the way full nodes do. + +Ethereum light nodes trust random sets of 512 validators that have been assigned to a _sync committee_. The sync committee acts as a DAC that signals to light clients that the data in the header is correct using a cryptographic signature. Every day, the sync committee refreshes. Each block header alerts light nodes as to which validators to expect to sign off the _next_ block, so they can't be tricked into trusting a malicious group pretending to be the real sync-committee. + +However, what happens if an attacker somehow _does_ manage to pass a malicious block header to light clients and convince them that it was signed off by an honest sync-committee? In that case, the attacker could include invalid transactions and the light client would blindly accept them, as they do not independently check all the state changes summarized in the block header. To protect against this, the light client could use fraud proofs. + +The way these fraud proofs work is that a full node, seeing an invalid state transition being gossiped around the network, could quickly generate a small piece of data demonstrating that a proposed state transition could not possibly arise from a given set of transactions and broadcast that data to peers. Light nodes could pick up those fraud-proofs and use them to discard bad block headers, ensuring they stay on the same honest chain as the full nodes. + +This relies on full nodes having access to full transaction data. An attacker who broadcasts a bad block header and also fails to make the transaction data available would be able to prevent full nodes from generating fraud proofs. The full nodes might be able to signal a warning about a bad block, but they couldn't back up their warning with proof, because the data wasn't made available to generate the proof from! + +The solution to this data availability problem is DAS. Light nodes download very small random chunks of the full state data and use the samples to verify that the full data set is available. The actual likelihood of incorrectly assuming full data availability after downloading N random chunks can be calculated ([for 100 chunks the chance is 10^-30](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html), i.e. incredibly unlikely). + +Even in this scenario, attacks that withhold just a few bytes could feasibly go unnoticed by clients making random data requests. Erasure coding fixes this by reconstructing small missing pieces of data that can be used to check proposed state changes. A fraud proof could then be constructed using the reconstructed data, preventing light nodes from accepting bad headers. + +**Note:** DAS and fraud proofs have not yet been implemented for proof-of-stake Ethereum light clients, but they are on the roadmap, most likely taking the form of ZK-SNARK based proofs. Today's light clients rely on a form of DAC: they verify the identities of the sync-committee and then trust the signed block headers they receive. + +## Data availability and layer 2 rollups + +[Layer 2 scaling solutions](/layer-2/), such as [rollups](/glossary/#rollups), reduce transaction costs and increase Ethereum's throughput by processing transactions offchain. Rollup transactions are compressed and posted on Ethereum in batches. Batches represent thousands of individual offchain transactions in a single transaction on Ethereum. This reduces congestion on the base layer and reduces fees for users. + +However, it is only possible to trust the 'summary' transactions posted to Ethereum if the state change proposed can be independently verified and confirmed to be the result of applying all the individual offchain transactions. If rollup operators do not make the transaction data available for this verification, then they could send incorrect data to Ethereum. + +[Optimistic rollups](/developers/docs/scaling/optimistic-rollups/) post compressed transaction data to Ethereum and wait for some amount of time (typically 7 days) to allow independent verifiers to check the data. If anyone identifies a problem, they can generate a fraud-proof and use it to challenge the rollup. This would cause the chain to roll back and omit the invalid block. This is only possible if data is available. Currently, there are two ways that optimistic rollups post transaction data to L1. Some rollups make data permanently available as `CALLDATA` which lives permanently onchain. With the implementation of EIP-4844, some rollups post their transaction data to cheaper blob storage instead. This is not permanent storage. Independent verifiers have to query the blobs and raise their challenges within ~18 days before the data is deleted from Ethereum layer-1. Data availability is only guaranteed by the Ethereum protocol for that short fixed window. After that, it becomes the responsibility of other entities in the Ethereum ecosystem. Any node can verify data availability using DAS, i.e. by downloading small, random samples of the blob data. + +[Zero-knowledge (ZK) rollups](/developers/docs/scaling/zk-rollups) don't need to post transaction data since [zero-knowledge validity proofs](/glossary/#zk-proof) guarantee the correctness of state transitions. However, data availability is still an issue because we can't guarantee the functionality of the ZK-rollup (or interact with it) without access to its state data. For example, users cannot know their balances if an operator withholds details about the rollup’s state. Also, they cannot perform state updates using information contained in a newly added block. + +## Data availability vs. data retrievability + +Data availability is different from data retrievability. Data availability is the assurance that full nodes have been able to access and verify the full set of transactions associated with a specific block. It does not necessarily follow that the data is accessible forever. + +Data retrievability is the ability of nodes to retrieve _historical information_ from the blockchain. This historical data is not needed for verifying new blocks, it is only required for syncing full nodes from the genesis block or serving specific historical requests. + +The core Ethereum protocol is primarily concerned with data availability, not data retrievability. Data retrievability can be provided by a small population of archive nodes run by third parties, or it can be distributed across the network using decentralized file storage such as the [Portal Network](https://www.ethportal.net/). + +## Further reading + +- [WTF is Data Availability?](https://medium.com/blockchain-capital-blog/wtf-is-data-availability-80c2c95ded0f) +- [What Is Data Availability?](https://coinmarketcap.com/alexandria/article/what-is-data-availability) +- [The Ethereum Offchain Data Availability Landscape](https://blog.celestia.org/ethereum-offchain-data-availability-landscape/) +- [A primer on data availability checks](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html) +- [An explanation of the sharding + DAS proposal](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) +- [A note on data availability and erasure coding](https://github.com/ethereum/research/wiki/A-note-on-data-availability-and-erasure-coding#can-an-attacker-not-circumvent-this-scheme-by-releasing-a-full-unavailable-block-but-then-only-releasing-individual-bits-of-data-as-clients-query-for-them) +- [Data availability committees.](https://medium.com/starkware/data-availability-e5564c416424) +- [Proof-of-stake data availability committees.](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) +- [Solutions to the data retrievability problem](https://notes.ethereum.org/@vbuterin/data_sharding_roadmap#Who-would-store-historical-data-under-sharding) +- [Data Availability Or: How Rollups Learned To Stop Worrying And Love Ethereum](https://research.2077.xyz/data-availability-or-how-rollups-learned-to-stop-worrying-and-love-ethereum) +- [EIP-7623: Increasing Calldata Cost](https://research.2077.xyz/eip-7623-increase-calldata-cost) + +--- + +## Developers > Docs > Data Structures And Encoding + +Ethereum creates, stores and transfers large volumes of data. This data must get formatted in standardized and memory-efficient ways to allow anyone to [run a node](/run-a-node/) on relatively modest consumer-grade hardware. To achieve this, several specific data structures are used on the Ethereum stack. + +## Prerequisites + +You should understand the fundamentals of Ethereum and [client software](/developers/docs/nodes-and-clients/). Familiarity with the networking layer and [the Ethereum whitepaper](/whitepaper/) is recommended. + +## Data structures + +### Patricia merkle tries + +Patricia Merkle Tries are structures that encode key-value pairs into a deterministic and cryptographically authenticated trie. These are used extensively across Ethereum's execution layer. + +[More on Patricia Merkle Tries](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) + +### Recursive Length Prefix + +Recursive Length Prefix (RLP) is a serialization method used extensively across Ethereum's execution layer. + +[More on RLP](/developers/docs/data-structures-and-encoding/rlp) + +### Simple Serialize + +Simple Serialize (SSZ) is the dominant serialization format on Ethereum's consensus layer because of its compatibility with merklelization. + +[More on SSZ](/developers/docs/data-structures-and-encoding/ssz) + +--- + +## Developers > Docs > Data Structures And Encoding > Patricia Merkle Trie + +The state of Ethereum (the totality of all accounts, balances, and smart contracts), is encoded into a special version of the data structure known generally in computer science as a Merkle Tree. This structure is useful for many applications in cryptography because it creates a verifiable relationship between all the individual pieces of data entangled in the tree, resulting in a single **root** value that can be used to prove things about the data. + +Ethereum's data structure is a 'modified Merkle-Patricia Trie', named so because it borrows some features of PATRICIA (the Practical Algorithm To Retrieve Information Coded in Alphanumeric), and because it is designed for efficient data re**trie**val of items that comprise the Ethereum state. + +A Merkle-Patricia trie is deterministic and cryptographically verifiable: The only way to generate a state root is by computing it from each individual piece of the state, and two states that are identical can be easily proven so by comparing the root hash and the hashes that led to it (_a Merkle proof_). Conversely, there is no way to create two different states with the same root hash, and any attempt to modify state with different values will result in a different state root hash. Theoretically, this structure provides the 'holy grail' of `O(log(n))` efficiency for inserts, lookups and deletes. + +In the near future, Ethereum plans to migrate to a [Verkle Tree](https://ethereum.org/en/roadmap/verkle-trees) structure, which will open up many new possibilities for future protocol improvements. + +## Prerequisites + +To better understand this page, it would be helpful to have basic knowledge of [hashes](https://en.wikipedia.org/wiki/Hash_function), [Merkle trees](https://en.wikipedia.org/wiki/Merkle_tree), [tries](https://en.wikipedia.org/wiki/Trie) and [serialization](https://en.wikipedia.org/wiki/Serialization). This article begins with a description of a basic [radix tree](https://en.wikipedia.org/wiki/Radix_tree), then gradually introduces the modifications necessary for Ethereum's more optimized data structure. + +## Basic radix tries + +In a basic radix trie, every node looks as follows: + +``` + [i_0, i_1 ... i_n, value] +``` + +Where `i_0 ... i_n` represent the symbols of the alphabet (often binary or hex), `value` is the terminal value at the node, and the values in the `i_0, i_1 ... i_n` slots are either `NULL` or pointers to (in our case, hashes of) other nodes. This forms a basic `(key, value)` store. + +Say you wanted to use a radix tree data structure for persisting an order over a set of key value pairs. To find the value currently mapped to the key `dog` in the trie, you would first convert `dog` into letters of the alphabet (giving `64 6f 67`), and then descend the trie following that path until you find the value. That is, you start by looking up the root hash in a flat key/value DB to find the root node of the trie. It is represented as an array of keys pointing to other nodes. You would use the value at index `6` as a key and look it up in the flat key/value DB to get the node one level down. Then pick index `4` to look up the next value, then pick index `6`, and so on, until, once you followed the path: `root -> 6 -> 4 -> 6 -> 15 -> 6 -> 7`, you would look up the value of the node and return the result. + +There is a difference between looking something up in the 'trie' and the underlying flat key/value 'DB'. They both define key/value arrangements, but the underlying DB can do a traditional 1 step lookup of a key. Looking up a key in the trie requires multiple underlying DB lookups to get to the final value described above. Let's refer to the latter as a `path` to eliminate ambiguity. + +The update and delete operations for radix tries can be defined as follows: + +```python + def update(node_hash, path, value): + curnode = db.get(node_hash) if node_hash else [NULL] * 17 + newnode = curnode.copy() + if path == "": + newnode[-1] = value + else: + newindex = update(curnode[path[0]], path[1:], value) + newnode[path[0]] = newindex + db.put(hash(newnode), newnode) + return hash(newnode) + + def delete(node_hash, path): + if node_hash is NULL: + return NULL + else: + curnode = db.get(node_hash) + newnode = curnode.copy() + if path == "": + newnode[-1] = NULL + else: + newindex = delete(curnode[path[0]], path[1:]) + newnode[path[0]] = newindex + + if all(x is NULL for x in newnode): + return NULL + else: + db.put(hash(newnode), newnode) + return hash(newnode) +``` + +A "Merkle" Radix tree is built by linking nodes using deterministically-generated cryptographic hash digests. This content-addressing (in the key/value DB `key == keccak256(rlp(value))`) provides a cryptographic integrity guarantee of the stored data. If the root hash of a given trie is publicly known, then anyone with access to the underlying leaf data can construct a proof that the trie includes a given value at a specific path by providing the hashes of each node joining a specific value to the tree root. + +It is impossible for an attacker to provide a proof of a `(path, value)` pair that does not exist since the root hash is ultimately based on all hashes below it. Any underlying modification would change the root hash. You can think of the hash as a compressed representation of structural information about the data, secured by the pre-image protection of the hashing function. + +We'll refer to an atomic unit of a radix tree (e.g. a single hex character, or 4 bit binary number) as a "nibble". While traversing a path one nibble at a time, as described above, nodes can maximally refer to 16 children but include a `value` element. We, hence, represent them as an array of length 17. We call these 17-element arrays "branch nodes". + +## Merkle Patricia Trie + +Radix tries have one major limitation: they are inefficient. If you want to store one `(path, value)` binding where the path, like in Ethereum, is 64 characters long (the number of nibbles in `bytes32`), we will need over a kilobyte of extra space to store one level per character, and each lookup or delete will take the full 64 steps. The Patricia trie introduced in the following solves this issue. + +### Optimization + +A node in a Merkle Patricia trie is one of the following: + +1. `NULL` (represented as the empty string) +2. `branch` A 17-item node `[ v0 ... v15, vt ]` +3. `leaf` A 2-item node `[ encodedPath, value ]` +4. `extension` A 2-item node `[ encodedPath, key ]` + +With 64 character paths it is inevitable that after traversing the first few layers of the trie, you will reach a node where no divergent path exists for at least part of the way down. To avoid having to create up to 15 sparse `NULL` nodes along the path, we shortcut the descent by setting up an `extension` node of the form `[ encodedPath, key ]`, where `encodedPath` contains the "partial path" to skip ahead (using a compact encoding described below), and the `key` is for the next DB lookup. + +For a `leaf` node, which can be marked by a flag in the first nibble of the `encodedPath`, the path encodes all prior node's path fragments and we can look up the `value` directly. + +This above optimization, however, introduces ambiguity. + +When traversing paths in nibbles, we may end up with an odd number of nibbles to traverse, but because all data is stored in `bytes` format. It is not possible to differentiate between, for instance, the nibble `1`, and the nibbles `01` (both must be stored as ``). To specify odd length, the partial path is prefixed with a flag. + +### Specification: Compact encoding of hex sequence with optional terminator + +The flagging of both _odd vs. even remaining partial path length_ and _leaf vs. extension node_ as described above reside in the first nibble of the partial path of any 2-item node. They result in the following: + +| hex char | bits | node type partial | path length | +| -------- | ---- | ------------------ | ----------- | +| 0 | 0000 | extension | even | +| 1 | 0001 | extension | odd | +| 2 | 0010 | terminating (leaf) | even | +| 3 | 0011 | terminating (leaf) | odd | + +For even remaining path length (`0` or `2`), another `0` "padding" nibble will always follow. + +```python + def compact_encode(hexarray): + term = 1 if hexarray[-1] == 16 else 0 + if term: + hexarray = hexarray[:-1] + oddlen = len(hexarray) % 2 + flags = 2 * term + oddlen + if oddlen: + hexarray = [flags] + hexarray + else: + hexarray = [flags] + [0] + hexarray + # hexarray now has an even length whose first nibble is the flags. + o = "" + for i in range(0, len(hexarray), 2): + o += chr(16 * hexarray[i] + hexarray[i + 1]) + return o +``` + +Examples: + +```python + > [1, 2, 3, 4, 5, ...] + '11 23 45' + > [0, 1, 2, 3, 4, 5, ...] + '00 01 23 45' + > [0, f, 1, c, b, 8, 10] + '20 0f 1c b8' + > [f, 1, c, b, 8, 10] + '3f 1c b8' +``` + +Here is the extended code for getting a node in the Merkle Patricia trie: + +```python + def get_helper(node_hash, path): + if path == []: + return node_hash + if node_hash == "": + return "" + curnode = rlp.decode(node_hash if len(node_hash) `, although _values_ are still shown as strings, denoted by `''`, for easier comprehension (they, too, would actually be `bytes`): + +``` + : 'verb' + : 'puppy' + : 'coins' + : 'stallion' +``` + +Now, we build such a trie with the following key/value pairs in the underlying DB: + +``` + rootHash: [ , hashA ] + hashA: [ <>, <>, <>, <>, hashB, <>, <>, <>, [ , 'stallion' ], <>, <>, <>, <>, <>, <>, <>, <> ] + hashB: [ , hashC ] + hashC: [ <>, <>, <>, <>, <>, <>, hashD, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'verb' ] + hashD: [ , [ <>, <>, <>, <>, <>, <>, [ , 'coins' ], <>, <>, <>, <>, <>, <>, <>, <>, <>, 'puppy' ] ] +``` + +When one node is referenced inside another node, what is included is `H(rlp.encode(node))`, where `H(x) = keccak256(x) if len(x) >= 32 else x` and `rlp.encode` is the [RLP](/developers/docs/data-structures-and-encoding/rlp) encoding function. + +Note that when updating a trie, one needs to store the key/value pair `(keccak256(x), x)` in a persistent lookup table _if_ the newly-created node has length >= 32. However, if the node is shorter than that, one does not need to store anything, since the function f(x) = x is reversible. + +## Tries in Ethereum + +All of the merkle tries in Ethereum's execution layer use a Merkle Patricia Trie. + +From a block header there are 3 roots from 3 of these tries. + +1. stateRoot +2. transactionsRoot +3. receiptsRoot + +### State Trie + +There is one global state trie, and it is updated every time a client processes a block. In it, a `path` is always: `keccak256(ethereumAddress)` and a `value` is always: `rlp(ethereumAccount)`. More specifically an ethereum `account` is a 4 item array of `[nonce,balance,storageRoot,codeHash]`. At this point, it's worth noting that this `storageRoot` is the root of another patricia trie: + +### Storage Trie + +Storage trie is where _all_ contract data lives. There is a separate storage trie for each account. To retrieve values at specific storage positions at a given address the storage address, integer position of the stored data in the storage, and the block ID are required. These can then be passed as arguments to the `eth_getStorageAt` defined in the JSON-RPC API, e.g. to retrieve the data in storage slot 0 for address `0x295a70b2de5e3953354a6a8344e616ed314d7251`: + +```bash +curl -X POST --data '' localhost:8545 + + + +``` + +Retrieving other elements in storage is slightly more involved because the position in the storage trie must first be calculated. The position is calculated as the `keccak256` hash of the address and the storage position, both left-padded with zeros to a length of 32 bytes. For example, the position for the data in storage slot 1 for address `0x391694e7e0b0cce554cb130d723a9d27458f9298` is: + +```python +keccak256(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001")) +``` + +In a Geth console, this can be calculated as follows: + +``` +> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001" +undefined +> web3.sha3(key, ) +"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9" +``` + +The `path` is therefore `keccak256()`. This can now be used to retrieve the data from the storage trie as before: + +```bash +curl -X POST --data '' localhost:8545 + + +``` + +Note: The `storageRoot` for an Ethereum account is empty by default if it's not a contract account. + +### Transactions Trie + +There is a separate transactions trie for every block, again storing `(key, value)` pairs. A path here is: `rlp(transactionIndex)` which represents the key that corresponds to a value determined by: + +```python +if legacyTx: + value = rlp(tx) +else: + value = TxType | encode(tx) +``` + +More information on this can be found in the [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) documentation. + +### Receipts Trie + +Every block has its own Receipts trie. A `path` here is: `rlp(transactionIndex)`. `transactionIndex` is its index within the block it was included in. The receipts trie is never updated. Similar to the Transactions trie, there are current and legacy receipts. To query a specific receipt in the Receipts trie, the index of the transaction in its block, the receipt payload and the transaction type are required. The Returned receipt can be of type `Receipt` which is defined as the concatenation of `TransactionType` and `ReceiptPayload` or it can be of type `LegacyReceipt` which is defined as `rlp([status, cumulativeGasUsed, logsBloom, logs])`. + +More information on this can be found in the [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) documentation. + +## Further Reading + +- [Modified Merkle Patricia Trie — How Ethereum saves a state](https://medium.com/codechain/modified-merkle-patricia-trie-how-ethereum-saves-a-state-e6d7555078dd) +- [Merkling in Ethereum](https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/) +- [Understanding the Ethereum trie](https://easythereentropy.wordpress.com/2014/06/04/understanding-the-ethereum-trie/) + +--- + +## Developers > Docs > Data Structures And Encoding > Rlp + +Recursive Length Prefix (RLP) serialization is used extensively in Ethereum's execution clients. RLP standardizes the transfer of data between nodes in a space-efficient format. The purpose of RLP is to encode arbitrarily nested arrays of binary data, and RLP is the primary encoding method used to serialize objects in Ethereum's execution layer. The main purpose of RLP is to encode structure; with the exception of positive integers, RLP delegates encoding specific data types (e.g. strings, floats) to higher-order protocols. Positive integers must be represented in big-endian binary form with no leading zeroes (thus making the integer value zero equivalent to the empty byte array). Deserialized positive integers with leading zeroes must be treated as invalid by any higher-order protocol using RLP. + +More information in [the Ethereum yellow paper (Appendix B)](https://ethereum.github.io/yellowpaper/paper.pdf#page=19). + +To use RLP to encode a dictionary, the two suggested canonical forms are: + +- use `[[k1,v1],[k2,v2]...]` with keys in lexicographic order +- use the higher-level Patricia Tree encoding as Ethereum does + +## Definition + +The RLP encoding function takes in an item. An item is defined as follows: + +- a string (i.e. byte array) is an item +- a list of items is an item +- a positive integer is an item + +For example, all of the following are items: + +- an empty string; +- the string containing the word "cat"; +- a list containing any number of strings; +- and a more complex data structures like `["cat", ["puppy", "cow"], "horse", [[]], "pig", [""], "sheep"]`. +- the number `100` + +Note that in the context of the rest of this page, 'string' means "a certain number of bytes of binary data"; no special encodings are used, and no knowledge about the content of the strings is implied (except as required by the rule against non-minimal positive integers). + +RLP encoding is defined as follows: + +- For a positive integer, it is converted to the shortest byte array whose big-endian interpretation is the integer, and then encoded as a string according to the rules below. +- For a single byte whose value is in the `[0x00, 0x7f]` (decimal `[0, 127]`) range, that byte is its own RLP encoding. +- Otherwise, if a string is 0-55 bytes long, the RLP encoding consists of a single byte with value **0x80** (dec. 128) plus the length of the string followed by the string. The range of the first byte is thus `[0x80, 0xb7]` (dec. `[128, 183]`). +- If a string is more than 55 bytes long, the RLP encoding consists of a single byte with value **0xb7** (dec. 183) plus the length in bytes of the length of the string in binary form, followed by the length of the string, followed by the string. For example, a 1024 byte long string would be encoded as `\xb9\x04\x00` (dec. `185, 4, 0`) followed by the string. Here, `0xb9` (183 + 2 = 185) as the first byte, followed by the 2 bytes `0x0400` (dec. 1024) that denote the length of the actual string. The range of the first byte is thus `[0xb8, 0xbf]` (dec. `[184, 191]`). +- If a string is 2^64 bytes long, or longer, it may not be encoded. +- If the total payload of a list (i.e. the combined length of all its items being RLP encoded) is 0-55 bytes long, the RLP encoding consists of a single byte with value **0xc0** plus the length of the payload followed by the concatenation of the RLP encodings of the items. The range of the first byte is thus `[0xc0, 0xf7]` (dec. `[192, 247]`). +- If the total payload of a list is more than 55 bytes long, the RLP encoding consists of a single byte with value **0xf7** plus the length in bytes of the length of the payload in binary form, followed by the length of the payload, followed by the concatenation of the RLP encodings of the items. The range of the first byte is thus `[0xf8, 0xff]` (dec. `[248, 255]`). + +In code, this is: + +```python +def rlp_encode(input): + if isinstance(input,str): + if len(input) == 1 and ord(input) prefix - 0x80: + strLen = prefix - 0x80 + return (1, strLen, str) + elif prefix prefix - 0xb7 and length > prefix - 0xb7 + to_integer(substr(input, 1, prefix - 0xb7)): + lenOfStrLen = prefix - 0xb7 + strLen = to_integer(substr(input, 1, lenOfStrLen)) + return (1 + lenOfStrLen, strLen, str) + elif prefix prefix - 0xc0: + listLen = prefix - 0xc0; + return (1, listLen, list) + elif prefix prefix - 0xf7 and length > prefix - 0xf7 + to_integer(substr(input, 1, prefix - 0xf7)): + lenOfListLen = prefix - 0xf7 + listLen = to_integer(substr(input, 1, lenOfListLen)) + return (1 + lenOfListLen, listLen, list) + raise Exception("input does not conform to RLP encoding form") + +def to_integer(b): + length = len(b) + if length == 0: + raise Exception("input is null") + elif length == 1: + return ord(b[0]) + return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256 +``` + +## Further reading + +- [RLP in Ethereum](https://medium.com/coinmonks/data-structure-in-ethereum-episode-1-recursive-length-prefix-rlp-encoding-decoding-d1016832f919) +- [Ethereum under the hood: RLP](https://medium.com/coinmonks/ethereum-under-the-hood-part-3-rlp-decoding-df236dc13e58) +- [Coglio, A. (2020). Ethereum's Recursive Length Prefix in ACL2. arXiv preprint arXiv:2009.13769.](https://arxiv.org/abs/2009.13769) + +## Related topics + +- [Patricia merkle trie](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) + +--- + +## Developers > Docs > Data Structures And Encoding > Ssz + +**Simple serialize (SSZ)** is the serialization method used on the Beacon Chain. It replaces the RLP serialization used on the execution layer everywhere across the consensus layer except the peer discovery protocol. To learn more about RLP serialization, see [Recursive-length prefix (RLP)](/developers/docs/data-structures-and-encoding/rlp/). SSZ is designed to be deterministic and also to Merkleize efficiently. SSZ can be thought of as having two components: a serialization scheme and a Merkleization scheme that is designed to work efficiently with the serialized data structure. + +## How does SSZ work? + +### Serialization + +SSZ is a serialization scheme that is not self-describing - rather it relies on a schema that must be known in advance. The goal of SSZ serialization is to represent objects of arbitrary complexity as strings of bytes. This is a very simple process for "basic types". The element is simply converted to hexadecimal bytes. Basic types include: + +- unsigned integers +- Booleans + +For complex "composite" types, serialization is more complicated because the composite type contains multiple elements that might have different types or different sizes, or both. Where these objects all have fixed lengths (i.e. the size of the elements is always going to be constant irrespective of their actual values) the serialization is simply a conversion of each element in the composite type ordered into little-endian bytestrings. These bytestrings are joined together. The serialized object has the bytelist representation of the fixed-length elements in the same order as they appear in the deserialized object. + +For types with variable lengths, the actual data gets replaced by an "offset" value in that element's position in the serialized object. The actual data gets added to a heap at the end of the serialized object. The offset value is the index for the start of the actual data in the heap, acting as a pointer to the relevant bytes. + +The example below illustrates how the offsetting works for a container with both fixed and variable-length elements: + +```Rust + + struct Dummy + + dummy = Dummy + + serialized = ssz.serialize(dummy) + +``` + +`serialized` would have the following structure (only padded to 4 bits here, padded to 32 bits in reality, and keeping the `int` representation for clarity): + +``` +[37, 0, 0, 0, 55, 0, 0, 0, 16, 0, 0, 0, 22, 0, 0, 0, 1, 2, 3, 4] +------------ ----------- ----------- ----------- ---------- + | | | | | + number1 number2 offset for number 3 value for + vector vector + +``` + +divided over lines for clarity: + +``` +[ + 37, 0, 0, 0, # little-endian encoding of `number1`. + 55, 0, 0, 0, # little-endian encoding of `number2`. + 16, 0, 0, 0, # The "offset" that indicates where the value of `vector` starts (little-endian 16). + 22, 0, 0, 0, # little-endian encoding of `number3`. + 1, 2, 3, 4, # The actual values in `vector`. +] +``` + +This is still a simplification - the integers and zeros in the schematics above would actually be stored bytelists, like this: + +``` +[ + 10100101000000000000000000000000 # little-endian encoding of `number1` + 10110111000000000000000000000000 # little-endian encoding of `number2`. + 10010000000000000000000000000000 # The "offset" that indicates where the value of `vector` starts (little-endian 16). + 10010110000000000000000000000000 # little-endian encoding of `number3`. + 10000001100000101000001110000100 # The actual value of the `bytes` field. +] +``` + +So the actual values for variable-length types are stored in a heap at the end of the serialized object with their offsets stored in their correct positions in the ordered list of fields. + +There are also some special cases that require specific treatment, such as the `BitList` type that requires a length cap to be added during serialization and removed during deserialization. Full details are available in the [SSZ spec](https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md). + +### Deserialization + +To deserialize this object requires the schema. The schema defines the precise layout of the serialized data so that each specific element can be deserialized from a blob of bytes into some meaningful object with the elements having the right type, value, size and position. It is the schema that tells the deserializer which values are actual values and which ones are offsets. All field names disappear when an object is serialized, but reinstantiated on deserialization according to the schema. + +See [ssz.dev](https://www.ssz.dev/overview) for an interactive explainer on this. + +## Merkleization + +This SSZ serialized object can then be merkleized - that is transformed into a Merkle-tree representation of the same data. First, the number of 32-byte chunks in the serialized object is determined. These are the "leaves" of the tree. The total number of leaves must be a power of 2 so that hashing together the leaves eventually produces a single hash-tree-root. If this is not naturally the case, additional leaves containing 32 bytes of zeros are added. Diagrammatically: + +``` + hash tree root + / \ + / \ + / \ + / \ + hash of leaves hash of leaves + 1 and 2 3 and 4 + / \ / \ + / \ / \ + / \ / \ + leaf1 leaf2 leaf3 leaf4 +``` + +There are also cases where the leaves of the tree do not naturally evenly distribute in the way they do in the example above. For example, leaf 4 could be a container with multiple elements that require additional "depth" to be added to the Merkle tree, creating an uneven tree. + +Instead of referring to these tree elements as leaf X, node X etc, we can give them generalized indices, starting with root = 1 and counting from left to right along each level. This is the generalized index explained above. Each element in the serialized list has a generalized index equal to `2**depth + idx` where idx is its zero-indexed position in the serialized object and the depth is the number of levels in the Merkle tree, which can be determined as the base-two logarithm of the number of elements (leaves). + +## Generalized indices + +A generalized index is an integer that represents a node in a binary Merkle tree where each node has a generalized index `2 ** depth + index in row`. + +``` + 1 --depth = 0 2**0 + 0 = 1 + 2 3 --depth = 1 2**1 + 0 = 2, 2**1+1 = 3 + 4 5 6 7 --depth = 2 2**2 + 0 = 4, 2**2 + 1 = 5... + +``` + +This representation yields a node index for each piece of data in the Merkle tree. + +## Multiproofs + +Providing the list of generalized indices representing a specific element allows us to verify it against the hash-tree-root. This root is our accepted version of reality. Any data we are provided can be verified against that reality by inserting it into the right place in the Merkle tree (determined by its generalized index) and observing that the root remains constant. There are functions in the spec [here](https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#merkle-multiproofs) that show how to compute the minimal set of nodes required to verify the contents of a particular set of generalized indices. + +For example, to verify data in index 9 in the tree below, we need the hash of the data at indices 8, 9, 5, 3, 1. +The hash of (8,9) should equal hash (4), which hashes with 5 to produce 2, which hashes with 3 to produce the tree root 1. If incorrect data was provided for 9, the root would change - we would detect this and fail to verify the branch. + +``` +* = data required to generate proof + + 1* + 2 3* + 4 5* 6 7 +8* 9* 10 11 12 13 14 15 + +``` + +## Further reading + +- [Upgrading Ethereum: SSZ](https://eth2book.info/altair/part2/building_blocks/ssz) +- [Upgrading Ethereum: Merkleization](https://eth2book.info/altair/part2/building_blocks/merkleization) +- [SSZ implementations](https://github.com/ethereum/consensus-specs/issues/2138) +- [SSZ calculator](https://simpleserialize.com/) +- [SSZ.dev](https://www.ssz.dev/) + +--- + +## Developers > Docs > Data Structures And Encoding > Web3 Secret Storage + +To make your app work on Ethereum, you can use the web3 object provided by the web3.js library. Under the hood it communicates to a local node through RPC calls. [web3](https://github.com/ethereum/web3.js/) works with any Ethereum node which exposes an RPC layer. + +`web3` contains the `eth` object - web3.eth. + +```js +var fs = require("fs") +var recognizer = require("ethereum-keyfile-recognizer") + +fs.readFile("keyfile.json", (err, data) => ) + +/** result + * [ 'web3', 3 ] web3 (v3) keyfile + * [ 'ethersale', undefined ] Ethersale keyfile + * null invalid keyfile + */ +``` + +This documents **version 3** of the Web3 Secret Storage Definition. + +## Definition + +The actual encoding and decoding of the file remains largely unchanged from version 1, except that the crypto algorithm is no longer fixed to AES-128-CBC (AES-128-CTR is now the minimal requirement). Most of the meanings/algorithm are similar to version 1, except `mac`, which is given as the SHA3 (keccak-256) of the concatenations of the second-leftmost 16 bytes of the derived key together with the full `ciphertext`. + +Secret key files are stored directly in `~/.web3/keystore` (for Unix-like systems) and `~/AppData/Web3/keystore` (for Windows). They may be named anything, but a good convention is `.json`, where `` is the 128-bit UUID given to the secret key (a privacy-preserving proxy for the secret key's address). + +All such files have an associated password. To derive a given `.json` file's secret key, first derive the file's encryption key; this is done through taking the file's password and passing it through a key derivation function as described by the `kdf` key. KDF-dependent static and dynamic parameters to the KDF function are described in `kdfparams` key. + +PBKDF2 must be supported by all minimally-compliant implementations, denoted though: + +- `kdf`: `pbkdf2` + +For PBKDF2, the kdfparams include: + +- `prf`: Must be `hmac-sha256` (may be extended in the future); +- `c`: number of iterations; +- `salt`: salt passed to PBKDF; +- `dklen`: length for the derived key. Must be >= 32. + +Once the file's key has been derived, it should be verified through the derivation of the MAC. The MAC should be calculated as the SHA3 (keccak-256) hash of the byte array formed as the concatenations of the second-leftmost 16 bytes of the derived key with the `ciphertext` key's contents, i.e.: + +```js +KECCAK(DK[16..31] ++ ) +``` + +(where `++` is the concatenation operator) + +This value should be compared to the contents of the `mac` key; if they are different, an alternative password should be requested (or the operation cancelled). + +After the file's key has been verified, the cipher text (the `ciphertext` key in the file) may be decrypted using the symmetric encryption algorithm specified by the `cipher` key and parameterised through the `cipherparams` key. If the derived key size and the algorithm's key size are mismatched, the zero padded, rightmost bytes of the derived key should be used as the key to the algorithm. + +All minimally-compliant implementations must support the AES-128-CTR algorithm, denoted through: + +- `cipher: aes-128-ctr` + +This cipher takes the following parameters, given as keys to the cipherparams key: + +- `iv`: 128-bit initialisation vector for the cipher. + +The key for the cipher is the leftmost 16 bytes of the derived key, i.e. `DK[0..15]` + +The creation/encryption of a secret key should be essentially the reverse of these instructions. Make sure the `uuid`, `salt` and `iv` are actually random. + +In addition to the `version` field, which should act as a "hard" identifier of version, implementations may also use `minorversion` to track smaller, non-breaking changes to the format. + +## Test Vectors + +Details: + +- `Address`: `008aeeda4d805471df9b2a5b0f38a0c3bcba786b` +- `ICAP`: `XE542A5PZHH8PYIZUBEJEO0MFWRAPPIL67` +- `UUID`: `3198bc9c-6672-5ab3-d9954942343ae5b6` +- `Password`: `testpassword` +- `Secret`: `7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d` + +### PBKDF2-SHA-256 + +Test vector using `AES-128-CTR` and `PBKDF2-SHA-256`: + +File contents of `~/.web3/keystore/3198bc9c-6672-5ab3-d9954942343ae5b6.json`: + +```json +, + "ciphertext": "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", + "kdf": "pbkdf2", + "kdfparams": , + "mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2" + }, + "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version": 3 +} +``` + +**Intermediates**: + +`Derived key`: `f06d69cdc7da0faffb1008270bca38f5e31891a3a773950e6d0fea48a7188551` +`MAC Body`: `e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46` +`MAC`: `517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2` +`Cipher key`: `f06d69cdc7da0faffb1008270bca38f5` + +### Scrypt + +Test vector using AES-128-CTR and Scrypt: + +```json +, + "ciphertext": "dd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2", + "kdf": "scrypt", + "kdfparams": , + "mac": "337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c" + }, + "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version": 3 +} +``` + +**Intermediates**: + +`Derived key`: `7446f59ecc301d2d79bc3302650d8a5cedc185ccbb4bf3ca1ebd2c163eaa6c2d` +`MAC Body`: `edc185ccbb4bf3ca1ebd2c163eaa6c2ddd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2` +`MAC`: `337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c` +`Cipher key`: `7446f59ecc301d2d79bc3302650d8a5c` + +## Alterations from Version 1 + +This version fixes several inconsistencies with the version 1 published [here](https://github.com/ethereum/homestead-guide/blob/master/old-docs-for-reference/go-ethereum-wiki.rst/Passphrase-protected-key-store-spec.rst). In brief these are: + +- Capitalisation is unjustified and inconsistent (scrypt lowercase, Kdf mixed-case, MAC uppercase). +- Address unnecessary and compromises privacy. +- `Salt` is intrinsically a parameter of the key derivation function and deserves to be associated with it, not with the crypto in general. +- _SaltLen_ unnecessary (just derive it from Salt). +- The key derivation function is given, yet the crypto algorithm is hard specified. +- `Version` is intrinsically numeric yet is a string (structured versioning would be possible with a string, but can be considered out of scope for a rarely changing configuration file format). +- `KDF` and `cipher` are notionally sibling concepts yet are organised differently. +- `MAC` is calculated through a whitespace agnostic piece of data(!) + +Changes have been made to the format to give the following file, functionally equivalent to the example given on the previously linked page: + +```json +, + "kdf": "scrypt", + "kdfparams": , + "mac": "8ccded24da2e99a11d48cda146f9cc8213eb423e2ea0d8427f41c3be414424dd", + "version": 1 + }, + "id": "0498f19a-59db-4d54-ac95-33901b4f1870", + "version": 2 +} +``` + +## Alterations from Version 2 + +Version 2 was an early C++ implementation with a number of bugs. All essentials remain unchanged from it. + +--- + +## Developers > Docs > Design And Ux > Dex Design Best Practice + +Since the launch of Uniswap in 2018, there have been hundreds of decentralized exchanges launched across dozens of different chains. +Many of these introduced new elements or added their own twist, but the interface has remained generally the same. + +One reason for this is [Jakob’s Law](https://lawsofux.com/jakobs-law/): + +> Users spend most of their time on other sites. This means that users prefer your site to work the same way as all the other sites they already know. + +Thanks to early innovators like Uniswap, Pancakeswap, and Sushiswap, DeFi users have a collective idea of what a DEX looks like. +For this reason, something like “best practice” is now emerging. We see more and more design decisions being standardized across sites. You can see the evolution of DEXes as a giant example of testing it live. Things that worked stayed, things that didn’t, got tossed out. There’s still room for personality, but there are certain standards a DEX should conform to. + +This article is a summary of: +- what to include +- how to make it as usable as possible +- the main ways to customize the design + +All of the example wireframes were made specifically for this article, although they are all based on real projects. + +The Figma kit is also included at the bottom - feel free to use it and speed up your own wireframes! + +## Basic anatomy of a DEX + +The UI generally contains three elements: +1. Main form +2. Button +3. Details panel + +![Generic DEX UI, showing the three main elements](./1.png) + + +## Variations + +This will be a common theme in this article, but there are various different ways these elements can be organized. The “details panel” can be: +- Above the button +- Below the button +- Hidden in an accordion panel +- And/or on a “preview” modal + +N.B. A “preview” modal is optional, but if you are showing very few details on the main UI, it becomes essential. + +## Structure of the main form + +This is the box where you actually choose which token you want to swap. The component consists of an input field and a small button in a row. + +DEXes typically display additional details in one row above and one row below, although this can be configured differently. + +![Input row, with a details row above and below](./2.png) + +## Variations + +Two UI variations are shown here; one without any borders, creating a very open design, and one where the input row has a border, creating a focus on that element. + +![Two UI variations of the main form](./3.png) + +This basic structure allows **four key pieces of info** to be shown in the design: one in each corner. If there is only one top/bottom row, then there are only two spots. + +During the evolution of DeFi, lots of different things have been included here. + +## Key info to include + +- Balance in wallet +- Max button +- Fiat equivalent +- Price impact on the “received” amount + +In the early days of DeFi, the fiat equivalent was often missing. If you are building any sort of Web3 project, it is essential that a fiat equivalent is shown. Users still think in terms of local currencies, so in order to match real world mental models, this should be included. + +On the second field (the one where you choose the token you are swapping to) you can also include the price impact next to the fiat currency amount, by calculating the difference between the input amount and estimated output amounts. This is quite a useful detail to include. + +Percentage buttons (e.g. 25%, 50%, 75%) can be a useful feature, but they take up more space, add more call to actions, and add more mental load. Same with percentage sliders. Some of these UI decisions will depend on your brand and your user type. + +Extra details can be shown below the main form. As this type of info is mostly for pro users, it makes sense to either: +- keep it as minimal as possible, or; +- hide it in an accordion panel + +![Details shown in the corners of that main form](./4.png) + +## Extra info to include + +- Token price +- Slippage +- Minimum received +- Expected output +- Price impact +- Gas cost estimate +- Other fees +- Order routing + +Arguably, some of these details could be optional. + +Order routing is interesting, but doesn’t make much difference to most users. + +Some other details are simply restating the same thing in different ways. For example “minimum received” and “slippage” are two sides of the same coin. If you have slippage set at 1%, then the minimum you can expect to receive = expected output-1%. Some UIs will show expected amount, minimum amount, and slippage… Which is useful but possibly overkill. + +Most users will leave default slippage anyway. + +“Price impact” is often shown in brackets next to the fiat equivalent in the “to” field. This is a great ux detail to add, but if it is shown here, does it really need to be shown again below? And then again on a preview screen? + +Many users (especially those swapping small amounts) will not care about these details; they will simply enter a number and hit swap. + +![Some details show the same thing](./5.png) + +Exactly what details are shown will depend on your audience and what feel you want the app to have. + +If you do include slippage tolerance in the details panel, you should also make it editable directly from here. This is a good example of an “accelerator”; a neat UX trick that can speed up experienced users’ flows, without impacting the general usability of the app. + +![Slippage can be controlled from the details panel](./6.png) + +It’s a good idea to think carefully about not just one specific piece of information on one screen, but about the entire flow through: +Entering numbers in Main Form → Scanning Details → Clicking to Preview Screen (if you have a preview screen). +Should the details panel be visible at all times, or does the user need to click it to expand? +Should you create friction by adding a preview screen? This forces the user to slow down and consider their trade, which can be useful. But do they want to see all the same info again? What is most useful to them at this point? + +## Design options + +As mentioned, a lot of this comes down to your personal style +Who is your user? +What is your brand? +Do you want a “pro” interface showing every detail, or do you want to be minimalist? +Even if you’re aiming for the pro users who want all info possible, you should still remember Alan Cooper’s wise words: + +> No matter how beautiful, no matter how cool your interface, it would be better if there were less of it. + +### Structure + +- tokens on the left, or tokens on the right +- 2 rows or 3 +- details above or below the button +- details expanded, minimized, or not shown + +### Component style + +- empty +- outlined +- filled + +From a pure UX point of view, UI style matters less than you think. Visual trends come and go in cycles, and a lot of preference is subjective. + +The easiest way to get a feel for this - and think about the various different configurations - is to take a look at some examples and then do some experimenting yourself. + +The included Figma kit contains empty, outlined and filled components. + +Take a look at the below examples to see different ways you can put it all together: + +![3 rows in a filled style](./7.png) + +![3 rows in a outlined style](./8.png) + +![2 rows in an empty style](./9.png) + +![3 rows in an outlined style, with a details panel](./10.png) + +![3 rows with the input row in an outlined style](./11.png) + +![2 rows in a filled style](./12.png) + +## But which side should the token go on? + +The bottom line is that it probably doesn’t make a huge difference to usability. There are a few things to bear in mind, however, which might sway you one way or the other. + +It’s been mildly interesting to see the fashion change with time. Uniswap initially had the token on the left, but has since moved it to the right. Sushiswap also made this change during a design upgrade. Most, but not all, protocols have followed suit. + +Financial convention traditionally puts the currency symbol before the number, e.g. $50, €50, £50, but we *say* 50 dollars, 50 Euros, 50 pounds. + +To the general user - especially someone who reads left to right, top to bottom - token on the right probably feels more natural. + +![A UI with tokens on the left](./13.png) + +Putting the token on the left and all the numbers on the right looks pleasingly symmetrical, which is a plus, but there is another downside to this layout. + +The law of proximity states that items that are close together are perceived as related. Accordingly, we want to place related items next to each other. The token balance is directly related to the token itself, and will change whenever a new token is selected. It therefore makes slightly more sense for the token balance to be next to the token select button. It could be moved underneath the token, but that breaks the symmetry of the layout. + +Ultimately, there are pluses and minuses for both options, but it is interesting how the trend appears to be towards token on the right. + +## Button behavior + +Don’t have a separate button for Approve. Also don’t have a separate click for Approve. The user wants to Swap, so just say “swap” on the button and initiate the approval as the first step. A modal can show progress with a stepper, or a simple “tx 1 of 2 - approving” notification. + +![A UI with separate buttons for approve and swap](./14.png) + +![A UI with one button that says approve](./15.png) + +### Button as contextual help + +The button can do double duty as an alert! + +This is actually a fairly unusual design pattern outside of Web3, but has become standard within it. This is a good innovation as it saves space, and keeps attention focused. + +If the main action - SWAP - is unavailable due to an error, the reason why can be explained with the button, e.g.: + +- switch network +- connect wallet +- various errors + +The button can also be **mapped to the action** that needs to be performed. For example, if the user cannot swap because they are on the wrong network, the button should say “switch to Ethereum”, and when the user clicks on the button, it should switch the network to Ethereum. This speeds up the user flow significantly. + +![Key actions being initiated from the main CTA](./16.png) + +![Error message shown within the main CTA](./17.png) + +## Build your own with this figma file + +Thanks to the hard work of multiple protocols, DEX design has improved a lot. We know what info the user needs, how we should show it, and how to make the flow as smooth as possible. +Hopefully this article provides a solid overview of the UX principles. + +If you want to experiment, please feel free to use the Figma wireframe kit. It is kept as simple as possible, but has enough flexibility to build the basic structure in various ways. + +[Figma wireframe kit](https://www.figma.com/community/file/1393606680816807382/dex-wireframes-kit) + +DeFi will continue to evolve, and there is always room for improvement. + +Good luck! + +--- + +## Developers > Docs > Design And Ux > Heuristics For Web3 + +Usability heuristics are broad “rules of thumb” that you can use to measure the usability of your site. +The 7 heuristics here are specifically tailored for Web3 and should be used alongside Jakob Nielsen's [10 general principles for interaction design](https://www.nngroup.com/articles/ten-usability-heuristics/). + +## Seven usability heuristics for web3 + +1. Feedback follows action +2. Security and trust +3. The most important info is obvious +4. Understandable terminology +5. Actions are as short as possible +6. Network connections are visible and flexible +7. Control from the app, not the wallet + + +## Definitions and examples + +### 1. Feedback follows action + +**It should be obvious when something has happened, or is happening.** + +Users decide on their next steps based on the outcome of their previous steps. Therefore it is essential that they remain informed about the system status. This is especially important in Web3 as transactions can sometimes take a short time to commit to the blockchain. If there is no feedback informing them to wait, users are unsure if anything has happened. + +**Tips:** +- Inform the user via messaging, notifications, and other alerts. +- Communicate waiting times clearly. +- If an action is going to take longer than a few seconds, reassure the user with a timer or an animation to make them feel like something is happening. +- If there are multiple steps to a process, show each step. + +**Example:** +Showing each step involved in a transaction helps users know where they are in the process. Appropriate icons let the user know the status of their actions. + +![Informing the user about each step when swapping tokens](./Image1.png) + +### 2. Security and trust are baked in + +Security should be prioritized, and this should be emphasized for the user. +People care deeply about their data. Safety is often a primary concern for users, so it should be considered at all levels of the design. You should always be seeking to earn the trust of your users, but the way you do this can mean different things on different apps. It should not be an afterthought, but should be designed consciously throughout. Build trust throughout the user experience, including social channels and documentation, as well as the final UI. Things like the level of decentralization, the treasury multi-sig status, and whether the team is doxxed, all affect users' trust + +**Tips:** +- List your audits proudly +- Get multiple audits +- Advertise any safety features that you designed +- Highlight possible risks, including underlying integrations +- Communicate complexity of strategies +- Consider non-UI issues that might affect your users' perception of safety + +**Example:** +Include your audits in the footer, at a prominent size. + +![Audits referenced in the website footer](./Image2.png) + +### 3. The most important info is obvious + +For complex systems, show only the most relevant data. Determine what is most important, and prioritize its display. +Too much information is overwhelming and users typically anchor on one piece of information when making decisions. In DeFi, this will probably be APR on yield apps and LTV on lending apps. + +**Tips:** +- User research will uncover the most important metric +- Make the key info big, and the other details small and unobtrusive +- People don’t read, they scan; ensure your design is scannable + +**Example:** Large tokens in full color are easy to find when scanning. The APR is big and highlighted in an accent color. + +![The token and APR are easy to find](./Image3.png) + +### 4. Clear terminology + +Terminology should be understandable and appropriate. +Technical jargon can be a huge blocker, because it requires the construction of a completely new mental model. Users are unable to relate the design to words, phrases and concepts they already know. Everything seems confusing and unfamiliar, and there is a steep learning curve before they can even attempt to use it. A users might approach DeFi wanting to save some money, and what they find is: Mining, farming, staking, emissions, bribes, vaults, lockers, veTokens, vesting, epochs, decentralized algorithms, protocol-owned liquidity… +Try to use simple terms that will be understood by the broadest group of people. Do not invent brand new terms just for your project. + +**Tips:** +- Use simple and consistent terminology +- Use existing language as much as possible +- Don’t come up with your own terms +- Follow conventions as they appear +- Educate users as much as possible + +**Example:** +“Your rewards” is a broadly understood, neutral, term; not a new word made up for this project. The rewards are denominated in USD to match real world mental models, even if the rewards themselves are in another token. + +![Token rewards, displayed in U.S. dollars](./Image4.png) + +### 5. Actions are as short as possible + +Speed up the user’s interactions by grouping sub actions. +This may be done on the smart contract level, as well as the UI. The user should not have to move from one part of the system to another – or leave the system entirely – to complete a common action. + +**Tips:** +- Combine "Approve" with other actions where possible +- Bundle signing steps as close together as possible + +**Example:** Combining “add liquidity” and “stake” is a simple example of an accelerator that saves a user both time and gas. + +![Modal showing a switch to combine the deposit and stake actions](./Image5.png) + +### 6. Network connections are visible and flexible + +Inform the user about what network they are connected to, and provide clear shortcuts to change network. +This is especially important on multichain apps. The main functions of the app should still be visible while disconnected or connected to a non-supported network. + +**Tips:** +- Show as much of the app as possible while disconnected +- Show which network the user is currently connected to +- Don’t make the user go to the wallet to change network +- If the app requires the user to switch network, prompt the action from the main call to action +- If the app contains markets or vaults for multiple networks, clearly state which set the user is currently looking at + +**Example:** Show the user which network they are connected to, and allow them to change it, in the appbar. + +![Dropdown button showing the connected network](./Image6.png) + +### 7. Control from the app, not the wallet + +The UI should tell the user everything they need to know and give them control over everything they need to do. +In Web3, there are actions you take in the UI, and actions you take in the wallet. Generally, you initiate an action in the UI, and then confirm it in the wallet. Users can feel uncomfortable if these two strands are not integrated carefully. + +**Tips:** +- Communicate system status via feedback in the UI +- Keep a record of their history +- Provide links to block explorers for old transactions +- Provide shortcuts to change networks. + +**Example:** A subtle container shows the user what relevant tokens they have in their wallet, and the main CTA provides a shortcut to change the network. + +![Main CTA is prompting the user to switch network](./Image7.png) + +--- + +## Developers > Docs > Design And Ux + +Are you new to designing with Ethereum? This is the right place for you. The Ethereum community has written resources to introduce you to web3 design and research basics. You'll learn about core concepts that may differ from other app designs you're familiar with. + +Need a more basic understanding of web3 first? Check out [**Learn hub**](/learn/). + +## Start with user research + +Effective design goes beyond creating visually appealing user interfaces. It involves gaining a deep understanding of the user's needs, objectives, and driving factors. Therefore, we highly recommend that all designers adopt a design process, such as the [**double diamond process**](), to ensure that their work is deliberate and intentional. + +- [Web3 needs more UX Researchers and Designers](https://blog.akasha.org/akasha-conversations-9-web3-needs-more-ux-researchers-and-designers) - An overview of current design maturity +- [A simple guide to UX Research in web3](https://uxplanet.org/a-complete-guide-to-ux-research-for-web-3-0-products-d6bead20ebb1) - Simple guide how to do research +- [How to Approach UX Decisions in Web3](https://archive.devcon.org/archive/watch/6/data-empathy-how-to-approach-ux-decisions-in-web3/) - A brief overview of quantitative and qualitative research and the differences between the two (video, 6 min) +- [Being a ux researcher in web3](https://medium.com/@georgia.rakusen/what-its-like-being-a-user-researcher-in-web3-6a4bcc096849) - A personal view on what it is like being a UX researcher in web3 + +## Research studies in web3 + +This is a curated list of user research done in web3 that may help with design and product decisions or work as an inspiration to conduct own study. + +| Area of focus | Name | +| :------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Crypto onboarding | [The Reown Pulse 2024: Crypto Consumer Sentiment & Usage](https://reown.com/blog/unveiling-walletconnects-consumer-crypto-report) | +| Crypto onboarding | [CRADL: UX in Cryptocurrency](https://docs.google.com/presentation/d/1s2OPSH5sMJzxRYaJSSRTe8W2iIoZx0PseIV-WeZWD1s/edit?usp=sharing) | +| Crypto onboarding | [CRADL: Onboarding to Cryptocurrency](https://docs.google.com/presentation/d/1R9nFuzA-R6SxaGCKhoMbE4Vxe0JxQSTiHXind3LVq_w/edit?usp=sharing) | +| Crypto onboarding | [Bitcoin UX report](https://github.com/patestevao/BitcoinUX-report/blob/master/report.md) | +| Crypto onboarding | [ConSensys: The State of Web3 perception around the world 2023](https://consensys.io/insight-report/web3-and-crypto-global-survey-2023) | +| Crypto onboarding | [NEAR: Accelerating the journey towards adoption](https://drive.google.com/file/d/1VuaQP4QSaQxR5ddQKTMGI0b0rWdP7uGn/view) | +| Staking | [OpenUX: Rocket Pool Node Operator UX](https://storage.googleapis.com/rocketpool/RocketPool-NodeOperator-UX-Report-Jan-2024.pdf) | +| Staking | [Staking: Key trends, takeaways, and predictions - Eth Staker](https://lookerstudio.google.com/u/0/reporting/cafcee00-e1af-4148-bae8-442a88ac75fa/page/p_ja2srdhh2c?s=hmbTWDh9hJo) | +| Staking | [Multi App Staking]() | +| DAO | [2022 DAO Research Update: What do DAO Builders Need?](https://blog.aragon.org/2022-dao-research-update/) | +| DeFi | [Coverage pools](https://github.com/threshold-network/UX-User-Research/tree/main/Keep%20Coverage%20Pool) | +| DeFi | [ConSensys: DeFi User Research Report 2022](https://cdn2.hubspot.net/hubfs/4795067/ConsenSys%20Codefi-Defi%20User%20ResearchReport.pdf) | +| Metaverse | [Metaverse: User Research Report](https://www.politico.com/f/?id=00000187-7685-d820-a7e7-7e85d1420000) | +| Metaverse | [Going on Safari: Researching Users in the Metaverse](https://archive.devcon.org/archive/watch/6/going-on-safari-researching-users-in-the-metaverse/?tab=YouTube) (video, 27 min) | +| Ethereum.org UX stats | [Usability and user satisfaction survey dashboard - Ethereum.org](https://lookerstudio.google.com/reporting/0a189a7c-a890-40db-a5c6-009db52c81c9) | + +## Design for web3 + +- [Web3 UX Design Handbook](https://web3ux.design/) - Practical guide to designing Web3 apps +- [Web3 Design Principles](https://medium.com/@lyricalpolymath/web3-design-principles-f21db2f240c1) - A framework of UX rules for blockchain based dapps +- [Blockchain Design Principles](https://medium.com/design-ibm/blockchain-design-principles-599c5c067b6e) - Lessons learned by the blockchain design team at IBM +- [Neueux.com](https://neueux.com/apps) - UI library of user flows with diverse filtering options +- [Web3's Usability Crisis: What You NEED to Know!](https://www.youtube.com/watch?v=oBSXT_6YDzg) - A panel discussion on pitfalls of developer focused project building (video, 34 min) + +## Getting Started + +- [Heuristics for Web3](/developers/docs/design-and-ux/heuristics-for-web3/) - 7 heuristics for Web3 interface design +- [DEX Design Best Practices](/developers/docs/design-and-ux/dex-design-best-practice/) - A guide to designing Decentralized Exchanges + +## Web3 Design Case Studies + +- [Deep Work Studio](https://deepwork.studio/case-studies/) +- [Selling an NFT on OpenSea](https://builtformars.com/case-studies/opensea) +- [Wallet UX teardown how wallets need to change](https://www.youtube.com/watch?v=oTpuxYj8JWI&ab_channel=ETHDenver) (video, 20 min) + +## Design Bounties + +- [Dework](https://app.dework.xyz/bounties) +- [Buildbox hackathons](https://app.buidlbox.io/) +- [ETHGlobal hackathons](https://ethglobal.com/) + +## Design DAOs and communities + +Get involved in professional community-driven organizations or join design groups to discuss design and research related topics and trends with other members. + +- [Vectordao.com](https://vectordao.com/) +- [Deepwork.studio](https://www.deepwork.studio/) +- [We3.co](https://we3.co/) +- [Openux.xyz](https://openux.xyz/) +- [Open Source Web3Design](https://www.web3designers.org/) + +## Design Systems and other design resources + +- [Optimism Design](https://www.figma.com/@optimism) (Figma) +- [Ethereum.org Design system](https://www.figma.com/@ethdotorg) (Figma) +- [Finity, a design system by Polygon](https://www.figma.com/community/file/1073921725197233598/finity-design-system) (Figma) +- [Kleros Design System](https://www.figma.com/community/file/999852250110186964/kleros-design-system) (Figma) +- [Safe Design System](https://www.figma.com/community/file/1337417127407098506/safe-design-system) (Figma) +- [ENS Design system](https://thorin.ens.domains/) +- [Mirror Design System](https://degen-xyz.vercel.app/) + +**Articles and projects listed on this page are not official endorsements**, and are provided for informational purposes only. +We add links to this page based on criteria in our [listing policy](/contributing/design/adding-design-resources). If you'd like us to add a project/article, edit this page on [GitHub](https://github.com/ethereum/ethereum-org-website/blob/dev/public/content/developers/docs/design-and-ux/index.md). + +--- + +## Developers > Docs > Development Networks + +When building an Ethereum application with smart contracts, you'll want to run it on a local network to see how it works before deploying it. + +Similar to how you might run a local server on your computer for web development, you can use a development network to create a local blockchain instance to test your dapp. These Ethereum development networks provide features that allow for much faster iteration than a public testnet (for instance you don’t need to deal with acquiring ETH from a testnet faucet). + +## Prerequisites + +You should understand the [basics of the Ethereum stack](/developers/docs/ethereum-stack/) and [Ethereum networks](/developers/docs/networks/) before diving into development networks. + +## What is a development network? + +Development networks are essentially Ethereum clients (implementations of Ethereum) designed specifically for local development. + +**Why not just run a standard Ethereum node locally?** + +You _could_ [run a node](/developers/docs/nodes-and-clients/#running-your-own-node) but since development networks are purpose-built for development, they often come packed with convenient features like: + +- Deterministically seeding your local blockchain with data (e.g. accounts with ETH balances) +- Instantly producing blocks with each transaction it receives, in order and with no delay +- Enhanced debugging and logging functionality + +## Available tools + +**Note**: Most [development frameworks](/developers/docs/frameworks/) include a built-in development network. We recommend starting with a framework to [set up your local development environment](/developers/local-environment/). + +### Hardhat Network + +A local Ethereum network designed for development. It allows you to deploy your contracts, run your tests and debug your code. + +Hardhat Network comes built-in with Hardhat, an Ethereum development environment for professionals. + +- [Website](https://hardhat.org/) +- [GitHub](https://github.com/nomiclabs/hardhat) + +### Local Beacon Chains + +Some consensus clients have built-in tools for spinning up local beacon chains for testing purposes. Instructions for Lighthouse, Nimbus and Lodestar are available: + +- [Local testnet using Lodestar](https://chainsafe.github.io/lodestar/contribution/advanced-topics/setting-up-a-testnet#post-merge-local-testnet/) +- [Local testnet using Lighthouse](https://lighthouse-book.sigmaprime.io/setup.html#local-testnets) +- [Local testnet using Nimbus](https://github.com/status-im/nimbus-eth1/blob/master/fluffy/docs/local_testnet.md) + +### Public Ethereum Test-chains + +There are also two maintained public test implementations of Ethereum: Sepolia and Hoodi. The recommended testnet with long-term support is Hoodi, which anyone is free to validate on. Sepolia uses a permissioned validator set, meaning there is no general access to new validators on this testnet. + +- [Hoodi Staking Launchpad](https://hoodi.launchpad.ethereum.org/) + +### Kurtosis Ethereum Package + +Kurtosis is a build system for multi-container test environments which enables developers to locally spin up reproducible instances of blockchain networks. + +The Ethereum Kurtosis package can be used to quickly instantiate a parameterizable, highly scalable, and private Ethereum testnet over Docker or Kubernetes. The package supports all major Execution Layer (EL) and Consensus Layer (CL) clients. Kurtosis gracefully handles all local port mappings and service connections for a representative network to be used in validation and testing workflows relating to Ethereum core infrastructure. + +- [Ethereum network package](https://github.com/kurtosis-tech/ethereum-package) +- [Website](https://www.kurtosis.com/) +- [GitHub](https://github.com/kurtosis-tech/kurtosis) +- [Documentation](https://docs.kurtosis.com/) + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Development frameworks](/developers/docs/frameworks/) +- [Set up a local development environment](/developers/local-environment/) + +--- + +## Developers > Docs > Ethereum Stack + +Like any software stack, the complete "Ethereum stack" will vary from project to project depending on your goals. + +There are, however, core components of Ethereum that help provide a mental model for how software applications interact with the Ethereum blockchain. Understanding the layers of the stack will help you understand the different ways that Ethereum can be integrated into software projects. + +## Level 1: Ethereum Virtual Machine + +The [Ethereum Virtual Machine (EVM)](/developers/docs/evm/) is the runtime environment for smart contracts on Ethereum. All smart contracts and state changes on the Ethereum blockchain are executed by [transactions](/developers/docs/transactions/). The EVM handles all of the transaction processing on the Ethereum network. + +As with any virtual machine, the EVM creates a level of abstraction between the executing code and the executing machine (an Ethereum node). Currently, the EVM is running on thousands of nodes distributed across the world. + +Under the hood, the EVM uses a set of opcode instructions to execute specific tasks. These (140 unique) opcodes allow the EVM to be [Turing-complete](https://en.wikipedia.org/wiki/Turing_completeness), which means the EVM is able to compute just about anything, given enough resources. + +As a dapp developer, you don't need to know much about the EVM other than it exists and that it reliably powers all applications on Ethereum without downtime. + +## Level 2: Smart contracts + +[Smart contracts](/developers/docs/smart-contracts/) are the executable programs that run on the Ethereum blockchain. + +Smart contracts are written using specific [programming languages](/developers/docs/smart-contracts/languages/) that compile to EVM bytecode (low-level machine instructions called opcodes). + +Not only do smart contracts serve as open source libraries, they are essentially open API services that are always running and can't be taken down. Smart contracts provide public functions which users and applications ([dapps](/developers/docs/dapps/)) may interact with, without needing permission. Any application may integrate with deployed smart contracts to compose functionality, such as adding [data feeds](/developers/docs/oracles/) or to support token swaps. Additionally, anyone can deploy new smart contracts to Ethereum in order to add custom functionality to meet their application's needs. + +As a dapp developer, you'll need to write smart contracts only if you want to add custom functionality on the Ethereum blockchain. You may find you can achieve most or all of your project's needs by merely integrating with existing smart contracts, for instance if you want to support payments in stablecoins or enable decentralized exchange of tokens. + +## Level 3: Ethereum nodes + +In order for an application to interact with the Ethereum blockchain, it must connect to an [Ethereum node](/developers/docs/nodes-and-clients/). Connecting to a node allows you to read blockchain data and/or send transactions to the network. + +Ethereum nodes are computers running software - an Ethereum client. A client is an implementation of Ethereum that verifies all transactions in each block, keeping the network secure and the data accurate. **Ethereum nodes are the Ethereum blockchain**. They collectively store the state of the Ethereum blockchain and reach consensus on transactions to mutate the blockchain state. + +By connecting your application to an Ethereum node (via the [JSON-RPC API](/developers/docs/apis/json-rpc/)), your application is able to read data from the blockchain (such as user account balances) as well as broadcast new transactions to the network (such as transferring ETH between user accounts or executing functions of smart contracts). + +## Level 4: Ethereum client APIs + +Many convenience libraries (built and maintained by Ethereum's open source community) allow your applications to connect to and communicate with the Ethereum blockchain. + +If your user-facing application is a web app, you may choose to `npm install` a [JavaScript API](/developers/docs/apis/javascript/) directly in your frontend. Or perhaps you'll choose to implement this functionality server-side, using a [Python](/developers/docs/programming-languages/python/) or [Java](/developers/docs/programming-languages/java/) API. + +While these APIs are not a necessary piece of the stack, they abstract away much of the complexity of interacting directly with an Ethereum node. They also provide utility functions (e.g. converting ETH to Gwei) so as a developer you can spend less time dealing with the intricacies of Ethereum clients and more time focused on the functionality specific to your application. + +## Level 5: End-user applications + +At the top level of the stack are user-facing applications. These are the standard applications you regularly use and build today: primarily web and mobile apps. + +The way you develop these user interfaces remains essentially unchanged. Often users will not need to know the application they're using is built using a blockchain. + +## Ready to choose your stack? + +Check out our guide to [set up a local development environment](/developers/local-environment/) for your Ethereum application. + +## Further reading + +- [The Architecture of a Web 3.0 application](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Evm + +The Ethereum Virtual Machine (EVM) is a decentralized virtual environment that executes code consistently and securely across all Ethereum nodes. Nodes run the EVM to execute smart contracts, using "[gas](/developers/docs/gas/)" to measure the computational effort required for [operations](/developers/docs/evm/opcodes/), ensuring efficient resource allocation and network security. + +## Prerequisites + +Some basic familiarity with common terminology in computer science such as [bytes](https://wikipedia.org/wiki/Byte), [memory](https://wikipedia.org/wiki/Computer_memory), and a [stack]() are necessary to understand the EVM. It would also be helpful to be comfortable with cryptography/blockchain concepts like [hash functions](https://wikipedia.org/wiki/Cryptographic_hash_function) and the [Merkle tree](https://wikipedia.org/wiki/Merkle_tree). + +## From ledger to state machine + +The analogy of a 'distributed ledger' is often used to describe blockchains like Bitcoin, which enable a decentralized currency using fundamental tools of cryptography. The ledger maintains a record of activity which must adhere to a set of rules that govern what someone can and cannot do to modify the ledger. For example, a Bitcoin address cannot spend more Bitcoin than it has previously received. These rules underpin all transactions on Bitcoin and many other blockchains. + +While Ethereum has its own native cryptocurrency (ether) that follows almost exactly the same intuitive rules, it also enables a much more powerful function: [smart contracts](/developers/docs/smart-contracts/). For this more complex feature, a more sophisticated analogy is required. Instead of a distributed ledger, Ethereum is a distributed [state machine](https://wikipedia.org/wiki/Finite-state_machine). Ethereum's state is a large data structure which holds not only all accounts and balances, but a _machine state_, which can change from block to block according to a pre-defined set of rules, and which can execute arbitrary machine code. The specific rules of changing state from block to block are defined by the EVM. + +![A diagram showing the make up of the EVM](./evm.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +## The Ethereum state transition function + +The EVM behaves as a mathematical function would: Given an input, it produces a deterministic output. It therefore is quite helpful to more formally describe Ethereum as having a **state transition function**: + +``` +Y(S, T)= S' +``` + +Given an old valid state `(S)` and a new set of valid transactions `(T)`, the Ethereum state transition function `Y(S, T)` produces a new valid output state `S'` + +### State + +In the context of Ethereum, the state is an enormous data structure called a [modified Merkle Patricia Trie](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/), which keeps all [accounts](/developers/docs/accounts/) linked by hashes and reducible to a single root hash stored on the blockchain. + +### Transactions + +Transactions are cryptographically signed instructions from accounts. There are two types of transactions: those which result in message calls and those which result in contract creation. + +Contract creation results in the creation of a new contract account containing compiled [smart contract](/developers/docs/smart-contracts/anatomy/) bytecode. Whenever another account makes a message call to that contract, it executes its bytecode. + +## EVM instructions + +The EVM executes as a [stack machine](https://wikipedia.org/wiki/Stack_machine) with a depth of 1024 items. Each item is a 256-bit word, which was chosen for the ease of use with 256-bit cryptography (such as Keccak-256 hashes or secp256k1 signatures). + +During execution, the EVM maintains a transient _memory_ (as a word-addressed byte array), which does not persist between transactions. + +Contracts, however, do contain a Merkle Patricia _storage_ trie (as a word-addressable word array), associated with the account in question and part of the global state. + +Compiled smart contract bytecode executes as a number of EVM [opcodes](/developers/docs/evm/opcodes), which perform standard stack operations like `XOR`, `AND`, `ADD`, `SUB`, etc. The EVM also implements a number of blockchain-specific stack operations, such as `ADDRESS`, `BALANCE`, `BLOCKHASH`, etc. + +![A diagram showing where gas is needed for EVM operations](../gas/gas.png) +_Diagrams adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +## EVM implementations + +All implementations of the EVM must adhere to the specification described in the Ethereum Yellowpaper. + +Over Ethereum's nine year history, the EVM has undergone several revisions, and there are several implementations of the EVM in various programming languages. + +[Ethereum execution clients](/developers/docs/nodes-and-clients/#execution-clients) include an EVM implementation. Additionally, there are multiple standalone implementations, including: + +- [Py-EVM](https://github.com/ethereum/py-evm) - _Python_ +- [evmone](https://github.com/ethereum/evmone) - _C++_ +- [ethereumjs-vm](https://github.com/ethereumjs/ethereumjs-vm) - _JavaScript_ +- [revm](https://github.com/bluealloy/revm) - _Rust_ + +## Further Reading + +- [Ethereum Yellowpaper](https://ethereum.github.io/yellowpaper/paper.pdf) +- [Jellopaper aka KEVM: Semantics of EVM in K](https://jellopaper.org/) +- [The Beigepaper](https://github.com/chronaeon/beigepaper) +- [Ethereum Virtual Machine Opcodes](https://www.ethervm.io/) +- [Ethereum Virtual Machine Opcodes Interactive Reference](https://www.evm.codes/) +- [A short introduction in Solidity's documentation](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#index-6) +- [Mastering Ethereum - The Ethereum Virtual Machine](https://github.com/ethereumbook/ethereumbook/blob/develop/13evm.asciidoc) + +## Related Topics + +- [Gas](/developers/docs/gas/) + +--- + +## Developers > Docs > Evm > Opcodes + +## Overview + +This is an updated version of the EVM reference page at [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes). +Also drawn from the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf), the [Jello Paper](https://jellopaper.org/evm/), and the [geth](https://github.com/ethereum/go-ethereum) implementation. +This is intended to be an accessible reference, but it is not particularly rigorous. +If you want to be certain of correctness and aware of every edge case, using the Jello Paper or a client implementation is advisable. + +Looking for an interactive reference? Check out [evm.codes](https://www.evm.codes/). + +For operations with dynamic gas costs, see [gas.md](https://github.com/wolflo/evm-opcodes/blob/main/gas.md). + +💡 Quick tip: To view entire lines, use `[shift] + scroll` to scroll horizontally on desktop. + +| Stack | Name | Gas | Initial Stack | Resulting Stack | Mem / Storage | Notes | +| :---: | :------------- | :---------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------- | :------------------------------ | :---------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | +| 00 | STOP | 0 | | | | halt execution | +| 01 | ADD | 3 | `a, b` | `a + b` | | (u)int256 addition modulo 2\*\*256 | +| 02 | MUL | 5 | `a, b` | `a * b` | | (u)int256 multiplication modulo 2\*\*256 | +| 03 | SUB | 3 | `a, b` | `a - b` | | (u)int256 addition modulo 2\*\*256 | +| 04 | DIV | 5 | `a, b` | `a // b` | | uint256 division | +| 05 | SDIV | 5 | `a, b` | `a // b` | | int256 division | +| 06 | MOD | 5 | `a, b` | `a % b` | | uint256 modulus | +| 07 | SMOD | 5 | `a, b` | `a % b` | | int256 modulus | +| 08 | ADDMOD | 8 | `a, b, N` | `(a + b) % N` | | (u)int256 addition modulo N | +| 09 | MULMOD | 8 | `a, b, N` | `(a * b) % N` | | (u)int256 multiplication modulo N | +| 0A | EXP | [A1](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a1-exp) | `a, b` | `a ** b` | | uint256 exponentiation modulo 2\*\*256 | +| 0B | SIGNEXTEND | 5 | `b, x` | `SIGNEXTEND(x, b)` | | [sign extend](https://wikipedia.org/wiki/Sign_extension) `x` from `(b+1)` bytes to 32 bytes | +| 0C-0F | _invalid_ | +| 10 | LT | 3 | `a, b` | `a b` | | uint256 greater-than | +| 12 | SLT | 3 | `a, b` | `a b` | | int256 greater-than | +| 14 | EQ | 3 | `a, b` | `a == b` | | (u)int256 equality | +| 15 | ISZERO | 3 | `a` | `a == 0` | | (u)int256 iszero | +| 16 | AND | 3 | `a, b` | `a && b` | | bitwise AND | +| 17 | OR | 3 | `a, b` | `a \|\| b` | | bitwise OR | +| 18 | XOR | 3 | `a, b` | `a ^ b` | | bitwise XOR | +| 19 | NOT | 3 | `a` | `~a` | | bitwise NOT | +| 1A | BYTE | 3 | `i, x` | `(x >> (248 - i * 8)) && 0xFF` | | `i`th byte of (u)int256 `x`, from the left | +| 1B | SHL | 3 | `shift, val` | `val > shift` | | logical shift right | +| 1D | SAR | 3 | `shift, val` | `val >> shift` | | arithmetic shift right | +| 1E-1F | _invalid_ | +| 20 | KECCAK256 | [A2](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a2-sha3) | `ost, len` | `keccak256(mem[ost:ost+len-1])` | | keccak256 | +| 21-2F | _invalid_ | +| 30 | ADDRESS | 2 | `.` | `address(this)` | | address of executing contract | +| 31 | BALANCE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `addr.balance` | | balance, in wei | +| 32 | ORIGIN | 2 | `.` | `tx.origin` | | address that originated the tx | +| 33 | CALLER | 2 | `.` | `msg.sender` | | address of msg sender | +| 34 | CALLVALUE | 2 | `.` | `msg.value` | | msg value, in wei | +| 35 | CALLDATALOAD | 3 | `idx` | `msg.data[idx:idx+32]` | | read word from msg data at index `idx` | +| 36 | CALLDATASIZE | 2 | `.` | `len(msg.data)` | | length of msg data, in bytes | +| 37 | CALLDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := msg.data[ost:ost+len-1] | copy msg data | +| 38 | CODESIZE | 2 | `.` | `len(this.code)` | | length of executing contract's code, in bytes | +| 39 | CODECOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | | mem[dstOst:dstOst+len-1] := this.code[ost:ost+len-1] | copy executing contract's bytecode | +| 3A | GASPRICE | 2 | `.` | `tx.gasprice` | | gas price of tx, in wei per unit gas [\*\*](https://eips.ethereum.org/EIPS/eip-1559#gasprice) | +| 3B | EXTCODESIZE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `len(addr.code)` | | size of code at addr, in bytes | +| 3C | EXTCODECOPY | [A4](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a4-extcodecopy) | `addr, dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := addr.code[ost:ost+len-1] | copy code from `addr` | +| 3D | RETURNDATASIZE | 2 | `.` | `size` | | size of returned data from last external call, in bytes | +| 3E | RETURNDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := returndata[ost:ost+len-1] | copy returned data from last external call | +| 3F | EXTCODEHASH | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `hash` | | hash = addr.exists ? keccak256(addr.code) : 0 | +| 40 | BLOCKHASH | 20 | `blockNum` | `blockHash(blockNum)` | | +| 41 | COINBASE | 2 | `.` | `block.coinbase` | | address of proposer of current block | +| 42 | TIMESTAMP | 2 | `.` | `block.timestamp` | | timestamp of current block | +| 43 | NUMBER | 2 | `.` | `block.number` | | number of current block | +| 44 | PREVRANDAO | 2 | `.` | `randomness beacon` | | randomness beacon | +| 45 | GASLIMIT | 2 | `.` | `block.gaslimit` | | gas limit of current block | +| 46 | CHAINID | 2 | `.` | `chain_id` | | push current [chain id](https://eips.ethereum.org/EIPS/eip-155) onto stack | +| 47 | SELFBALANCE | 5 | `.` | `address(this).balance` | | balance of executing contract, in wei | +| 48 | BASEFEE | 2 | `.` | `block.basefee` | | base fee of current block | +| 49 | BLOBHASH | 3 | `idx` | `tx.blob_versioned_hashes[idx]` | | [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) | +| 4A | BLOBBASEFEE | 2 | `.` | `block.blobbasefee` | | blob base fee of current block ([EIP-7516](https://eips.ethereum.org/EIPS/eip-7516)) | +| 4B-4F | _invalid_ | +| 50 | POP | 2 | `_anon` | `.` | | remove item from top of stack and discard it | +| 51 | MLOAD | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost` | `mem[ost:ost+32]` | | read word from memory at offset `ost` | +| 52 | MSTORE | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost:ost+32] := val | write a word to memory | +| 53 | MSTORE8 | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost] := val && 0xFF | write a single byte to memory | +| 54 | SLOAD | [A6](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a6-sload) | `key` | `storage[key]` | | read word from storage | +| 55 | SSTORE | [A7](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a7-sstore) | `key, val` | `.` | storage[key] := val | write word to storage | +| 56 | JUMP | 8 | `dst` | `.` | | `$pc := dst` mark that `pc` is only assigned if `dst` is a valid jumpdest | +| 57 | JUMPI | 10 | `dst, condition` | `.` | | `$pc := condition ? dst : $pc + 1` | +| 58 | PC | 2 | `.` | `$pc` | | program counter | +| 59 | MSIZE | 2 | `.` | `len(mem)` | | size of memory in current execution context, in bytes | +| 5A | GAS | 2 | `.` | `gasRemaining` | | +| 5B | JUMPDEST | 1 | | | mark valid jump destination | a valid jump destination for example a jump destination not inside the push data | +| 5C | TLOAD | 100 | `key` | `tstorage[key]` | | read word from transient storage ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | +| 5D | TSTORE | 100 | `key, val` | `.` | tstorage[key] := val | write word to transient storage ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | +| 5E | MCOPY | 3+3\*words+[A0](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `dstOst, ost, len` | `.` | mem[dstOst] := mem[ost:ost+len] | copy memory from one area to another ([EIP-5656](https://eips.ethereum.org/EIPS/eip-5656)) | +| 5F | PUSH0 | 2 | `.` | `uint8` | | push the constant value 0 onto stack | +| 60 | PUSH1 | 3 | `.` | `uint8` | | push 1-byte value onto stack | +| 61 | PUSH2 | 3 | `.` | `uint16` | | push 2-byte value onto stack | +| 62 | PUSH3 | 3 | `.` | `uint24` | | push 3-byte value onto stack | +| 63 | PUSH4 | 3 | `.` | `uint32` | | push 4-byte value onto stack | +| 64 | PUSH5 | 3 | `.` | `uint40` | | push 5-byte value onto stack | +| 65 | PUSH6 | 3 | `.` | `uint48` | | push 6-byte value onto stack | +| 66 | PUSH7 | 3 | `.` | `uint56` | | push 7-byte value onto stack | +| 67 | PUSH8 | 3 | `.` | `uint64` | | push 8-byte value onto stack | +| 68 | PUSH9 | 3 | `.` | `uint72` | | push 9-byte value onto stack | +| 69 | PUSH10 | 3 | `.` | `uint80` | | push 10-byte value onto stack | +| 6A | PUSH11 | 3 | `.` | `uint88` | | push 11-byte value onto stack | +| 6B | PUSH12 | 3 | `.` | `uint96` | | push 12-byte value onto stack | +| 6C | PUSH13 | 3 | `.` | `uint104` | | push 13-byte value onto stack | +| 6D | PUSH14 | 3 | `.` | `uint112` | | push 14-byte value onto stack | +| 6E | PUSH15 | 3 | `.` | `uint120` | | push 15-byte value onto stack | +| 6F | PUSH16 | 3 | `.` | `uint128` | | push 16-byte value onto stack | +| 70 | PUSH17 | 3 | `.` | `uint136` | | push 17-byte value onto stack | +| 71 | PUSH18 | 3 | `.` | `uint144` | | push 18-byte value onto stack | +| 72 | PUSH19 | 3 | `.` | `uint152` | | push 19-byte value onto stack | +| 73 | PUSH20 | 3 | `.` | `uint160` | | push 20-byte value onto stack | +| 74 | PUSH21 | 3 | `.` | `uint168` | | push 21-byte value onto stack | +| 75 | PUSH22 | 3 | `.` | `uint176` | | push 22-byte value onto stack | +| 76 | PUSH23 | 3 | `.` | `uint184` | | push 23-byte value onto stack | +| 77 | PUSH24 | 3 | `.` | `uint192` | | push 24-byte value onto stack | +| 78 | PUSH25 | 3 | `.` | `uint200` | | push 25-byte value onto stack | +| 79 | PUSH26 | 3 | `.` | `uint208` | | push 26-byte value onto stack | +| 7A | PUSH27 | 3 | `.` | `uint216` | | push 27-byte value onto stack | +| 7B | PUSH28 | 3 | `.` | `uint224` | | push 28-byte value onto stack | +| 7C | PUSH29 | 3 | `.` | `uint232` | | push 29-byte value onto stack | +| 7D | PUSH30 | 3 | `.` | `uint240` | | push 30-byte value onto stack | +| 7E | PUSH31 | 3 | `.` | `uint248` | | push 31-byte value onto stack | +| 7F | PUSH32 | 3 | `.` | `uint256` | | push 32-byte value onto stack | +| 80 | DUP1 | 3 | `a` | `a, a` | | clone 1st value on stack | +| 81 | DUP2 | 3 | `_, a` | `a, _, a` | | clone 2nd value on stack | +| 82 | DUP3 | 3 | `_, _, a` | `a, _, _, a` | | clone 3rd value on stack | +| 83 | DUP4 | 3 | `_, _, _, a` | `a, _, _, _, a` | | clone 4th value on stack | +| 84 | DUP5 | 3 | `..., a` | `a, ..., a` | | clone 5th value on stack | +| 85 | DUP6 | 3 | `..., a` | `a, ..., a` | | clone 6th value on stack | +| 86 | DUP7 | 3 | `..., a` | `a, ..., a` | | clone 7th value on stack | +| 87 | DUP8 | 3 | `..., a` | `a, ..., a` | | clone 8th value on stack | +| 88 | DUP9 | 3 | `..., a` | `a, ..., a` | | clone 9th value on stack | +| 89 | DUP10 | 3 | `..., a` | `a, ..., a` | | clone 10th value on stack | +| 8A | DUP11 | 3 | `..., a` | `a, ..., a` | | clone 11th value on stack | +| 8B | DUP12 | 3 | `..., a` | `a, ..., a` | | clone 12th value on stack | +| 8C | DUP13 | 3 | `..., a` | `a, ..., a` | | clone 13th value on stack | +| 8D | DUP14 | 3 | `..., a` | `a, ..., a` | | clone 14th value on stack | +| 8E | DUP15 | 3 | `..., a` | `a, ..., a` | | clone 15th value on stack | +| 8F | DUP16 | 3 | `..., a` | `a, ..., a` | | clone 16th value on stack | +| 90 | SWAP1 | 3 | `a, b` | `b, a` | | +| 91 | SWAP2 | 3 | `a, _, b` | `b, _, a` | | +| 92 | SWAP3 | 3 | `a, _, _, b` | `b, _, _, a` | | +| 93 | SWAP4 | 3 | `a, _, _, _, b` | `b, _, _, _, a` | | +| 94 | SWAP5 | 3 | `a, ..., b` | `b, ..., a` | | +| 95 | SWAP6 | 3 | `a, ..., b` | `b, ..., a` | | +| 96 | SWAP7 | 3 | `a, ..., b` | `b, ..., a` | | +| 97 | SWAP8 | 3 | `a, ..., b` | `b, ..., a` | | +| 98 | SWAP9 | 3 | `a, ..., b` | `b, ..., a` | | +| 99 | SWAP10 | 3 | `a, ..., b` | `b, ..., a` | | +| 9A | SWAP11 | 3 | `a, ..., b` | `b, ..., a` | | +| 9B | SWAP12 | 3 | `a, ..., b` | `b, ..., a` | | +| 9C | SWAP13 | 3 | `a, ..., b` | `b, ..., a` | | +| 9D | SWAP14 | 3 | `a, ..., b` | `b, ..., a` | | +| 9E | SWAP15 | 3 | `a, ..., b` | `b, ..., a` | | +| 9F | SWAP16 | 3 | `a, ..., b` | `b, ..., a` | | +| A0 | LOG0 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len` | `.` | | LOG0(memory[ost:ost+len-1]) | +| A1 | LOG1 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0` | `.` | | LOG1(memory[ost:ost+len-1], topic0) | +| A2 | LOG2 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1` | `.` | | LOG2(memory[ost:ost+len-1], topic0, topic1) | +| A3 | LOG3 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2` | `.` | | LOG3(memory[ost:ost+len-1], topic0, topic1, topic2) | +| A4 | LOG4 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2, topic3` | `.` | | LOG4(memory[ost:ost+len-1], topic0, topic1, topic2, topic3) | +| A5-EF | _invalid_ | +| F0 | CREATE | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len` | `addr` | | addr = keccak256(rlp([address(this), this.nonce])) | +| F1 | CALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | gas, addr, val, argOst, argLen, retOst, retLen | `success` | mem[retOst:retOst+retLen-1] := returndata | +| F2 | CALLCODE | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, val, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] = returndata | same as DELEGATECALL, but does not propagate original msg.sender and msg.value | +| F3 | RETURN | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | return mem[ost:ost+len-1] | +| F4 | DELEGATECALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | +| F5 | CREATE2 | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len, salt` | `addr` | | addr = keccak256(0xff ++ address(this) ++ salt ++ keccak256(mem[ost:ost+len-1]))[12:] | +| F6-F9 | _invalid_ | +| FA | STATICCALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | +| FB-FC | _invalid_ | +| FD | REVERT | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | revert(mem[ost:ost+len-1]) | +| FE | INVALID | [AF](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid) | | | designated invalid opcode - [EIP-141](https://eips.ethereum.org/EIPS/eip-141) | +| FF | SELFDESTRUCT | [AB](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#ab-selfdestruct) | `addr` | `.` | | sends all ETH to `addr`; if executed in the same transaction as a contract was created it destroys the contract | + +--- + +## Developers > Docs > Frameworks + +## Introduction to frameworks + +Building a full-fledged dapp requires +different pieces of technology. Software frameworks include many of the needed +features or provide easy plugin systems to pick the tools you +desire. + +Frameworks come with a lot of out-of-the-box functionality, +like: + +- Features to spin up a local blockchain instance. +- Utilities to compile and test your smart contracts. +- Client development add-ons to build your user-facing application + within the same project/repository. +- Configuration to connect to Ethereum networks and deploy + contracts, whether to a locally running instance, or one of + Ethereum's public networks. +- Decentralized app distribution - integrations with storage + options like IPFS. + +## Prerequisites + +Before diving into frameworks, we recommend you first read through our introduction to [dapps](/developers/docs/dapps/) and the [Ethereum stack](/developers/docs/ethereum-stack/). + +## Available frameworks + +**Foundry** - **_Foundry is a blazing fast, portable and modular toolkit for Ethereum application development_** + +- [Install Foundry](https://book.getfoundry.sh/) +- [Foundry book](https://book.getfoundry.sh/) +- [Foundry community chat on Telegram](https://t.me/foundry_support) +- [Awesome Foundry](https://github.com/crisgarner/awesome-foundry) + +**Hardhat -** **_Ethereum development environment for professionals._** + +- [hardhat.org](https://hardhat.org) +- [GitHub](https://github.com/nomiclabs/hardhat) + +**Ape -** **_The smart contract development tool for Pythonistas, Data Scientists, and Security Professionals._** + +- [Documentation](https://docs.apeworx.io/ape/stable/) +- [GitHub](https://github.com/ApeWorX/ape) + +**Web3j -** **_A platform for developing blockchain applications on the JVM._** + +- [Homepage](https://www.web3labs.com/web3j-sdk) +- [Documentation](https://docs.web3j.io) +- [GitHub](https://github.com/web3j/web3j) + +**ethers-kt -** **_Async, high-performance Kotlin/Java/Android library for EVM-based blockchains._** + +- [GitHub](https://github.com/Kr1ptal/ethers-kt) +- [Examples](https://github.com/Kr1ptal/ethers-kt/tree/master/examples) +- [Discord](https://discord.gg/rx35NzQGSb) + +**Create Eth App -** **_Create Ethereum-powered apps with one command. Comes with a wide offering of UI frameworks and DeFi templates to choose from._** + +- [GitHub](https://github.com/paulrberg/create-eth-app) +- [Templates](https://github.com/PaulRBerg/create-eth-app/tree/develop/templates) + +**Scaffold-Eth -** **_Ethers.js + Hardhat + React components and hooks for web3: everything you need to get started building decentralized applications powered by smart contracts._** + +- [GitHub](https://github.com/scaffold-eth/scaffold-eth-2) + +**Tenderly -** **_Web3 development platform that enables blockchain developers to build, test, debug, monitor, and operate smart contracts and improve dapp UX._** + +- [Website](https://tenderly.co/) +- [Documentation](https://docs.tenderly.co/ethereum-development-practices) + +**The Graph -** **_The Graph for querying blockchain data efficiently._** + +- [Website](https://thegraph.com/) +- [Tutorial](/developers/tutorials/the-graph-fixing-web3-data-querying/) + +**Alchemy -** **_Ethereum Development Platform._** + +- [alchemy.com](https://www.alchemy.com/) +- [GitHub](https://github.com/alchemyplatform) +- [Discord](https://discord.com/invite/alchemyplatform) + +**NodeReal -** **_Ethereum Development Platform._** + +- [Nodereal.io](https://nodereal.io/) +- [GitHub](https://github.com/node-real) +- [Discord](https://discord.gg/V5k5gsuE) + +**thirdweb SDK -** **_Build web3 applications that can interact with your smart contracts using our powerful SDKs and CLI._** + +- [Documentation](https://portal.thirdweb.com/sdk/) +- [GitHub](https://github.com/thirdweb-dev/) + +**Chainstack -** **_Web3 (Ethereum and otherwise) Development Platform._** + +- [chainstack.com](https://www.chainstack.com/) +- [GitHub](https://github.com/chainstack) +- [Discord](https://discord.gg/BSb5zfp9AT) + +**Crossmint -** **_Enterprise-grade web3 development platform, that allows you to build NFT applications on all major chains EVM Chains(and others)._** + +- [Website](https://www.crossmint.com) +- [Documentation](https://docs.crossmint.com) +- [Discord](https://discord.com/invite/crossmint) + +**Brownie -** **_Python-based development environment and testing framework._** + +- [Documentation](https://eth-brownie.readthedocs.io/en/latest/) +- [GitHub](https://github.com/eth-brownie/brownie) +- **Brownie is currently unmaintained** + +**OpenZeppelin SDK -** **_The Ultimate Smart Contract Toolkit: A suite of tools to help you develop, compile, upgrade, deploy and interact with smart contracts._** + +- [OpenZeppelin SDK](https://openzeppelin.com/sdk/) +- [GitHub](https://github.com/OpenZeppelin/openzeppelin-sdk) +- [Community Forum](https://forum.openzeppelin.com/c/support/17) +- **OpenZeppelin SDK development has ended** + +**Catapulta -** **_Multi-chain smart contracts deployment tool, automate verifications in block explorers, keep track deployed smart contracts and share deployment reports, plug-n-play for Foundry and Hardhat projects._** + +- [Website](https://catapulta.sh/) +- [Documentation](https://catapulta.sh/docs) +- [Github](https://github.com/catapulta-sh) + +**Covalent -** **_Enriched blockchain APIs for 200+ Chains._** + +- [covalenthq.com](https://www.covalenthq.com/) +- [Documentation](https://www.covalenthq.com/docs/api/) +- [GitHub](https://github.com/covalenthq) +- [Discord](https://www.covalenthq.com/discord/) + +**Wake -** **_All-in-one Python framework for contracts testing, fuzzing, deployment, vulnerability scanning and code navigation._** + +- [Homepage](https://getwake.io/) +- [Documentation](https://ackeeblockchain.com/wake/docs/latest/) +- [GitHub](https://github.com/Ackee-Blockchain/wake) +- [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity) + +**Veramo -** **_Open source, modular and agnostic framework that makes it easy for decentralized application developers to build decentralized identities and verifiable credentials into their applications._** + +- [Homepage](https://veramo.io/) +- [Documentation](https://veramo.io/docs/basics/introduction) +- [GitHub](https://github.com/uport-project/veramo) +- [Discord](https://discord.com/invite/FRRBdjemHV) +- [NPM Package](https://www.npmjs.com/package/@veramo/core) + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Set up a local development environment](/developers/local-environment/) + +--- + +## Developers > Docs > Gas + +Gas is essential to the Ethereum network. It is the fuel that allows it to operate, in the same way that a car needs gasoline to run. + +## Prerequisites + +To better understand this page, we recommend you first read up on [transactions](/developers/docs/transactions/) and the [EVM](/developers/docs/evm/). + +## What is gas? + +Gas refers to the unit that measures the amount of computational effort required to execute specific operations on the Ethereum network. + +Since each Ethereum transaction requires computational resources to execute, those resources have to be paid for to ensure Ethereum is not vulnerable to spam and cannot get stuck in infinite computational loops. Payment for computation is made in the form of a gas fee. + +The gas fee is **the amount of gas used to do some operation, multiplied by the cost per unit gas**. The fee is paid regardless of whether a transaction succeeds or fails. + +![A diagram showing where gas is needed in EVM operations](./gas.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +Gas fees have to be paid in Ethereum's native currency, ether (ETH). Gas prices are usually quoted in gwei, which is a denomination of ETH. Each gwei is equal to one-billionth of an ETH (0.000000001 ETH or 10-9 ETH). + +For example, instead of saying that your gas costs 0.000000001 ether, you can say your gas costs 1 gwei. + +The word 'gwei' is a contraction of 'giga-wei', meaning 'billion wei'. One gwei is equal to one billion wei. Wei itself (named after [Wei Dai](https://wikipedia.org/wiki/Wei_Dai), creator of [b-money](https://www.investopedia.com/terms/b/bmoney.asp)) is the smallest unit of ETH. + +## How are gas fees calculated? + +You can set the amount of gas you are willing to pay when you submit a transaction. By offering a certain amount of gas, you are bidding for your transaction to be included in the next block. If you offer too little, validators are less likely to choose your transaction for inclusion, meaning your transaction may execute late or not at all. If you offer too much, you might waste some ETH. So, how can you tell how much to pay? + +The total gas you pay is divided into two components: the `base fee` and the `priority fee` (tip). + +The `base fee` is set by the protocol - you have to pay at least this amount for your transaction to be considered valid. The `priority fee` is a tip that you add to the base fee to make your transaction attractive to validators so that they choose it for inclusion in the next block. + +A transaction that only pays the `base fee` is technically valid but unlikely to be included because it offers no incentive to the validators to choose it over any other transaction. The 'correct' `priority` fee is determined by the network usage at the time you send your transaction - if there is a lot of demand then you might have to set your `priority` fee higher, but when there is less demand you can pay less. + +For example, let's say Jordan has to pay Taylor 1 ETH. An ETH transfer requires 21,000 units of gas, and the base fee is 10 gwei. Jordan includes a tip of 2 gwei. + +The total fee would now be equal to: + +`units of gas used * (base fee + priority fee)` + +where the `base fee` is a value set by the protocol and the `priority fee` is a value set by the user as a tip to the validator. + +i.e. `21,000 * (10 + 2) = 252,000 gwei` (0.000252 ETH). + +When Jordan sends the money, 1.000252 ETH will be deducted from Jordan's account. Taylor will be credited 1.0000 ETH. The validator receives the tip of 0.000042 ETH. The `base fee` of 0.00021 ETH is burned. + +### Base fee + +Every block has a base fee which acts as a reserve price. To be eligible for inclusion in a block the offered price per gas must at least equal the base fee. The base fee is calculated independently of the current block and is instead determined by the blocks before it - making transaction fees more predictable for users. When the block is created this **base fee is "burned"**, removing it from circulation. + +The base fee is calculated by a formula that compares the size of the previous block (the amount of gas used for all the transactions) with the target size. The base fee will increase by a maximum of 12.5% per block if the target block size is exceeded. This exponential growth makes it economically non-viable for block size to remain high indefinitely. + +| Block Number | Included Gas | Fee Increase | Current Base Fee | +| ------------ | -----------: | -----------: | ---------------: | +| 1 | 15M | 0% | 100 gwei | +| 2 | 30M | 0% | 100 gwei | +| 3 | 30M | 12.5% | 112.5 gwei | +| 4 | 30M | 12.5% | 126.6 gwei | +| 5 | 30M | 12.5% | 142.4 gwei | +| 6 | 30M | 12.5% | 160.2 gwei | +| 7 | 30M | 12.5% | 180.2 gwei | +| 8 | 30M | 12.5% | 202.7 gwei | + +Following the table above - to create a transaction on block number 9, a wallet will let the user know with certainty that the **maximum base fee** to be added to the next block is `current base fee * 112.5%` or `202.7 gwei * 112.5% = 228.1 gwei`. + +It's also important to note it is unlikely we will see extended spikes of full blocks because of the speed at which the base fee increases preceding a full block. + +| Block Number | Included Gas | Fee Increase | Current Base Fee | +| ------------ | -----------: | -----------: | ---------------: | +| 30 | 30M | 12.5% | 2705.6 gwei | +| ... | ... | 12.5% | ... | +| 50 | 30M | 12.5% | 28531.3 gwei | +| ... | ... | 12.5% | ... | +| 100 | 30M | 12.5% | 10302608.6 gwei | + +### Priority fee (tips) + +The priority fee (tip) incentivizes validators to include a transaction in the block. Without tips, validators would find it economically viable to mine empty blocks, as they would receive the same block reward. Small tips give validators a minimal incentive to include a transaction. For transactions to be preferentially executed ahead of other transactions in the same block, a higher tip can be added to try to outbid competing transactions. + +### Max fee + +To execute a transaction on the network, users can specify a maximum limit they are willing to pay for their transaction to be executed. This optional parameter is known as the `maxFeePerGas`. For a transaction to be executed, the max fee must exceed the sum of the base fee and the tip. The transaction sender is refunded the difference between the max fee and the sum of the base fee and tip. + +### Block size + +Each block has a target size of 15 million gas, but the size of blocks will increase or decrease in accordance with network demand, up until the block limit of 30 million gas (2x the target block size). The protocol achieves an equilibrium block size of 15 million on average through the process of _tâtonnement_. This means if the block size is greater than the target block size, the protocol will increase the base fee for the following block. Similarly, the protocol will decrease the base fee if the block size is less than the target block size. The amount by which the base fee is adjusted is proportional to how far the current block size is from the target. [More on blocks](/developers/docs/blocks/). + +### Calculating gas fees in practice + +You can explicitly state how much you are willing to pay to get your transaction executed. However, most wallet providers will automatically set a recommended transaction fee (base fee + recommended priority fee) to reduce the amount of complexity burdened onto their users. + +## Why do gas fees exist? + +In short, gas fees help keep the Ethereum network secure. By requiring a fee for every computation executed on the network, we prevent bad actors from spamming the network. In order to avoid accidental or hostile infinite loops or other computational wastage in code, each transaction is required to set a limit to how many computational steps of code execution it can use. The fundamental unit of computation is "gas". + +Although a transaction includes a limit, any gas not used in a transaction is returned to the user (i.e. `max fee - (base fee + tip)` is returned). + +![Diagram showing how unused gas is refunded](../transactions/gas-tx.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +## What is the gas limit? + +The gas limit refers to the maximum amount of gas you are willing to consume on a transaction. More complicated transactions involving [smart contracts](/developers/docs/smart-contracts/) require more computational work, so they require a higher gas limit than a simple payment. A standard ETH transfer requires a gas limit of 21,000 units of gas. + +For example, if you put a gas limit of 50,000 for a simple ETH transfer, the EVM would consume 21,000, and you would get back the remaining 29,000. However, if you specify too little gas, for example, a gas limit of 20,000 for a simple ETH transfer, the transaction will fail during the validation phase. It will be rejected before being included in a block, and no gas will be consumed. On the other hand, if a transaction runs out of gas during execution (e.g., a smart contract uses up all the gas halfway), the EVM will revert any changes, but all the gas provided will still be consumed for the work performed. + +## Why can gas fees get so high? + +High gas fees are due to the popularity of Ethereum. If there's too much demand, users must offer higher tip amounts to try and outbid other users' transactions. A higher tip can make it more likely that your transaction will get into the next block. Also, more complex smart contract apps might be doing lots of operations to support their functions, making them consume a lot of gas. + +## Initiatives to reduce gas costs + +The Ethereum [scalability upgrades](/roadmap/) should ultimately address some of the gas fee issues, which will, in turn, enable the platform to process thousands of transactions per second and scale globally. + +Layer 2 scaling is a primary initiative to greatly improve gas costs, user experience and scalability. [More on layer 2 scaling](/developers/docs/scaling/#layer-2-scaling). + +## Monitoring gas fees + +If you want to monitor gas prices, so you can send your ETH for less, you can use many different tools such as: + +- [Etherscan](https://etherscan.io/gastracker) _Transaction gas price estimator_ +- [ETH Gas Tracker](https://www.ethgastracker.com/) _Monitor and track the Ethereum, and L2 gas prices to reduce transaction fees and save money_ +- [Blocknative ETH Gas Estimator](https://chrome.google.com/webstore/detail/blocknative-eth-gas-estim/ablbagjepecncofimgjmdpnhnfjiecfm) _Gas estimating Chrome extension supporting both Type 0 legacy transactions and Type 2 EIP-1559 transactions._ +- [Cryptoneur Gas Fees Calculator](https://www.cryptoneur.xyz/gas-fees-calculator) _Calculate gas fees in your local currency for different transaction types on Mainnet, Arbitrum, and Polygon._ + +## Related tools + +- [Blocknative's Gas Platform](https://www.blocknative.com/gas) _Gas estimation API powered by Blocknative's global mempool data platform_ + +## Further reading + +- [Ethereum Gas Explained](https://defiprime.com/gas) +- [Reducing the gas consumption of your Smart Contracts](https://medium.com/coinmonks/8-ways-of-reducing-the-gas-consumption-of-your-smart-contracts-9a506b339c0a) +- [Proof of Stake versus Proof of Work](https://blockgeeks.com/guides/proof-of-work-vs-proof-of-stake/) +- [Gas Optimization Strategies for Developers](https://www.alchemy.com/overviews/solidity-gas-optimization) +- [EIP-1559 docs](https://eips.ethereum.org/EIPS/eip-1559). +- [Tim Beiko's EIP-1559 Resources](https://hackmd.io/@timbeiko/1559-resources) +- [EIP-1559: Separating Mechanisms From Memes](https://research.2077.xyz/eip-1559-separating-mechanisms-from-memes) + +--- + +## Developers > Docs > Ides + +When it comes to setting up an [integrated development environment (IDE)](https://wikipedia.org/wiki/Integrated_development_environment), programming applications on Ethereum is similar to programming any other software project. There are many options to choose from, so at the end of the day, pick the IDE or code editor that best suits your preferences. Most likely the best IDE choice for your Ethereum development is the IDE you already use for traditional software development. + +## Web-based IDEs + +If you're looking to fiddle with code before you [set up a local development environment](/developers/local-environment/), these web apps are custom-built for Ethereum smart contract development. + +**[Remix](https://remix.ethereum.org/)** - **_Web-based IDE with built in static analysis, and a test blockchain virtual machine_** + +- [Docs](https://remix-ide.readthedocs.io/en/latest/#) +- [Gitter](https://gitter.im/ethereum/remix) + +**[ChainIDE](https://chainide.com/)** - **_A cloud-based multi-chain IDE_** + +- [Docs](https://chainide.gitbook.io/chainide-english-1/) +- [Help forum](https://forum.chainide.com/) + +**[Replit (Solidity Starter - Beta)](https://replit.com/@replit/Solidity-starter-beta)** - **_A customizable development environment for Ethereum with hot reloading, error checking, and first-class testnet support_** + +- [Docs](https://docs.replit.com/) + +**[Tenderly Sandbox](https://sandbox.tenderly.co/)** - **_A fast prototyping environment where you can write, execute, and debug smart contracts in the browser using Solidity and JavaScript_** + +**[EthFiddle](https://ethfiddle.com/)** - **_Web-based IDE that lets you write, compile, and debug your smart contract_** + +- [Gitter](https://gitter.im/loomnetwork/ethfiddle) + +## Desktop IDEs + +Most established IDEs have built plugins to enhance the Ethereum development experience. At a minimum, they provide syntax highlighting for [smart contract languages](/developers/docs/smart-contracts/languages/). + +**Visual Studio Code -** **_Professional cross-platform IDE with official Ethereum support_** + +- [Visual Studio Code](https://code.visualstudio.com/) +- [Code samples](https://github.com/Azure-Samples/blockchain/blob/master/blockchain-workbench/application-and-smart-contract-samples/readme.md) +- [GitHub](https://github.com/microsoft/vscode) + +**JetBrains IDEs (IntelliJ IDEA, etc.) -** **_Essential tools for software developers and teams_** + +- [JetBrains](https://www.jetbrains.com/) +- [GitHub](https://github.com/JetBrains) +- [IntelliJ Solidity](https://github.com/intellij-solidity/intellij-solidity/) + +**Remix Desktop -** **_Experience Remix IDE on your local machine_** + +- [Download](https://github.com/ethereum/remix-desktop/releases) +- [GitHub](https://github.com/ethereum/remix-desktop) + +## Plugins and extensions + +- [solidity](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) - Ethereum Solidity Language for Visual Studio Code +- [Solidity + Hardhat for VS Code](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity) - Solidity and Hardhat support by the Hardhat team +- [Prettier Solidity](https://github.com/prettier-solidity/prettier-plugin-solidity) - Code formatter using prettier + +## Further reading + +- [Ethereum IDEs](https://www.alchemy.com/list-of/web3-ides-on-ethereum) _- Alchemy's list of Ethereum IDEs_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs + +This documentation is designed to help you build with Ethereum. It covers Ethereum as a concept, explains the Ethereum tech stack, and documents advanced topics for more complex applications and use cases. + +This is an open-source community effort, so feel free to suggest new topics, add new content, and provide examples wherever you think it might be helpful. All documentation can be edited via GitHub – if you're unsure how, [follow these instructions](https://github.com/ethereum/ethereum-org-website/blob/dev/docs/editing-markdown.md). + +## Development modules + +If this is your first attempt at Ethereum development, we recommend starting at the beginning and working your way through like a book. + +### Foundational topics + + + +### Ethereum stack + + + +### Advanced + +--- + +## Developers > Docs > Intro To Ether + +## Prerequisites + +To help you better understand this page, we recommend you first read [Introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +## What is a cryptocurrency? + +A cryptocurrency is a medium of exchange secured by a blockchain-based ledger. + +A medium of exchange is anything widely accepted as payment for goods and services, and a ledger is a data store that keeps track of transactions. Blockchain technology allows users to make transactions on the ledger without reliance upon a trusted third party to maintain the ledger. + +The first cryptocurrency was Bitcoin, created by Satoshi Nakamoto. Since Bitcoin's release in 2009, people have made thousands of cryptocurrencies across many different blockchains. + +## What is ether? + +**Ether (ETH)** is the cryptocurrency used for many things on the Ethereum network. Fundamentally, it is the only acceptable form of payment for transaction fees, and after [The Merge](/roadmap/merge), ether is required to validate and propose blocks on Mainnet. Ether is also used as a primary form of collateral in the [DeFi](/defi) lending markets, as a unit of account in NFT marketplaces, as payment earned for performing services or selling real-world goods, and more. + +Ethereum allows developers to create [**decentralized applications (dapps)**](/developers/docs/dapps), which all share a pool of computing power. This shared pool is finite, so Ethereum needs a mechanism to determine who gets to use it. Otherwise, a dapp could accidentally or maliciously consume all network resources, which would block others from accessing it. + +The ether cryptocurrency supports a pricing mechanism for Ethereum's computing power. When users want to make a transaction, they must pay ether to have their transaction recognized on the blockchain. These usage costs are known as [gas fees](/developers/docs/gas/), and the gas fee depends on the amount of computing power required to execute the transaction and the network-wide demand for computing power at the time. + +Therefore, even if a malicious dapp submitted an infinite loop, the transaction would eventually run out of ether and terminate, allowing the network to return to normal. + +It is [common to conflate](https://abcnews.go.com/Business/bitcoin-slumps-week-low-amid-renewed-worries-chinese/story?id=78399845) Ethereum and ether — when people reference the "price of Ethereum," they are describing the price of ether. + +## Minting ether + +Minting is the process in which new ether gets created on the Ethereum ledger. The underlying Ethereum protocol creates the new ether, and it is not possible for a user to create ether. + +Ether is minted as a reward for each block proposed and at every epoch checkpoint for other validator activity related to reaching consensus. The total amount issued depends on the number of validators and how much ether they have staked. This total issuance is divided equally among validators in the ideal case that all validators are honest and online, but in reality, it varies based on validator performance. About 1/8 of the total issuance goes to the block proposer; the remainder is distributed across the other validators. Block proposers also receive tips from transaction fees and MEV-related income, but these come from recycled ether, not new issuance. + +## Burning ether + +As well as creating ether through block rewards, ether can be destroyed through a process called 'burning'. When ether gets burned, it gets removed from circulation permanently. + +Ether burn occurs in every transaction on Ethereum. When users pay for their transactions, a base gas fee, set by the network according to transactional demand, gets destroyed. This, coupled with variable block sizes and a maximum gas fee, simplifies transaction fee estimation on Ethereum. When network demand is high, [blocks](https://etherscan.io/block/12965263) can burn more ether than they mint, effectively offsetting ether issuance. + +Burning the base fee hinders a block producer's ability to manipulate transactions. For example, if block producers received the base fee, they could include their own transactions for free and raise the base fee for everyone else. Alternatively, they could refund the base fee to some users offchain, leading to a more opaque and complex transaction fee market. + +## Denominations of ether + +Since the value of many transactions on Ethereum are small, ether has several denominations which may be referenced as smaller units of account. Of these denominations, Wei and gwei are particularly important. + +Wei is the smallest possible amount of ether, and as a result, many technical implementations, such as the [Ethereum Yellowpaper](https://ethereum.github.io/yellowpaper/paper.pdf), will base all calculations in Wei. + +Gwei, short for giga-wei, is often used to describe gas costs on Ethereum. + +| Denomination | Value in ether | Common Usage | +| ------------ | ---------------- | ------------------------- | +| Wei | 10-18 | Technical implementations | +| Gwei | 10-9 | Human-readable gas fees | + +## Transferring ether + +Each transaction on Ethereum contains a `value` field, which specifies the amount of ether to be transferred, denominated in wei, to send from the sender's address to the recipient address. + +When the recipient address is a [smart contract](/developers/docs/smart-contracts/), this transferred ether may be used to pay for gas when the smart contract executes its code. + +[More on transactions](/developers/docs/transactions/) + +## Querying ether + +Users can query the ether balance of any [account](/developers/docs/accounts/) by inspecting the account's `balance` field, which shows ether holdings denominated in wei. + +[Etherscan](https://etherscan.io) is a popular tool to inspect address balances via a web-based application. For example, [this Etherscan page](https://etherscan.io/address/0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae) shows the balance for the Ethereum Foundation. Account balances can also be queried using wallets or directly by making requests to nodes. + +## Further reading + +- [Defining ether and Ethereum](https://www.cmegroup.com/education/courses/introduction-to-ether/defining-ether-and-ethereum.html) – _CME Group_ +- [Ethereum Whitepaper](/whitepaper/): The original proposal for Ethereum. This document includes a description of ether and the motivations behind its creation. +- [Gwei Calculator](https://www.alchemy.com/gwei-calculator): Use this gwei calculator to easily convert wei, gwei, and ether. Simply plug in any amount of wei, gwei, or ETH and automatically calculate the conversion. + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Intro To Ethereum + +## What is a blockchain? + +A blockchain is a public database that is updated and shared across many computers in a network. + +"Block" refers to data and state being stored in consecutive groups known as "blocks". If you send ETH to someone else, the transaction data needs to be added to a block to be successful. + +"Chain" refers to the fact that each block cryptographically references its parent. In other words, blocks get chained together. The data in a block cannot change without changing all subsequent blocks, which would require the consensus of the entire network. + +Every computer in the network must agree upon each new block and the chain as a whole. These computers are known as "nodes". Nodes ensure everyone interacting with the blockchain has the same data. To accomplish this distributed agreement, blockchains need a consensus mechanism. + +Ethereum uses a [proof-of-stake-based consensus mechanism](/developers/docs/consensus-mechanisms/pos/). Anyone who wants to add new blocks to the chain must stake ETH - the native currency in Ethereum - as collateral and run validator software. These "validators" can then be randomly selected to propose blocks that other validators check and add to the blockchain. There is a system of rewards and penalties that strongly incentivize participants to be honest and available online as much as possible. + +If you would like to see how blockchain data is hashed and subsequently appended to the history of block references, be sure to check out [this demo](https://andersbrownworth.com/blockchain/blockchain) by Anders Brownworth and watch the accompanying video below. + +Watch Anders explain hashes in blockchains: + + + +## What is Ethereum? + +Ethereum is a blockchain with a computer embedded in it. It is the foundation for building apps and organizations in a decentralized, permissionless, censorship-resistant way. + +In the Ethereum universe, there is a single, canonical computer (called the Ethereum Virtual Machine, or EVM) whose state everyone on the Ethereum network agrees on. Everyone who participates in the Ethereum network (every Ethereum node) keeps a copy of the state of this computer. Additionally, any participant can broadcast a request for this computer to perform arbitrary computation. Whenever such a request is broadcast, other participants on the network verify, validate, and carry out ("execute") the computation. This execution causes a state change in the EVM, which is committed and propagated throughout the entire network. + +Requests for computation are called transaction requests; the record of all transactions and the EVM's present state gets stored on the blockchain, which in turn is stored and agreed upon by all nodes. + +Cryptographic mechanisms ensure that once transactions are verified as valid and added to the blockchain, they can't be tampered with later. The same mechanisms also ensure that all transactions are signed and executed with appropriate "permissions" (no one should be able to send digital assets from Alice's account, except for Alice herself). + +## What is ether? + +**Ether (ETH)** is the native cryptocurrency of Ethereum. The purpose of ETH is to allow for a market for computation. Such a market provides an economic incentive for participants to verify and execute transaction requests and provide computational resources to the network. + +Any participant who broadcasts a transaction request must also offer some amount of ETH to the network as a bounty. The network will burn part of the bounty and award the rest to whoever eventually does the work of verifying the transaction, executing it, committing it to the blockchain, and broadcasting it to the network. + +The amount of ETH paid corresponds to the resources required to do the computation. These bounties also prevent malicious participants from intentionally clogging the network by requesting the execution of infinite computation or other resource-intensive scripts, as these participants must pay for computation resources. + +ETH is also used to provide crypto-economic security to the network in three main ways: 1) it is used as a means to reward validators who propose blocks or call out dishonest behavior by other validators; 2) It is staked by validators, acting as collateral against dishonest behavior—if validators attempt to misbehave their ETH can be destroyed; 3) it is used to weigh 'votes' for newly proposed blocks, feeding into the fork-choice part of the consensus mechanism. + +## What are smart contracts? + +In practice, participants don't write new code every time they want to request a computation on the EVM. Rather, application developers upload programs (reusable snippets of code) into EVM state, and users make requests to execute these code snippets with varying parameters. We call the programs uploaded to and executed by the network smart contracts. + +At a very basic level, you can think of a smart contract like a sort of vending machine: a script that, when called with certain parameters, performs some actions or computation if certain conditions are satisfied. For example, a simple vendor smart contract could create and assign ownership of a digital asset if the caller sends ETH to a specific recipient. + +Any developer can create a smart contract and make it public to the network, using the blockchain as its data layer, for a fee paid to the network. Any user can then call the smart contract to execute its code, again for a fee paid to the network. + +Thus, with smart contracts, developers can build and deploy arbitrarily complex user-facing apps and services such as: marketplaces, financial instruments, games, etc. + +## Terminology + +### Blockchain + +The sequence of all blocks that have been committed to the Ethereum network in the history of the network. So named because each block contains a reference to the previous block, which helps us maintain an ordering over all blocks (and thus over the precise history). + +### ETH + +**Ether (ETH)** is the native cryptocurrency of Ethereum. Users pay ETH to other users to have their code execution requests fulfilled. + +[More on ETH](/developers/docs/intro-to-ether/) + +### EVM + +The Ethereum Virtual Machine is the global virtual computer whose state every participant on the Ethereum network stores and agrees on. Any participant can request the execution of arbitrary code on the EVM; code execution changes the state of the EVM. + +[More on the EVM](/developers/docs/evm/) + +### Nodes + +The real-life machines which are storing the EVM state. Nodes communicate with each other to propagate information about the EVM state and new state changes. Any user can also request the execution of code by broadcasting a code execution request from a node. The Ethereum network itself is the aggregate of all Ethereum nodes and their communications. + +[More on nodes](/developers/docs/nodes-and-clients/) + +### Accounts + +Where ETH is stored. Users can initialize accounts, deposit ETH into the accounts, and transfer ETH from their accounts to other users. Accounts and account balances are stored in a big table in the EVM; they are a part of the overall EVM state. + +[More on accounts](/developers/docs/accounts/) + +### Transactions + +A "transaction request" is the formal term for a request for code execution on the EVM, and a "transaction" is a fulfilled transaction request and the associated change in the EVM state. Any user can broadcast a transaction request to the network from a node. For the transaction request to affect the agreed-upon EVM state, it must be validated, executed, and "committed to the network" by another node. Execution of any code causes a state change in the EVM; upon commitment, this state change is broadcast to all nodes in the network. Some examples of transactions: + +- Send X ETH from my account to Alice's account. +- Publish some smart contract code into EVM state. +- Execute the code of the smart contract at address X in the EVM, with arguments Y. + +[More on transactions](/developers/docs/transactions/) + +### Blocks + +The volume of transactions is very high, so transactions are "committed" in batches, or blocks. Blocks generally contain dozens to hundreds of transactions. + +[More on blocks](/developers/docs/blocks/) + +### Smart contracts + +A reusable snippet of code (a program) which a developer publishes into EVM state. Anyone can request that the smart contract code be executed by making a transaction request. Because developers can write arbitrary executable applications into the EVM (games, marketplaces, financial instruments, etc.) by publishing smart contracts, these are often also called [dapps, or Decentralized Apps](/developers/docs/dapps/). + +[More on smart contracts](/developers/docs/smart-contracts/) + +## Further reading + +- [Ethereum Whitepaper](/whitepaper/) +- [How does Ethereum work, anyway?](https://medium.com/@preethikasireddy/how-does-ethereum-work-anyway-22d1df506369) - _Preethi Kasireddy_ (**NB** this resource is still valuable but be aware that it predates [The Merge](/roadmap/merge) and therefore still refers to Ethereum's proof-of-work mechanism - Ethereum is actually now secured using [proof-of-stake](/developers/docs/consensus-mechanisms/pos)) + +### More of a visual learner? + +This video series offers a thorough exploration of foundational topics: + + + +[Ethereum Basics Playlist](https://youtube.com/playlist?list=PLqgutSGloqiJyyoL0zvLVFPS-GMD2wKa5&si=kZTf5I7PKGTXDsOZ) + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related tutorials + +- [A developer's guide to Ethereum, part 1](/developers/tutorials/a-developers-guide-to-ethereum-part-one/) _– A very beginner-friendly exploration of Ethereum using Python and web3.py_ + +--- + +## Developers > Docs > Mev + +Maximal extractable value (MEV) refers to the maximum value that can be extracted from block production in excess of the standard block reward and gas fees by including, excluding, and changing the order of transactions in a block. + +## Maximal extractable value + +Maximal extractable value was first applied in the context of [proof-of-work](/developers/docs/consensus-mechanisms/pow/), and initially referred to as "miner extractable value". This is because in proof-of-work, miners control transaction inclusion, exclusion, and ordering. However, since the transition to proof-of-stake via [The Merge](/roadmap/merge) validators have been responsible for these roles, and mining is no longer part of the Ethereum protocol. The value extraction methods still exist, though, so the term "Maximal extractable value" is now used instead. + +## Prerequisites + +Make sure you're familiar with [transactions](/developers/docs/transactions/), [blocks](/developers/docs/blocks/), [proof-of-stake](/developers/docs/consensus-mechanisms/pos) and [gas](/developers/docs/gas/). Familiarity with [dapps](/dapps/) and [DeFi](/defi/) is helpful as well. + +## MEV extraction + +In theory MEV accrues entirely to validators because they are the only party that can guarantee the execution of a profitable MEV opportunity. In practice, however, a large portion of MEV is extracted by independent network participants referred to as "searchers." Searchers run complex algorithms on blockchain data to detect profitable MEV opportunities and have bots to automatically submit those profitable transactions to the network. + +Validators do get a portion of the full MEV amount anyway because searchers are willing to pay high gas fees (which go to the validator) in exchange for higher likelihood of inclusion of their profitable transactions in a block. Assuming searchers are economically rational, the gas fee that a searcher is willing to pay will be an amount up to 100% of the searcher's MEV (because if the gas fee was higher, the searcher would lose money). + +With that, for some highly competitive MEV opportunities, such as [DEX arbitrage](#mev-examples-dex-arbitrage), searchers may have to pay 90% or even more of their total MEV revenue in gas fees to the validator because so many people want to run the same profitable arbitrage trade. This is because the only way to guarantee that their arbitrage transaction runs is if they submit the transaction with the highest gas price. + +### Gas golfing + +This dynamic has made being good at "gas golfing" — programming transactions so that they use the least amount of gas — a competitive advantage, because it allows searchers to set a higher gas price while keeping their total gas fees constant (since gas fees = gas price \* gas used). + +A few well-known gas golf techniques include: using addresses that start with a long string of zeroes (e.g. [0x0000000000C521824EaFf97Eac7B73B084ef9306](https://etherscan.io/address/0x0000000000c521824eaff97eac7b73b084ef9306)) since they take less space (and hence gas) to store; and leaving small [ERC-20](/developers/docs/standards/tokens/erc-20/) token balances in contracts, since it costs more gas to initialize a storage slot (the case if the balance is 0) than to update a storage slot. Finding more techniques to reduce gas usage is an active area of research among searchers. + +### Generalized frontrunners + +Rather than programming complex algorithms to detect profitable MEV opportunities, some searchers run generalized frontrunners. Generalized frontrunners are bots that watch the mempool to detect profitable transactions. The frontrunner will copy the potentially profitable transaction's code, replace addresses with the frontrunner's address, and run the transaction locally to double-check that the modified transaction results in a profit to the frontrunner's address. If the transaction is indeed profitable, the frontrunner will submit the modified transaction with the replaced address and a higher gas price, "frontrunning" the original transaction and getting the original searcher's MEV. + +### Flashbots + +Flashbots is an independent project which extends execution clients with a service that allows searchers to submit MEV transactions to validators without revealing them to the public mempool. This prevents transactions from being frontrun by generalized frontrunners. + +## MEV examples + +MEV emerges on the blockchain in a few ways. + +### DEX arbitrage + +[Decentralized exchange](/glossary/#dex) (DEX) arbitrage is the simplest and most well-known MEV opportunity. As a result, it is also the most competitive. + +It works like this: if two DEXes are offering a token at two different prices, someone can buy the token on the lower-priced DEX and sell it on the higher-priced DEX in a single, atomic transaction. Thanks to the mechanics of the blockchain, this is true, riskless arbitrage. + +[Here's an example](https://etherscan.io/tx/0x5e1657ef0e9be9bc72efefe59a2528d0d730d478cfc9e6cdd09af9f997bb3ef4) of a profitable arbitrage transaction where a searcher turned 1,000 ETH into 1,045 ETH by taking advantage of different pricing of the ETH/DAI pair on Uniswap vs. Sushiswap. + +### Liquidations + +Lending protocol liquidations present another well-known MEV opportunity. + +Lending protocols like Maker and Aave require users to deposit some collateral (e.g. ETH). This deposited collateral is then used to lend out to other users. + +Users can then borrow assets and tokens from others depending on what they need (e.g. you might borrow MKR if you want to vote in a MakerDAO governance proposal) up to a certain percentage of their deposited collateral. For example, if the borrowing amount is a maximum of 30%, a user who deposits 100 DAI into the protocol can borrow up to 30 DAI worth of another asset. The protocol determines the exact borrowing power percentage. + +As the value of a borrower's collateral fluctuates, so too does their borrowing power. If, due to market fluctuations, the value of borrowed assets exceeds say, 30% of the value of their collateral (again, the exact percentage is determined by the protocol), the protocol typically allows anyone to liquidate the collateral, instantly paying off the lenders (this is similar to how [margin calls](https://www.investopedia.com/terms/m/margincall.asp) work in traditional finance). If liquidated, the borrower usually has to pay a hefty liquidation fee, some of which goes to the liquidator — which is where the MEV opportunity comes in. + +Searchers compete to parse blockchain data as fast as possible to determine which borrowers can be liquidated and be the first to submit a liquidation transaction and collect the liquidation fee for themselves. + +### Sandwich trading + +Sandwich trading is another common method of MEV extraction. + +To sandwich, a searcher will watch the mempool for large DEX trades. For instance, suppose someone wants to buy 10,000 UNI with DAI on Uniswap. A trade of this magnitude will have a meaningful effect on the UNI/DAI pair, potentially significantly raising the price of UNI relative to DAI. + +A searcher can calculate the approximate price effect of this large trade on the UNI/DAI pair and execute an optimal buy order immediately _before_ the large trade, buying UNI cheaply, then execute a sell order immediately _after_ the large trade, selling it for the higher price caused by the large order. + +Sandwiching, however, is riskier as it isn't atomic (unlike DEX arbitrage, as described above) and is prone to a [salmonella attack](https://github.com/Defi-Cartel/salmonella). + +### NFT MEV + +MEV in the NFT space is an emergent phenomenon, and isn't necessarily profitable. + +However, since NFT transactions happen on the same blockchain shared by all other Ethereum transactions, searchers can use similar techniques as those used in traditional MEV opportunities in the NFT market too. + +For example, if there's a popular NFT drop and a searcher wants a certain NFT or set of NFTs, they can program a transaction such that they are the first in line to buy the NFT, or they can buy the entire set of NFTs in a single transaction. Or if an NFT is [mistakenly listed at a low price](https://www.theblockcrypto.com/post/113546/mistake-sees-69000-cryptopunk-sold-for-less-than-a-cent), a searcher can frontrun other purchasers and snap it up for cheap. + +One prominent example of NFT MEV occurred when a searcher spent $7 million to [buy](https://etherscan.io/address/0x650dCdEB6ecF05aE3CAF30A70966E2F395d5E9E5) every single Cryptopunk at the price floor. A blockchain researcher [explained on Twitter](https://twitter.com/IvanBogatyy/status/1422232184493121538) how the buyer worked with an MEV provider to keep their purchase secret. + +### The long tail + +DEX arbitrage, liquidations, and sandwich trading are all very well-known MEV opportunities and are unlikely to be profitable for new searchers. However, there is a long tail of lesser known MEV opportunities (NFT MEV is arguably one such opportunity). + +Searchers who are just getting started may be able to find more success by searching for MEV in this longer tail. Flashbot's [MEV job board](https://github.com/flashbots/mev-job-board) lists some emerging opportunities. + +## Effects of MEV + +MEV is not all bad — there are both positive and negative consequences to MEV on Ethereum. + +### The good + +Many DeFi projects rely on economically rational actors to ensure the usefulness and stability of their protocols. For instance, DEX arbitrage ensures that users get the best, most correct prices for their tokens, and lending protocols rely on speedy liquidations when borrowers fall below collateralization ratios to ensure lenders get paid back. + +Without rational searchers seeking and fixing economic inefficiencies and taking advantage of protocols' economic incentives, DeFi protocols and dapps in general may not be as robust as they are today. + +### The bad + +At the application layer, some forms of MEV, like sandwich trading, result in an unequivocally worse experience for users. Users who are sandwiched face increased slippage and worse execution on their trades. + +At the network layer, generalized frontrunners and the gas-price auctions they often engage in (when two or more frontrunners compete for their transaction to be included in the next block by progressively raising their own transactions' gas price) result in network congestion and high gas prices for everyone else trying to run regular transactions. + +Beyond what's happening _within_ blocks, MEV can have deleterious effects _between_ blocks. If the MEV available in a block significantly exceeds the standard block reward, validators may be incentivized to reorg blocks and capture the MEV for themselves, causing blockchain re-organization and consensus instability. + +This possibility of blockchain re-organization has been [previously explored on the Bitcoin blockchain](https://dl.acm.org/doi/10.1145/2976749.2978408). As Bitcoin's block reward halves and transaction fees make up a greater and greater portion of the block reward, situations arise where it becomes economically rational for miners to give up the next block's reward and instead remine past blocks with higher fees. With the growth of MEV, the same sort of situation could occur in Ethereum, threatening the integrity of the blockchain. + +## State of MEV + +MEV extraction ballooned in early 2021, resulting in extremely high gas prices in the first few months of the year. The emergence of Flashbots's MEV relay has reduced the effectiveness of generalized frontrunners and has taken gas price auctions offchain, lowering gas prices for ordinary users. + +While many searchers are still making good money from MEV, as opportunities become more well-known and more and more searchers compete for the same opportunity, validators will capture more and more total MEV revenue (because the same sort of gas auctions as originally described above also occur in Flashbots, albeit privately, and validators will capture the resulting gas revenue). MEV is also not unique to Ethereum, and as opportunities become more competitive on Ethereum, searchers are moving to alternate blockchains like Binance Smart Chain, where similar MEV opportunities as those on Ethereum exist with less competition. + +On the other hand, the transition from proof-of-work to proof-of-stake and the ongoing effort to scale Ethereum using rollups all change the MEV landscape in ways that are still somewhat unclear. It is not yet well known how having guaranteed block-proposers known slightly in advance changes the dynamics of MEV extraction compared to the probabilistic model in proof-of-work or how this will be disrupted when [single secret leader election](https://ethresear.ch/t/secret-non-single-leader-election/11789) and [distributed validator technology](/staking/dvt/) get implemented. Similarly, it remains to be seen what MEV opportunities exist when most user activity is ported away from Ethereum and onto its layer 2 rollups and shards. + +## MEV in Ethereum Proof-of-Stake (PoS) + +As explained, MEV has negative implications for overall user experience and consensus-layer security. But Ethereum’s transition to a proof-of-stake consensus (dubbed “The Merge”) potentially introduces new MEV-related risks: + +### Validator centralization + +In post-Merge Ethereum, validators (having made security deposits of 32 ETH) come to consensus on the validity of blocks added to the Beacon Chain. Since 32 ETH may be out of the reach of many, [joining a staking pool](/staking/pools/) may be a more feasible option. Nevertheless, a healthy distribution of [solo stakers](/staking/solo/) is ideal, as it mitigates the centralization of validators and improves Ethereum’s security. + +However, MEV extraction is believed to be capable of accelerating validator centralization. This is partly because, as validators [earn less for proposing blocks](/roadmap/merge/issuance/#how-the-merge-impacts-ETH-supply) than miners previously did, MEV extraction has greatly [influenced validator earnings](https://github.com/flashbots/eth2-research/blob/main/notebooks/mev-in-eth2/eth2-mev-calc.ipynb) since [The Merge](/roadmap/merge/). + +Larger staking pools will likely have more resources to invest in necessary optimizations to capture MEV opportunities. The more MEV these pools extract, the more resources they have to improve their MEV-extraction capabilities (and increase overall revenue), essentially creating [economies of scale](https://www.investopedia.com/terms/e/economiesofscale.asp#). + +With fewer resources at their disposal, solo stakers may be unable to profit from MEV opportunities. This may increase the pressure on independent validators to join powerful staking pools to boost their earnings, reducing decentralization in Ethereum. + +### Permissioned mempools + +In response to sandwiching and frontrunning attacks, traders may start conducting offchain deals with validators for transaction privacy. Instead of sending a potential MEV transaction to the public mempool, the trader sends it directly to the validator, who includes it in a block and splits profits with the trader. + +“Dark pools” are a larger version of this arrangement and function as permissioned, access-only mempools open to users willing to pay certain fees. This trend would diminish Ethereum’s permissionlessness and trustlessness and potentially transform the blockchain into a “pay-to-play” mechanism that favors the highest bidder. + +Permissioned mempools would also accelerate the centralization risks described in the previous section. Large pools running multiple validators will likely benefit from offering transaction privacy to traders and users, increasing their MEV revenues. + +Combating these MEV-related problems in post-Merge Ethereum is a core area of research. To date, two solutions proposed to reduce the negative impact of MEV on Ethereum’s decentralization and security after The Merge are [**Proposer-Builder Separation (PBS)**](/roadmap/pbs/) and the [**Builder API**](https://github.com/ethereum/builder-specs). + +### Proposer-Builder Separation + +In both proof-of-work and proof-of-stake, a node that builds a block proposes it for addition to the chain to other nodes participating in consensus. A new block becomes part of the canonical chain after another miner builds on top of it (in PoW) or it receives attestations from the majority of validators (in PoS). + +The combination of block producer and block proposer roles is what introduces most of the MEV-related problems described previously. For example, consensus nodes are incentivized to trigger chain reorganizations in [time-bandit attacks](https://www.mev.wiki/attack-examples/time-bandit-attack) to maximize MEV earnings. + +[Proposer-builder separation](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) (PBS) is designed to mitigate the impact of MEV, especially at the consensus layer. PBS’ major feature is the separation of block producer and block proposer rules. Validators are still responsible for proposing and voting on blocks, but a new class of specialized entities, called **block builders**, are tasked with ordering transactions and building blocks. + +Under PBS, a block builder creates a transaction bundle and places a bid for its inclusion in a Beacon Chain block (as the “execution payload”). The validator selected to propose the next block then checks the different bids and chooses the bundle with the highest fee. PBS essentially creates an auction market, where builders negotiate with validators selling blockspace. + +Current PBS designs use a [commit-reveal scheme](https://gitcoin.co/blog/commit-reveal-scheme-on-ethereum/) in which builders only publish a cryptographic commitment to a block’s contents (block header) along with their bids. After accepting the winning bid, the proposer creates a signed block proposal that includes the block header. The block builder is expected to publish the full block body after seeing the signed block proposal, and it must also receive enough [attestations](/glossary/#attestation) from validators before it is finalized. + +#### How does proposer-builder separation mitigate MEV’s impact? + +In-protocol proposer-builder separation reduces MEV’s effect on consensus by removing MEV extraction from the purview of validators. Instead, block builders running specialized hardware will capture MEV opportunities going forward. + +This doesn’t exclude validators totally from MEV-related income, though, as builders must bid high to get their blocks accepted by validators. Nevertheless, with validators no longer directly focused on optimizing MEV income, the threat of time-bandit attacks reduces. + +Proposer-builder separation also reduces MEV’s centralization risks. For instance, the use of a commit-reveal scheme removes the need for builders to trust validators not to steal the MEV opportunity or expose it to other builders. This lowers the barrier for solo stakers to benefit from MEV, otherwise, builders would trend towards favoring large pools with offchain reputation and conducting offchain deals with them. + +Similarly, validators don’t have to trust builders not to withhold block bodies or publish invalid blocks because payment is unconditional. The validator’s fee still processes even if the proposed block is unavailable or declared invalid by other validators. In the latter case, the block is simply discarded, forcing the block builder to lose all transaction fees and MEV revenue. + +### Builder API + +While proposer-builder separation promises to reduce the effects of MEV extraction, implementing it requires changes to the consensus protocol. Specifically, the [fork choice](/developers/docs/consensus-mechanisms/pos/#fork-choice) rule on the Beacon Chain would need to be updated. The [Builder API](https://github.com/ethereum/builder-specs) is a temporary solution aimed at providing a working implementation of proposer-builder separation, albeit with higher trust assumptions. + +The Builder API is a modified version of the [Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) used by consensus layer clients to request execution payloads from execution layer clients. As outlined in the [honest validator specification](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/validator.md), validators selected for block proposing duties request a transaction bundle from a connected execution client, which they include in the proposed Beacon Chain block. + +The Builder API also acts as a middleware between validators and execution-layer clients; but it is different because it allows validators on the Beacon Chain to source blocks from external entities (instead of building a block locally using an execution client). + +Below is an overview of how the Builder API works: + +1. The Builder API connects the validator to a network of block builders running execution layer clients. Like in PBS, builders are specialized parties that invest in resource-intensive block-building and use different strategies to maximize revenue earned from MEV + priority tips. + +2. A validator (running a consensus layer client) requests execution payloads along with bids from the network of builders. Bids from builders will contain the execution payload header—a cryptographic commitment to the payload's contents—and a fee to be paid to the validator. + +3. The validator reviews the incoming bids and picks the execution payload with the highest fee. Using the Builder API, the validator creates a "blinded" Beacon block proposal that includes only their signature and the execution payload header and sends it to the builder. + +4. The builder running the Builder API is expected to respond with the full execution payload upon seeing the blinded block proposal. This allows the validator to create a "signed" Beacon block, which they propagate throughout the network. + +5. A validator using the Builder API is still expected to build a block locally in case the block builder fails to respond promptly, so they don't miss out on block proposal rewards. However, validator cannot create another block using either the now-revealed transactions or another set, as it would amount to _equivocation_ (signing two blocks within the same slot), which is a slashable offense. + +An example implementation of the Builder API is [MEV Boost](https://github.com/flashbots/mev-boost), an improvement on the [Flashbots auction mechanism](https://docs.flashbots.net/Flashbots-auction/overview/) designed to curb the negative externalities of MEV on Ethereum. Flashbots auction allows validators in proof-of-stake to outsource the work of building profitable blocks to specialized parties called **searchers**. +![A diagram showing the MEV flow in detail](./mev.png) + +Searchers look for lucrative MEV opportunities and send transaction bundles to block proposers along with a [sealed-price bid](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction) for inclusion in the block. The validator running mev-geth, a forked version of the go-ethereum (Geth) client only has to choose the bundle with the most profit and include it as part of the new block. To protect block proposers (validators) from spam and invalid transactions, transaction bundles pass through **relayers** for validation before getting to the proposer. + +MEV Boost retains the same workings of the original Flashbots auction, albeit with new features designed for Ethereum’s switch to proof-of-stake. Searchers still find profitable MEV transactions for inclusion in blocks, but a new class of specialized parties, called **builders**, are responsible for aggregating transactions and bundles into blocks. A builder accepts sealed-price bids from searchers and runs optimizations to find the most profitable ordering. + +The relayer is still responsible for validating transaction bundles before passing them to the proposer. However, MEV Boost introduces **escrows** responsible for providing [data availability](/developers/docs/data-availability/) by storing block bodies sent by builders and block headers sent by validators. Here, a validator connected to a relay asks for available execution payloads and uses MEV Boost’s ordering algorithm to select the payload header with the highest bid + MEV tips. + +#### How does the Builder API mitigate MEV’s impact? + +The core benefit of the Builder API is its potential to democratize access to MEV opportunities. Using commit-reveal schemes eliminates trust assumptions and reduces entry barriers for validators seeking to benefit from MEV. This should reduce the pressure on solo stakers to integrate with large staking pools in order to boost MEV profits. + +Widespread implementation of the Builder API will encourage greater competition among block builders, which increases censorship resistance. As validators review bids from multiple builders, a builder intent on censoring one or more user transactions must outbid all other non-censoring builders to be successful. This dramatically increases the cost of censoring users and discourages the practice. + +Some projects, such as MEV Boost, use the Builder API as part of an overall structure designed to provide transaction privacy to certain parties, such as traders trying to avoid frontrunning/sandwiching attacks. This is achieved by providing a private communication channel between users and block builders. Unlike the permissioned mempools described earlier, this approach is beneficial for the following reasons: + +1. The existence of multiple builders on the market makes censoring impractical, which benefits users. In contrast, the existence of centralized and trust-based dark pools would concentrate power in the hands of a few block builders and increase the possibility of censoring. + +2. The Builder API software is open-source, which allows anyone to offer block-builder services. This means users aren’t forced into using any particular block builder and improves Ethereum’s neutrality and permissionlessness. Moreover, MEV-seeking traders won’t inadvertently contribute to centralization by using private transaction channels. + +## Related resources + +- [Flashbots docs](https://docs.flashbots.net/) +- [Flashbots GitHub](https://github.com/flashbots/pm) +- [MEV-Explore](https://explore.flashbots.net/) - _Dashboard and live transaction explorer for MEV transactions_ +- [mevboost.org](https://www.mevboost.org/) - _Tracker with real-time stats for MEV-Boost relays and block builders_ + +## Further reading + +- [What Is Miner-Extractable Value (MEV)?](https://blog.chain.link/what-is-miner-extractable-value-mev/) +- [MEV and Me](https://www.paradigm.xyz/2021/02/mev-and-me) +- [Ethereum is a Dark Forest](https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest/) +- [Escaping the Dark Forest](https://samczsun.com/escaping-the-dark-forest/) +- [Flashbots: Frontrunning the MEV Crisis](https://medium.com/flashbots/frontrunning-the-mev-crisis-40629a613752) +- [@bertcmiller's MEV Threads](https://twitter.com/bertcmiller/status/1402665992422047747) +- [MEV-Boost: Merge ready Flashbots Architecture](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177) +- [What Is MEV Boost](https://www.alchemy.com/overviews/mev-boost) +- [Why run mev-boost?](https://writings.flashbots.net/writings/why-run-mevboost/) +- [The Hitchhikers Guide To Ethereum](https://members.delphidigital.io/reports/the-hitchhikers-guide-to-ethereum) + +--- + +## Developers > Docs > Networking Layer + +Ethereum is a peer-to-peer network with thousands of nodes that must be able to communicate with one another using standardized protocols. The "networking layer" is the stack of protocols that allow those nodes to find each other and exchange information. This includes "gossiping" information (one-to-many communication) over the network as well as swapping requests and responses between specific nodes (one-to-one communication). Each node must adhere to specific networking rules to ensure they are sending and receiving the correct information. + +There are two parts to the client software (execution clients and consensus clients), each with its own distinct networking stack. As well as communicating with other Ethereum nodes, the execution and consensus clients have to communicate with each other. This page gives an introductory explanation of the protocols that enable this communication. + +Execution clients gossip transactions over the execution-layer peer-to-peer network. This requires encrypted communication between authenticated peers. When a validator is selected to propose a block, transactions from the node's local transaction pool will be passed to consensus clients via a local RPC connection, which will be packaged into Beacon blocks. Consensus clients will then gossip Beacon blocks across their p2p network. This requires two separate p2p networks: one connecting execution clients for transaction gossip and one connecting consensus clients for block gossip. + +## Prerequisites + +Some knowledge of Ethereum [nodes and clients](/developers/docs/nodes-and-clients/) will be helpful for understanding this page. + +## The Execution Layer + +The execution layer's networking protocols is divided into two stacks: + +- the discovery stack: built on top of UDP and allows a new node to find peers to connect to + +- the DevP2P stack: sits on top of TCP and enables nodes to exchange information + +Both stacks work in parallel. The discovery stack feeds new network participants into the network, and the DevP2P stack enables their interactions. + +### Discovery + +Discovery is the process of finding other nodes in network. This is bootstrapped using a small set of bootnodes (nodes whose addresses are [hardcoded](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go) into the client so they can be found immediately and connect the client to peers). These bootnodes only exist to introduce a new node to a set of peers - this is their sole purpose, they do not participate in normal client tasks like syncing the chain, and they are only used the very first time a client is spun up. + +The protocol used for the node-bootnode interactions is a modified form of [Kademlia](https://medium.com/coinmonks/a-brief-overview-of-kademlia-and-its-use-in-various-decentralized-platforms-da08a7f72b8f) which uses a [distributed hash table](https://en.wikipedia.org/wiki/Distributed_hash_table) to share lists of nodes. Each node has a version of this table containing the information required to connect to its closest peers. This 'closeness' is not geographical - distance is defined by the similarity of the node's ID. Each node's table is regularly refreshed as a security feature. For example, in the [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5), discovery protocol nodes are also able to send 'ads' that display the subprotocols that the client supports, allowing peers to negotiate about the protocols they can both use to communicate over. + +Discovery starts with a game of PING-PONG. A successful PING-PONG "bonds" the new node to a bootnode. The initial message that alerts a bootnode to the existence of a new node entering the network is a `PING`. This `PING` includes hashed information about the new node, the bootnode and an expiry time-stamp. The bootnode receives the `PING` and returns a `PONG` containing the `PING` hash. If the `PING` and `PONG` hashes match then the connection between the new node and bootnode is verified and they are said to have "bonded". + +Once bonded, the new node can send a `FIND-NEIGHBOURS` request to the bootnode. The data returned by the bootnode includes a list of peers that the new node can connect to. If the nodes are not bonded, the `FIND-NEIGHBOURS` request will fail, so the new node will not be able to enter the network. + +Once the new node receives a list of neighbours from the bootnode, it begins a PING-PONG exchange with each of them. Successful PING-PONGs bond the new node with its neighbours, enabling message exchange. + +``` +start client --> connect to bootnode --> bond to bootnode --> find neighbours --> bond to neighbours +``` + +Execution clients are currently using the [Discv4](https://github.com/ethereum/devp2p/blob/master/discv4.md) discovery protocol and there is an active effort to migrate to the [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5) protocol. + +#### ENR: Ethereum Node Records + +The [Ethereum Node Record (ENR)](/developers/docs/networking-layer/network-addresses/) is an object that contains three basic elements: a signature (hash of record contents made according to some agreed identity scheme), a sequence number that tracks changes to the record, and an arbitrary list of key:value pairs. This is a future-proof format that allows easier exchange of identifying information between new peers and is the preferred [network address](/developers/docs/networking-layer/network-addresses) format for Ethereum nodes. + +#### Why is discovery built on UDP? + +UDP does not support any error checking, resending of failed packets, or dynamically opening and closing connections - instead it just fires a continuous stream of information at a target, regardless of whether it is successfully received. This minimal functionality also translates into minimal overhead, making this kind of connection very fast. For discovery, where a node simply wants to make its presence known in order to then establish a formal connection with a peer, UDP is sufficient. However, for the rest of the networking stack, UDP is not fit for purpose. The informational exchange between nodes is quite complex and therefore needs a more fully featured protocol that can support resending, error checking etc. The additional overhead associated with TCP is worth the additional functionality. Therefore, the majority of the P2P stack operates over TCP. + +### DevP2P + +DevP2P is itself a whole stack of protocols that Ethereum implements to establish and maintain the peer-to-peer network. After new nodes enter the network, their interactions are governed by protocols in the [DevP2P](https://github.com/ethereum/devp2p) stack. These all sit on top of TCP and include the RLPx transport protocol, wire protocol and several sub-protocols. [RLPx](https://github.com/ethereum/devp2p/blob/master/rlpx.md) is the protocol governing initiating, authenticating and maintaining sessions between nodes. RLPx encodes messages using RLP (Recursive Length Prefix) which is a very space-efficient method of encoding data into a minimal structure for sending between nodes. + +A RLPx session between two nodes begins with an initial cryptographic handshake. This involves the node sending an auth message which is then verified by the peer. On successful verification, the peer generates an auth-acknowledgement message to return to the initiator node. This is a key-exchange process that enables the nodes to communicate privately and securely. A successful cryptographic handshake then triggers both nodes to send a "hello" message to one another "on the wire". The wire protocol is initiated by a successful exchange of hello messages. + +The hello messages contain: + +- protocol version +- client ID +- port +- node ID +- list of supported sub-protocols + +This is the information required for a successful interaction because it defines what capabilities are shared between both nodes and configures the communication. There is a process of sub-protocol negotiation where the lists of sub-protocols supported by each node are compared and those that are common to both nodes can be used in the session. + +Along with the hello messages, the wire protocol can also send a "disconnect" message that gives warning to a peer that the connection will be closed. The wire protocol also includes PING and PONG messages that are sent periodically to keep a session open. The RLPx and wire protocol exchanges therefore establish the foundations of communication between the nodes, providing the scaffolding for useful information to be exchanged according to a specific sub-protocol. + +### Sub-protocols + +#### Wire protocol + +Once peers are connected, and an RLPx session has been started, the wire protocol defines how peers communicate. Initially, the wire protocol defined three main tasks: chain synchronization, block propagation and transaction exchange. However, once Ethereum switched to proof-of-stake, block propagation and chain synchronization became part of the consensus layer. Transaction exchange is still in the remit of the execution clients. Transaction exchange refers to exchanging pending transactions between nodes so that block builders can select some of them for inclusion in the next block. Detailed information about these tasks is available [here](https://github.com/ethereum/devp2p/blob/master/caps/eth.md). Clients that support these sub-protocols expose them via the [JSON-RPC](/developers/docs/apis/json-rpc/). + +#### les (light ethereum subprotocol) + +This is a minimal protocol for syncing light clients. Traditionally this protocol has rarely been used because full nodes are required to serve data to light clients without being incentivized. The default behavior of execution clients is not to serve light client data over les. More information is available in the les [spec](https://github.com/ethereum/devp2p/blob/master/caps/les.md). + +#### Snap + +The [snap protocol](https://github.com/ethereum/devp2p/blob/master/caps/snap.md#ethereum-snapshot-protocol-snap) is an optional extension that allows peers to exchange snapshots of recent states, allowing peers to verify account and storage data without having to download intermediate Merkle trie nodes. + +#### Wit (witness protocol) + +The [witness protocol](https://github.com/ethereum/devp2p/blob/master/caps/wit.md#ethereum-witness-protocol-wit) is an optional extension that enables exchange of state witnesses between peers, helping to sync clients to the tip of the chain. + +#### Whisper + +Whisper was a protocol that aimed to deliver secure messaging between peers without writing any information to the blockchain. It was part of the DevP2P wire protocol but is now deprecated. Other [related projects](https://wakunetwork.com/) exist with similar aims. + +## The consensus layer + +The consensus clients participate in a separate peer-to-peer network with a different specification. Consensus clients need to participate in block gossip so that they can receive new blocks from peers and broadcast them when it is their turn to be block proposer. Similar to the execution layer, this first requires a discovery protocol so that a node can find peers and establish secure sessions for exchanging blocks, attestations etc. + +### Discovery + +Similar to the execution clients, consensus clients use [discv5](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-discovery-domain-discv5) over UDP for finding peers. The consensus layer implementation of discv5 differs from that of the execution clients only in that it includes an adaptor connecting discv5 into a [libP2P](https://libp2p.io/) stack, deprecating DevP2P. The execution layer's RLPx sessions are deprecated in favour of libP2P's noise secure channel handshake. + +### ENRs + +The ENR for consensus nodes includes the node's public key, IP address, UDP and TCP ports and two consensus-specific fields: the attestation subnet bitfield and `eth2` key. The former makes it easier for nodes to find peers participating in specific attestation gossip sub-networks. The `eth2` key contains information about which Ethereum fork version the node is using, ensuring peers are connecting to the right Ethereum. + +### libP2P + +The libP2P stack supports all communications after discovery. Clients can dial and listen on IPv4 and/or IPv6 as defined in their ENR. The protocols on the libP2P layer can be subdivided into the gossip and req/resp domains. + +### Gossip + +The gossip domain includes all information that has to spread rapidly throughout the network. This includes beacon blocks, proofs, attestations, exits and slashings. This is transmitted using libP2P gossipsub v1 and relies on various metadata being stored locally at each node, including maximum size of gossip payloads to receive and transmit. Detailed information about the gossip domain is available [here](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub). + +### Request-response + +The request-response domain contains protocols for clients requesting specific information from their peers. Examples include requesting specific Beacon blocks matching certain root hashes or within a range of slots. The responses are always returned as snappy-compressed SSZ encoded bytes. + +## Why does the consensus client prefer SSZ to RLP? + +SSZ stands for simple serialization. It uses fixed offsets that make it easy to decode individual parts of an encoded message without having to decode the entire structure, which is very useful for the consensus client as it can efficiently grab specific pieces of information from encoded messages. It is also designed specifically to integrate with Merkle protocols, with related efficiency gains for Merkleization. Since all hashes in the consensus layer are Merkle roots, this adds up to a significant improvement. SSZ also guarantees unique representations of values. + +## Connecting the execution and consensus clients + +Both consensus and execution clients run in parallel. They need to be connected so that the consensus client can provide instructions to the execution client, and the execution client can pass bundles of transactions to the consensus client to include in Beacon blocks. The communication between the two clients can be achieved using a local RPC connection. An API known as the ['Engine-API'](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) defines the instructions sent between the two clients. Since both clients sit behind a single network identity, they share an ENR (Ethereum node record) which contains a separate key for each client (eth1 key and eth2 key). + +A summary of the control flow is shown below, with the relevant networking stack in brackets. + +### When consensus client is not block producer: + +- Consensus client receives a block via the block gossip protocol (consensus p2p) +- Consensus client pre-validates the block, i.e. ensures it arrived from a valid sender with correct metadata +- The transactions in the block are sent to the execution layer as an execution payload (local RPC connection) +- The execution layer executes the transactions and validates the state in the block header (i.e. checks hashes match) +- Execution layer passes validation data back to consensus layer, block now considered to be validated (local RPC connection) +- Consensus layer adds block to head of its own blockchain and attests to it, broadcasting the attestation over the network (consensus p2p) + +### When consensus client is block producer: + +- Consensus client receives notice that it is the next block producer (consensus p2p) +- Consensus layer calls `create block` method in execution client (local RPC) +- Execution layer accesses the transaction mempool which has been populated by the transaction gossip protocol (execution p2p) +- Execution client bundles transactions into a block, executes the transactions and generates a block hash +- Consensus client grabs the transactions and block hash from the execution client and adds them to the beacon block (local RPC) +- Consensus client broadcasts the block over the block gossip protocol (consensus p2p) +- Other clients receive the proposed block via the block gossip protocol and validate as described above (consensus p2p) + +Once the block has been attested by sufficient validators it is added to the head of the chain, justified and eventually finalized. + +![](cons_client_net_layer.png) +![](exe_client_net_layer.png) + +Network layer schematic for consensus and execution clients, from [ethresear.ch](https://ethresear.ch/t/eth1-eth2-client-relationship/7248) + +## Further Reading + +[DevP2P](https://github.com/ethereum/devp2p) +[LibP2p](https://github.com/libp2p/specs) +[Consensus layer network specs](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure) +[kademlia to discv5](https://vac.dev/kademlia-to-discv5) +[kademlia paper](https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf) +[intro to Ethereum p2p](https://p2p.paris/en/talks/intro-ethereum-networking/) +[eth1/eth2 relationship](http://ethresear.ch/t/eth1-eth2-client-relationship/7248) +[merge and eth2 client details video](https://www.youtube.com/watch?v=zNIrIninMgg) + +--- + +## Developers > Docs > Networking Layer > Network Addresses + +Ethereum nodes have to identify themselves with some basic information to connect to peers. To ensure any potential peer can interpret this information, it is relayed in one of three standardized formats that any Ethereum node can understand: multiaddr, enode, or Ethereum Node Records (ENRs). ENRs are the current standard for Ethereum network addresses. + +## Prerequisites + +Some understanding of Ethereum's [networking layer](/developers/docs/networking-layer/) is required to understand this page. + +## Multiaddr + +The original Ethereum node address format was the 'multiaddr' (short for 'multi-addresses'). Multiaddr is a universal format designed for peer-to-peer networks. Addresses are represented as key-value pairs with keys and values separated with a forward slash. For example, the multiaddr for a node with IPv4 address `192.168.22.27` listening to TCP port `33000` looks like: + +`/ip4/192.168.22.27/tcp/33000` + +For an Ethereum node, the multiaddr contains the node-ID (a hash of their public key): + +`/ip4/192.168.22.27/tcp/33000/p2p/5t7Nv7dG2d6ffbvAiewVsEwWweU3LdebSqX2y1bPrW8br` + +## Enode + +An enode is a way to identify an Ethereum node using a URL address format. The hexadecimal node-ID is encoded in the username portion of the URL separated from the host using an @ sign. The hostname can only be given as an IP address; DNS names are not allowed. The port in the hostname section is the TCP listening port. If the TCP and UDP (discovery) ports differ, the UDP port is specified as a query parameter "discport". + +In the following example, the node URL describes a node with IP address `10.3.58.6`, TCP port `30303` and UDP discovery port `30301`. + +`enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301` + +## Ethereum Node Records (ENRs) + +Ethereum Node Records (ENRs) are a standardized format for network addresses on Ethereum. They supersede multiaddr's and enodes. These are especially useful because they allow greater informational exchange between nodes. The ENR contains a signature, sequence number and fields detailing the identity scheme used to generate and validate signatures. The ENR can also be populated with arbitrary data organized as key-value pairs. These key-value pairs contain the node's IP address and information about the sub-protocols the node is able to use. Consensus clients use a [specific ENR structure](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure) to identify boot nodes and also include an `eth2` field containing information about the current Ethereum fork and the attestation gossip subnet (this connects the node to a particular set of peers whose attestations are aggregated together). + +## Further Reading + +- [EIP-778: Ethereum Node Records (ENR)](https://eips.ethereum.org/EIPS/eip-778) +- [Network addresses in Ethereum](https://dean.eigenmann.me/blog/2020/01/21/network-addresses-in-ethereum/) +- [LibP2P: Multiaddr-Enode-ENR?!](https://consensys.net/diligence/blog/2020/09/libp2p-multiaddr-enode-enr/) + +--- + +## Developers > Docs > Networking Layer > Portal Network + +Ethereum is a network made up of computers that run Ethereum client software. Each of these computers is called a 'node'. The client software allows a node to send and receive data on the Ethereum network, and verifies data against the Ethereum protocol rules. Nodes keep a lot of historical data in their disk storage and add to it when they receive new packets of information, known as blocks, from other nodes on the network. This is necessary for always checking that a node has information consistent with the rest of the network. This means running a node can require a lot of disk space. Some node operations can require a lot of RAM too. + +To get around this disk storage problem, 'light' nodes have been developed that request information from full nodes instead of storing it all themselves. However, this means the light node is not independently verifying the information and is trusting another node instead. It also means that full nodes are required to take on extra work to serve those light nodes. + +The Portal Network is a new networking design for Ethereum that aims to solve the data availability problem for "light" nodes without having to trust or put extra strain on full nodes, by sharing the necessary data in small chunks across the network. + +More on [nodes and clients](/developers/docs/nodes-and-clients/) + +## Why do we need the Portal Network + +Ethereum nodes store their own full or partial copy of the Ethereum blockchain. This local copy is used to validate transactions and ensure the node is following the correct chain. This locally stored data allows nodes to independently verify that incoming data is valid and correct without needing to trust any other entity. + +This local copy of the blockchain and associated state and receipt data takes up a lot of space on the node's hard disk. For example, a 2TB hard disk is recommended for running a node using [Geth](https://geth.ethereum.org) paired to a consensus client. Using snap sync, which only stores chain data from a relatively recent set of blocks, Geth typically occupies about 650GB of disk space but grows at around 14GB/week (you can prune the node back down to 650GB periodically). + +This means running nodes can be expensive, because a large amount of disk space has to be dedicated to Ethereum. There are several solutions to this problem on the Ethereum roadmap, including [history expiry](/roadmap/statelessness/#history-expiry), [state expiry](/roadmap/statelessness/#state-expiry) and [statelessness](/roadmap/statelessness/). However, these are likely several years away from being implemented. There are also [light nodes](/developers/docs/nodes-and-clients/light-clients/) that do not save their own copy of the chain data, they request the data they need from full nodes. However, this means light nodes have to trust full nodes to provide honest data and also stresses the full nodes that have to serve the data the light nodes need. + +The Portal Network aims to provide an alternative way for light nodes to get their data that does not require trusting or adding significantly to the work that has to be done by full nodes. The way this will be done is to introduce a new way for Ethereum nodes to share data across the network. + +## How does the Portal Network work? + +Ethereum nodes have strict protocols that define how they communicate with each other. Execution clients communicate using a set of subprotocols known as [DevP2P](/developers/docs/networking-layer/#devp2p), while consensus clients use a different stack of subprotocols called [libP2P](/developers/docs/networking-layer/#libp2p). These define the types of data that can be passed between nodes. + +![devP2P and libP2P](portal-network-devp2p-libp2p.png) + +Nodes can also serve specific data through the [JSON-RPC API](/developers/docs/apis/json-rpc/), which is how apps and wallets swap information with Ethereum nodes. However, none of these are ideal protocols for serving data to light clients. + +Light clients can't currently request specific pieces of chain data over DevP2P or libP2p because those protocols are only designed to enable chain synchronization and gossiping of blocks and transactions. Light clients do not want to download this information because that would stop them from being "light". + +The JSON-RPC API is not an ideal choice for light client data requests either, because it relies upon a connection to a specific full node or centralized RPC provider that can serve the data. This means the light client has to trust that specific node/provider to be honest, and also the full node might have to handle lots of requests from many light clients, adding to their bandwidth requirements. + +The point of the Portal Network is to rethink the whole design, building specifically for lightness, outside of the design constraints of the existing Ethereum clients. + +The core idea of the Portal Network is to take the best bits of the current networking stack by enabling information needed by light clients, such as historical data and the identity of the current head of the chain to be served through a lightweight DevP2P style peer-to-peer decentralized network using a [DHT](https://en.wikipedia.org/wiki/Distributed_hash_table) (similar to Bittorrent). + +The idea is to add small parts of the total historical Ethereum data and some specific node responsibilities to each node. Then, requests are served by seeking out the nodes storing the specific data that was requested and retrieving it from them. + +This inverts the normal model of light nodes finding a single node and requesting them to filter and serve large volumes of data; instead, they quickly filter a large network of nodes that each handle small amounts of data. + +The goal is to allow a decentralized network of lightweight Portal clients to: + +- track the head of the chain +- sync recent and historical chain data +- retrieve state data +- broadcast transactions +- execute transactions using the [EVM](/developers/docs/evm/) + +The benefits of this network design are: + +- reduce dependence on centralized providers +- Reduce Internet bandwidth usage +- Minimized or zero syncing +- Accessible to resource-constrained devices (\<1 GB RAM, \<100 MB disk space, 1 CPU) + +The diagram below shows the functions of existing clients that can be delivered by the Portal Network, enabling users to access these functions on very low-resource devices. + +### The Portal Networks + +| Beacon light client | State network | Transaction gossip | History network | +| ------------------- | ---------------------------- | ------------------- | --------------- | +| Beacon chain light | Account and contract storage | Lightweight mempool | Headers | +| Protocol data | | | Block bodies | +| | | | Receipts | + +## Client diversity by default + +The Portal Network developers also made the design choice to build three separate Portal Network clients from day one. + +The Portal Network clients are: + +- [Trin](https://github.com/ethereum/trin): written in Rust +- [Fluffy](https://fluffy.guide): written in Nim +- [Ultralight](https://github.com/ethereumjs/ultralight): written in Typescript +- [Shisui](https://github.com/optimism-java/shisui): written in Go + +Having multiple independent client implementations enhances the resilience and decentralization of the Ethereum network. + +If one client experiences issues or vulnerabilities, other clients can continue to operate smoothly, preventing a single point of failure. Additionally, diverse client implementations foster innovation and competition, driving improvements and reducing monoculture risk within the ecosystem. + +## Further reading + +- [The Portal Network (Piper Merriam at Devcon Bogota)](https://www.youtube.com/watch?v=0stc9jnQLXA). +- [The Portal Network discord](https://discord.gg/CFFnmE7Hbs) +- [The Portal Network website](https://www.ethportal.net/) + +--- + +## Developers > Docs > Networks + +Ethereum networks are groups of connected computers that communicate using the Ethereum protocol. There is only one Ethereum Mainnet, but independent networks conforming to the same protocol rules can be created for testing and development purposes. There are many independent "networks" that conform to the protocol without interacting with each other. You can even start one locally on your own computer for testing your smart contracts and web3 apps. + +Your Ethereum account will work across the different networks, but your account balance and transaction history won't carry over from the main Ethereum network. For testing purposes, it's useful to know which networks are available and how to get testnet ETH to play around with. In general, for security considerations, it's not recommended to reuse mainnet accounts on testnets or vice versa. + +## Prerequisites + +You should understand the [basics of Ethereum](/developers/docs/intro-to-ethereum/) before reading up on the different networks, as the test networks will give you a cheap, safe version of Ethereum to play around with. + +## Public networks + +Public networks are accessible to anyone in the world with an internet connection. Anyone can read or create transactions on a public blockchain and validate the transactions being executed. The consensus among peers decides on the inclusion of transactions and the state of the network. + +### Ethereum Mainnet + +Mainnet is the primary public Ethereum production blockchain, where actual-value transactions occur on the distributed ledger. + +When people and exchanges discuss ETH prices, they're talking about Mainnet ETH. + +### Ethereum Testnets + +In addition to Mainnet, there are public testnets. These are networks used by protocol developers or smart contract developers to test both protocol upgrades as well as potential smart contracts in a production-like environment before deployment to Mainnet. Think of this as an analog to production versus staging servers. + +You should test any contract code you write on a testnet before deploying to Mainnet. Among dapps that integrate with existing smart contracts, most projects have copies deployed to testnets. + +Most testnets started by using a permissioned proof-of-authority consensus mechanism. This means a small number of nodes are chosen to validate transactions and create new blocks – staking their identity in the process. Alternatively, some testnets feature an open proof-of-stake consensus mechanism where everyone can test running a validator, just like Ethereum Mainnet. + +ETH on testnets is supposed to have no real value; however, there have been markets created for certain types of testnet ETH that have become scarce or hard to obtain. Since you need ETH to actually interact with Ethereum (even on testnets), most people get testnet ETH for free from faucets. Most faucets are webapps where you can input an address which you request ETH to be sent to. + +#### Which Testnet should I use? + +The two public testnets that client developers are currently maintaining are Sepolia and Hoodi. Sepolia is a network for contract and application developers to test their applications. The Hoodi network lets protocol developers test network upgrades, and lets stakers test running validators. + +#### Sepolia + +**Sepolia is the recommended default testnet for application development**. The Sepolia network uses a permissioned validator set controlled by client & testing teams. + +##### Resources + +- [Website](https://sepolia.dev/) +- [GitHub](https://github.com/eth-clients/sepolia) +- [Otterscan](https://sepolia.otterscan.io/) +- [Etherscan](https://sepolia.etherscan.io) +- [Blockscout](https://eth-sepolia.blockscout.com/) + +##### Faucets + +- [QuickNode Sepolia Faucet](https://faucet.quicknode.com/ethereum/sepolia) +- [Grabteeth](https://grabteeth.xyz/) +- [PoW faucet](https://sepolia-faucet.pk910.de/) +- [Alchemy Sepolia faucet](https://www.alchemy.com/faucets/ethereum-sepolia) +- [Infura Sepolia faucet](https://www.infura.io/faucet) +- [Chainstack Sepolia faucet](https://faucet.chainstack.com/sepolia-testnet-faucet) +- [Ethereum Ecosystem faucet](https://www.ethereum-ecosystem.com/faucets/ethereum-sepolia) +- [Google Cloud Web3 Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) + +#### Hoodi + +Hoodi is a testnet for testing validating and staking. The Hoodi network is open for users wanting to run a testnet validator. Stakers wanting to test protocol upgrades before they are deployed to mainnet should therefore use Hoodi. + +- Open validator set, stakers can test network upgrades +- Large state, useful for testing complex smart contract interactions +- Longer to sync and requires more storage to run a node + +##### Resources + +- [Website](https://hoodi.ethpandaops.io/) +- [GitHub](https://github.com/eth-clients/hoodi) +- [Explorer](https://explorer.hoodi.ethpandaops.io/) +- [Checkpoint Sync](https://checkpoint-sync.hoodi.ethpandaops.io/) +- [Otterscan](https://hoodi.otterscan.io/) +- [Etherscan](https://hoodi.etherscan.io/) +- [Blockscout](https://hoodi.cloud.blockscout.com/) + +##### Faucets + +- [Hoodi Faucet](https://hoodi.ethpandaops.io/) +- [PoW faucet](https://hoodi-faucet.pk910.de/) + +#### Holesky + +The Holesky testnet will be [deprecated in September 2025](https://blog.ethereum.org/en/2025/03/18/hoodi-holesky). Staking operators and infrastructure providers should use Hoodi for validator testing instead. + +##### Resources + +- [Website](https://holesky.ethpandaops.io/) +- [GitHub](https://github.com/eth-clients/holesky) +- [Otterscan](https://holesky.otterscan.io/) +- [Etherscan](https://holesky.etherscan.io/) +- [Blockscout](https://eth-holesky.blockscout.com/) + +##### Faucets + +- [QuickNode Holesky Faucet](https://faucet.quicknode.com/ethereum/holesky) +- [PoW faucet](https://holesky-faucet.pk910.de/) +- [Alchemy Holesky Faucet](https://www.alchemy.com/faucets/ethereum-holesky) +- [Chainstack Holesky faucet](https://faucet.chainstack.com/holesky-testnet-faucet) +- [Ethereum Ecosystem faucet](https://www.ethereum-ecosystem.com/faucets/ethereum-holesky) +- [Google Cloud Web3 Holesky faucet](https://cloud.google.com/application/web3/faucet/ethereum/holesky) + +To launch a Validator on Hoodi testnet, use [Hoodi launchpad](https://hoodi.launchpad.ethereum.org/en/). + +### Layer 2 testnets + +[Layer 2 (L2)](/layer-2/) is a collective term to describe a specific set of Ethereum scaling solutions. A layer 2 is a separate blockchain that extends Ethereum and inherits the security guarantees of Ethereum. Layer 2 testnets are usually tightly coupled to public Ethereum testnets. + +#### Arbitrum Sepolia + +A testnet for [Arbitrum](https://arbitrum.io/). + +##### Resources + +- [Etherscan](https://sepolia.arbiscan.io/) +- [Blockscout](https://sepolia-explorer.arbitrum.io/) + +##### Faucets + +- [Chainlink faucet](https://faucets.chain.link/arbitrum-sepolia) +- [Alchemy faucet](https://www.alchemy.com/faucets/arbitrum-sepolia) +- [QuickNode Arbitrum Sepolia Faucet](https://faucet.quicknode.com/arbitrum/sepolia) +- [Alchemy Arbitrum Sepolia Faucet](https://www.alchemy.com/faucets/arbitrum-sepolia) +- [Chainlink Arbitrum Sepolia faucet](https://faucets.chain.link/arbitrum-sepolia) + +#### Optimistic Sepolia + +A testnet for [Optimism](https://www.optimism.io/). + +##### Resources + +- [Etherscan](https://sepolia-optimistic.etherscan.io/) +- [Blockscout](https://optimism-sepolia.blockscout.com/) + +##### Faucets + +- [Chainlink faucet](https://faucets.chain.link/optimism-sepolia) +- [Alchemy faucet](https://www.alchemy.com/faucets/optimism-sepolia) +- [Testnet faucets](https://docs.optimism.io/builders/tools/build/faucets) + +#### Starknet Sepolia + +A testnet for [Starknet](https://www.starknet.io). + +##### Resources + +- [Starkscan](https://sepolia.starkscan.co/) + +##### Faucets + +- [Alchemy faucet](https://www.alchemy.com/faucets/starknet-sepolia) +- [Starknet faucet](https://starknet-faucet.vercel.app/) +- [Blast Starknet Sepolia faucet](https://blastapi.io/faucets/starknet-sepolia-eth) + +## Private networks + +An Ethereum network is a private network if its nodes are not connected to a public network (i.e. Mainnet or a testnet). In this context, private only means reserved or isolated, rather than protected or secure. + +### Development networks + +To develop an Ethereum application, you'll want to run it on a private network to see how it works before deploying it. Similar to how you create a local server on your computer for web development, you can create a local blockchain instance to test your dapp. This allows for much faster iteration than a public testnet. + +There are projects and tools dedicated to assist with this. Learn more about [development networks](/developers/docs/development-networks/). + +### Consortium networks + +The consensus process is controlled by a pre-defined set of nodes that are trusted. For example, a private network of known academic institutions that each govern a single node, and blocks are validated by a threshold of signatories within the network. + +If a public Ethereum network is like the public internet, a consortium network is like a private intranet. + +## Related tools + +- [Chainlist](https://chainlist.org/) _list of EVM networks to connect wallets and providers to the appropriate Chain ID and Network ID_ +- [EVM-based Chains](https://github.com/ethereum-lists/chains) _GitHub repo of chain metadata that powers Chainlist_ + +## Further reading + +- [Proposal: Predictable Ethereum Testnet Lifecycle](https://ethereum-magicians.org/t/proposal-predictable-ethereum-testnet-lifecycle/11575/17) +- [The Evolution of Ethereum Testnets](https://etherworld.co/2022/08/19/the-evolution-of-ethereum-testnet/) + +--- + +## Developers > Docs > Nodes And Clients > Archive Nodes + +An archive node is an instance of an Ethereum client configured to build an archive of all historical states. It is a useful tool for certain use cases but might be more tricky to run than a full node. + +## Prerequisites + +You should understand the concept of an [Ethereum node](/developers/docs/nodes-and-clients/), [its architecture](/developers/docs/nodes-and-clients/node-architecture/), [sync strategies](/developers/docs/nodes-and-clients/#sync-modes), practices of [running](/developers/docs/nodes-and-clients/run-a-node/) and [using them](/developers/docs/apis/json-rpc/). + +## What is an archive node + +To grasp the importance of an archive node, let's clarify the concept of "state." Ethereum can be referred to as _transaction-based state machine_. It consists of accounts and applications executing transactions which are changing their state. The global data with information about each account and contract is stored in a trie database called state. This is handled by the execution layer (EL) client and includes: + +- Account balances and nonces +- Contract code and storage +- Consensus-related data, e.g. Staking Deposit Contract + +To interact with the network, verify and produce new blocks, Ethereum clients have to keep up with the most recent changes (the tip of the chain) and therefore the current state. An execution layer client configured as a full node verifies and follows the latest state of the network but only caches the past few states, e.g. the state associated with the last 128 blocks, so it can handle chain reorgs and provide fast access to recent data. The recent state is what all clients need to verify incoming transactions and use the network. + +You can imagine the state as a momentary network snapshot at a given block and the archive as a history replay. + +Historical states can be safely pruned because they are not necessary for the network to operate and it would be uselessly redundant for client to keep all out-of-date data. States that existed before some recent block (e.g. 128 blocks before the head) are effectively thrown away. Full nodes only keep historical blockchain data (blocks and transactions) and occasional historical snapshots they can use to regenerate older states on request. They do this by re-executing past transactions in the EVM, which can be computationally demanding when the desired state is far from the nearest snapshot. + +However, this means that accessing a historical state on a full node consumes a lot of computation. The client might need to execute all past transactions and compute one historical state from genesis. Archive nodes solve this by storing not only the most recent states but every historical state created after each block. It basically makes a trade-off with bigger disk space requirement. + +It's important to note that the network does not depend on archive nodes to keep and provide all historical data. As mentioned above, all historical interim states can be derived on a full node. Transactions are stored by any full node (currently less than 400G) and can be replayed to build the whole archive. + +### Use cases + +Regular usage of Ethereum like sending transactions, deploying contracts, verifying consensus, etc. does not require access to historical states. Users never need an archive node for a standard interaction with the network. + +The main benefit of state archive is a quick access to queries about historical states. For example, archive node would promptly return results like: + +- _What was ETH balance of account 0x1337... at block 15537393?_ +- _What is the balance of token 0x in contract 0x at block 1920000?_ + +As explained above, a full node would need to generate this data by EVM execution which uses the CPU and takes time. Archive nodes access them on the disk and serve responses immediately. This is a useful feature for certain parts of infrastructure, for example: + +- Service providers like block explorers +- Researchers +- Security analysts +- Dapp developers +- Auditing and compliance + +There are various free [services](/developers/docs/nodes-and-clients/nodes-as-a-service/) that also allow access to historical data. As it is more demanding to run an archive node, this access is mostly limited and works only for occasional access. If your project requires constant access to historical data, you should consider running one yourself. + +## Implementations and usage + +Archive node in this context means data served by user facing execution layer clients as they handle the state database and provide JSON-RPC endpoints. Configuration options, sync time and database size may vary by client. For details, please refer to the documentation provided by your client. + +Before starting your own archive node, learn about the differences between the clients and especially the various [hardware requirements](/developers/docs/nodes-and-clients/run-a-node/#requirements). Most clients are not optimized for this feature and their archives require more than 12TB of space. In contrast, implementations like Erigon can store the same data in under 3TB which makes them the most effective way of running an archive node. + +## Recommended practices + +Apart from general [recommendations for running a node](/developers/docs/nodes-and-clients/run-a-node/), an archive node may be more demanding on hardware and maintenance. Considering Erigons [key features](https://github.com/ledgerwatch/erigon#key-features), the most practical approach is using the [Erigon](/developers/docs/nodes-and-clients/#erigon) client implementation. + +### Hardware + +Always make sure to verify hardware requirements for a given mode in a client's documentation. +The biggest requirement for archive nodes is the disk space. Depending on client, it varies from 3TB to 12TB. Even if HDD might be considered a better solution for large amounts of data, syncing it and constantly updating the head of the chain will require SSD drives. [SATA](https://www.cleverfiles.com/help/sata-hard-drive.html) drives are good enough but it should be a reliable quality, at least [TLC](https://blog.synology.com/tlc-vs-qlc-ssds-what-are-the-differences). Disks can be fitted into a desktop computer or a server with enough slots. Such dedicated devices are ideal for running high uptime node. It's totally possible to run it on a laptop but the portability will come at an additional cost. + +All of the data needs to fit in one volume, therefore disks have to be joined, e.g. with [RAID0](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_0) or LVM. It might be also worth considering using [ZFS](https://en.wikipedia.org/wiki/ZFS) as it supports "Copy-on-write" which ensures data is correctly written to the disk without any low level errors. + +For more stability and security in preventing accidental database corruption, especially in a professional setup, consider using [ECC memory](https://en.wikipedia.org/wiki/ECC_memory) if your system supports it. The size of RAM is generally advised to be the same as for a full node but more RAM can help speed up the synchronization. + +During initial sync, clients in archive mode will execute every transaction since genesis. Execution speed is mostly limited by the CPU, so a faster CPU can help with the initial sync time. On an average consumer computer, the initial sync can take up to a month. + +## Further reading + +- [Ethereum Full Node vs Archive Node](https://www.quicknode.com/guides/infrastructure/ethereum-full-node-vs-archive-node) - _QuickNode, September 2022_ +- [Building Your Own Ethereum Archive Node](https://tjayrush.medium.com/building-your-own-ethereum-archive-node-72c014affc09) - _Thomas Jay Rush, August 2021_ +- [How to set up Erigon, Erigon’s RPC and TrueBlocks (scrape and API) as services](https://magnushansson.xyz/blog_posts/crypto_defi/2022-01-10-Erigon-Trueblocks) _– Magnus Hansson, updated September 2022_ + +## Related topics + +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [Running a node](/developers/docs/nodes-and-clients/run-a-node/) + +--- + +## Developers > Docs > Nodes And Clients > Bootnodes + +When a new node joins the Ethereum network it needs to connect to nodes that are already on the network in order to then discover new peers. These entry points into the Ethereum network are called bootnodes. Clients usually have a list of bootnodes hardcoded into them. These bootnodes are typically run by the Ethereum Foundation's devops team or client teams themselves. Note that bootnodes are not the same as static nodes. Static nodes are called over and over again, whereas bootnodes are only called upon if there are not enough peers to connect to and a node needs to bootstrap some new connections. + +## Connect to a bootnode + +Most clients have a list of bootnodes builtin, but you might also want to run your own bootnode, or use one that is not part of the client's hardcoded list. In this case, you can specify them when starting your client, as follows (example is for Geth, please check your client's documentation): + +``` +geth --bootnodes "enode://@:" +``` + +## Run a bootnode + +Bootnodes are full nodes that are not behind a NAT ([Network Address Translation](https://www.geeksforgeeks.org/network-address-translation-nat/)). Every full node can act as a bootnode as long as it is publicly available. + +When you start up a node it should log your [enode](/developers/docs/networking-layer/network-addresses/#enode), which is a public identifier that others can use to connect to your node. + +The enode is usually regenerated on every restart, so make sure to look at your client's documentation on how to generate a persistent enode for your bootnode. + +In order to be a good bootnode it's a good idea to increase the maximum number of peers that can connect to it. Running a bootnode with many peers will increase the bandwidth requirement significantly. + +## Available bootnodes + +A list of builtin bootnodes within go-ethereum can be found [here](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go#L23). These bootnodes are maintained by the Ethereum Foundation and the go-ethereum team. + +There are other lists of bootnodes maintained by volunteers available. Please make sure to always include at least one official bootnode, otherwise you could be eclipse attacked. + +--- + +## Developers > Docs > Nodes And Clients > Client Diversity + +The behavior of an Ethereum node is controlled by the client software it runs. There are several production-level Ethereum clients, each one developed and maintained in different languages by separate teams. The clients are built to a common spec that ensures the clients seamlessly communicate with each other and have the same functionality and provide an equivalent user experience. However, at the moment the distribution of clients across nodes is not equal enough to realize this network fortification to its full potential. Ideally, users divide roughly equally across the various clients to bring as much client diversity as possible to the network. + +## Prerequisites + +If you don't already understand what nodes and clients are, check out [nodes and clients](/developers/docs/nodes-and-clients/). [Execution](/glossary/#execution-layer) and [consensus](/glossary/#consensus-layer) layers are defined in the glossary. + +## Why are there multiple clients? + +Multiple, independently developed and maintained clients exist because client diversity makes the network more resilient to attacks and bugs. Multiple clients is a strength unique to Ethereum - other blockchains rely on the infallibility of a single client. However, it is not enough simply to have multiple clients available, they have to be adopted by the community and the total active nodes distributed relatively evenly across them. + +## Why is client diversity important? + +Having many independently developed and maintained clients is vital for the health of a decentralized network. Let's explore the reasons why. + +### Bugs + +A bug in an individual client is less of a risk to the network when representing a minority of Ethereum nodes. With a roughly even distribution of nodes across many clients, the likelihood of most clients suffering from a shared issue is small, and as a result, the network is more robust. + +### Resilience to attacks + +Client diversity also offers resilience to attacks. For example, an attack that [tricks a particular client](https://twitter.com/vdWijden/status/1437712249926393858) onto a particular branch of the chain is unlikely to be successful because other clients are unlikely to be exploitable in the same way and the canonical chain remains uncorrupted. Low client diversity increases the risk associated with a hack on the dominant client. Client diversity has already proven to be an important defense against malicious attacks on the network, for example the Shanghai denial-of-service attack in 2016 was possible because attackers were able to trick the dominant client (Geth) into executing a slow disk i/o operation tens of thousands of times per block. Because alternative clients were also online which did not share the vulnerability, Ethereum was able to resist the attack and continue to operate while the vulnerability in Geth was fixed. + +### Proof-of-stake finality + +A bug in a consensus client with over 33% of the Ethereum nodes could prevent the consensus layer from finalizing, meaning users could not trust that transactions would not be reverted or changed at some point. This would be very problematic for many of the apps built on top of Ethereum, particularly DeFi. + + Worse still, a critical bug in a client with a two-thirds majority could cause the chain to incorrectly split and finalize, leading to a large set of validators getting stuck on an invalid chain. If they want to rejoin the correct chain, these validators face slashing or a slow and expensive voluntary withdrawal and reactivation. The magnitude of a slashing scales with the number of culpable nodes with a two-thirds majority slashed maximally (32 ETH). + +Although these are unlikely scenarios, the Ethereum eco-system can mitigate their risk by evening out the distribution of clients across the active nodes. Ideally, no consensus client would ever reach a 33% share of the total nodes. + +### Shared responsibility + +There is also a human cost to having majority clients. It puts excess strain and responsibility on a small development team. The lesser the client diversity, the greater the burden of responsibility for the developers maintaining the majority client. Spreading this responsibility across multiple teams is good for both the health of Ethereum's network of nodes and its network of people. + +## Current client diversity + +![Pie chart showing client diversity](./client-diversity.png) +_Diagram data from [ethernodes.org](https://ethernodes.org) and [clientdiversity.org](https://clientdiversity.org/)_ + +The two pie charts above show snapshots of the current client diversity for the execution and consensus layers (at time of writing in January 2022). The execution layer is overwhelmingly dominated by [Geth](https://geth.ethereum.org/), with [Open Ethereum](https://openethereum.github.io/) a distant second, [Erigon](https://github.com/ledgerwatch/erigon) third and [Nethermind](https://nethermind.io/) fourth, with other clients comprising less than 1 % of the network. The most commonly used client on the consensus layer - [Prysm](https://prysmaticlabs.com/#projects) - is not as dominant as Geth but still represents over 60% of the network. [Lighthouse](https://lighthouse.sigmaprime.io/) and [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) make up ~20% and ~14% respectively, and other clients are rarely used. + +The execution layer data were obtained from [Ethernodes](https://ethernodes.org) on 23-Jan-2022. Data for consensus clients was obtained from [Michael Sproul](https://github.com/sigp/blockprint). Consensus client data is more difficult to obtain because the consensus layer clients do not always have unambiguous traces that can be used to identify them. The data was generated using a classification algorithm that sometimes confuses some of the minority clients (see [here](https://twitter.com/sproulM_/status/1440512518242197516) for more details). In the diagram above, these ambiguous classifications are treated with an either/or label (e.g. Nimbus/Teku). Nevertheless, it is clear that the majority of the network is running Prysm. The data is a snapshot over a fixed set of blocks (in this case Beacon blocks in slots 2048001 to 2164916) and Prysm's dominance has sometimes been higher, exceeding 68%. Despite only being snapshots, the values in the diagram provide a good general sense of the current state of client diversity. + +Up to date client diversity data for the consensus layer is now available at [clientdiversity.org](https://clientdiversity.org/). + +## Execution layer + +Until now, the conversation around client diversity has focused mainly on the consensus layer. However, the execution client [Geth](https://geth.ethereum.org) currently accounts for around 85% of all nodes. This percentage is problematic for the same reasons as for consensus clients. For example, a bug in Geth affecting transaction handling or constructing execution payloads could lead to consensus clients finalizing problematic or bugged transactions. Therefore, Ethereum would be healthier with a more even distribution of execution clients, ideally with no client representing more than 33% of the network. + +## Use a minority client + +Addressing client diversity requires more than individual users to choose minority clients - it requires validator pools and institutions like the major dapps and exchanges to switch clients too. However, all users can do their part in redressing the current imbalance and normalizing the use of all the available Ethereum software. After The Merge, all node operators will be required to run an execution client and a consensus client. Choosing combinations of the clients suggested below will help increase client diversity. + +### Execution clients + +[Besu](https://www.hyperledger.org/use/besu) + +[Nethermind](https://downloads.nethermind.io/) + +[Erigon](https://github.com/ledgerwatch/erigon) + +[Go-Ethereum](https://geth.ethereum.org/) + +### Consensus clients + +[Nimbus](https://nimbus.team/) + +[Lighthouse](https://github.com/sigp/lighthouse) + +[Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) + +[Lodestar](https://github.com/ChainSafe/lodestar) + +[Prysm](https://docs.prylabs.network/docs/getting-started) + +[Grandine](https://docs.grandine.io/) + +Technical users can help accelerate this process by writing more tutorials and documentation for minority clients and encouraging their node-operating peers to migrate away from the dominant clients. Guides for switching to a minority consensus client are available on [clientdiversity.org](https://clientdiversity.org/). + +## Client diversity dashboards + +Several dashboards give real-time client diversity statistics for the execution and consensus layer. + +**Consensus layer:** + +- [Rated.network](https://www.rated.network/) +- [clientdiversity.org](https://clientdiversity.org/) + +**Execution layer:** + +- [supermajority.info](https://supermajority.info//) +- [Ethernodes](https://ethernodes.org/) + +## Further reading + +- [Client diversity on Ethereum's consensus layer](https://mirror.xyz/jmcook.eth/S7ONEka_0RgtKTZ3-dakPmAHQNPvuj15nh0YGKPFriA) +- [Ethereum Merge: Run the majority client at your own peril!](https://dankradfeist.de/ethereum/2022/03/24/run-the-majority-client-at-your-own-peril.html) – _Dankrad Fiest, March 24 2022_ +- [Importance of client diversity](https://our.status.im/the-importance-of-client-diversity/) +- [List of Ethereum node services](https://ethereumnodes.com/) +- ["Five Whys" of the client diversity problem](https://notes.ethereum.org/@afhGjrKfTKmksTOtqhB9RQ/BJGj7uh08) +- [Ethereum Diversity and How to Solve For It (YouTube)](https://www.youtube.com/watch?v=1hZgCaiqwfU) +- [clientdiversity.org](https://clientdiversity.org/) + +## Related topics + +- [Run an Ethereum node](/run-a-node/) +- [Nodes and clients](/developers/docs/nodes-and-clients/) + +--- + +## Developers > Docs > Nodes And Clients + +Ethereum is a distributed network of computers (known as nodes) running software that can verify blocks and transaction data. The software must be run on your computer to turn it into an Ethereum node. There are two separate pieces of software (known as 'clients') required to form a node. + +## Prerequisites + +You should understand the concept of a peer-to-peer network and the [basics of the EVM](/developers/docs/evm/) before diving deeper and running your own instance of an Ethereum client. Take a look at our [introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +If you're new to the topic of nodes, we recommend first checking out our user-friendly introduction on [running an Ethereum node](/run-a-node). + +## What are nodes and clients? + +A "node" is any instance of Ethereum client software that is connected to other computers also running Ethereum software, forming a network. A client is an implementation of Ethereum that verifies data against the protocol rules and keeps the network secure. A node has to run two clients: a consensus client and an execution client. + +- The execution client (also known as the Execution Engine, EL client or formerly the Eth1 client) listens to new transactions broadcasted in the network, executes them in EVM, and holds the latest state and database of all current Ethereum data. +- The consensus client (also known as the Beacon Node, CL client or formerly the Eth2 client) implements the proof-of-stake consensus algorithm, which enables the network to achieve agreement based on validated data from the execution client. There is also a third piece of software, known as a 'validator' that can be added to the consensus client, allowing a node to participate in securing the network. + +These clients work together to keep track of the head of the Ethereum chain and allow users to interact with the Ethereum network. The modular design with multiple pieces of software working together is called [encapsulated complexity](https://vitalik.eth.limo/general/2022/02/28/complexity.html). This approach made it easier to execute [The Merge](/roadmap/merge) seamlessly, makes client software easier to maintain and develop, and enables the reuse of individual clients, for example, in the [layer 2 ecosystem](/layer-2/). + +![Coupled execution and consensus clients](./eth1eth2client.png) +Simplified diagram of a coupled execution and consensus client. + +### Client diversity + +Both [execution clients](/developers/docs/nodes-and-clients/#execution-clients) and [consensus clients](/developers/docs/nodes-and-clients/#consensus-clients) exist in a variety of programming languages developed by different teams. + +Multiple client implementations can make the network stronger by reducing its dependency on a single codebase. The ideal goal is to achieve diversity without any client dominating the network, thereby eliminating a potential single point of failure. +The variety of languages also invites a broader developer community and allows them to create integrations in their preferred language. + +Learn more about [client diversity](/developers/docs/nodes-and-clients/client-diversity/). + +What these implementations have in common is they all follow a single specification. Specifications dictate how the Ethereum network and blockchain functions. Every technical detail is defined and specifications can be found as: + +- Originally, the [Ethereum Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) +- [Execution specs](https://github.com/ethereum/execution-specs/) +- [Consensus specs](https://github.com/ethereum/consensus-specs) +- [EIPs](https://eips.ethereum.org/) implemented in various [network upgrades](/history/) + +### Tracking nodes in the network + +Multiple trackers offer a real-time overview of nodes in the Ethereum network. Note that due to the nature of decentralized networks, these crawlers can only provide a limited view of the network and might report different results. + +- [Map of nodes](https://etherscan.io/nodetracker) by Etherscan +- [Ethernodes](https://ethernodes.org/) by Bitfly +- [Nodewatch](https://www.nodewatch.io/) by Chainsafe, crawling consensus nodes +- [Monitoreth](https://monitoreth.io/) - by MigaLabs, A distributed network monitoring tool +- [Weekly Network Health Reports](https://probelab.io) - by ProbeLab, Using the [Nebula crawler](https://github.com/dennis-tra/nebula) and other tools + +## Node types + +If you want to [run your own node](/developers/docs/nodes-and-clients/run-a-node/), you should understand that there are different types of node that consume data differently. In fact, clients can run three different types of nodes: light, full and archive. There are also options of different sync strategies which enable faster synchronization time. Synchronization refers to how quickly it can get the most up-to-date information on Ethereum's state. + +### Full node + +Full nodes do a block-by-block validation of the blockchain, including downloading and verifying the block body and state data for each block. There are different classes of full node - some start from the genesis block and verify every single block in the entire history of the blockchain. Others start their verification at a more recent block that they trust to be valid (e.g. Geth's 'snap sync'). Regardless of where the verification starts, full nodes only keep a local copy of relatively recent data (typically the most recent 128 blocks), allowing older data to be deleted to save disk space. Older data can be regenerated when it is needed. + +- Stores full blockchain data (although this is periodically pruned so a full node does not store all state data back to genesis) +- Participates in block validation, verifies all blocks and states. +- All states can be either retrieved from local storage or regenerated from 'snapshots' by a full node. +- Serves the network and provides data on request. + +### Archive node + +Archive nodes are full nodes that verify every block from genesis and never delete any of the downloaded data. + +- Stores everything kept in the full node and builds an archive of historical states. It is needed if you want to query something like an account balance at block #4,000,000, or simply and reliably test your own transactions set without validating them using tracing. +- This data represents units of terabytes, which makes archive nodes less attractive for average users but can be handy for services like block explorers, wallet vendors, and chain analytics. + +Syncing clients in any mode other than archive will result in pruned blockchain data. This means, there is no archive of all historical states but the full node is able to build them on demand. + +Learn more about [Archive nodes](/developers/docs/nodes-and-clients/archive-nodes). + +### Light node + +Instead of downloading every block, light nodes only download block headers. These headers contain summary information about the contents of the blocks. Any other information the light node requires gets requested from a full node. The light node can then independently verify the data they receive against the state roots in the block headers. Light nodes enable users to participate in the Ethereum network without the powerful hardware or high bandwidth required to run full nodes. Eventually, light nodes might run on mobile phones or embedded devices. The light nodes do not participate in consensus (i.e. they cannot be validators), but they can access the Ethereum blockchain with the same functionality and security guarantees as a full node. + +Light clients are an area of active development for Ethereum and we expect to see new light clients for the consensus layer and execution layer soon. +There are also potential routes to providing light client data over the [gossip network](https://www.ethportal.net/). This is advantageous because the gossip network could support a network of light nodes without requiring full nodes to serve requests. + +Ethereum does not support a large population of light nodes yet, but light node support is an area expected to develop rapidly in the near future. In particular, clients like [Nimbus](https://nimbus.team/), [Helios](https://github.com/a16z/helios), and [LodeStar](https://lodestar.chainsafe.io/) are currently heavily focused on light nodes. + +## Why should I run an Ethereum node? + +Running a node allows you to directly, trustlessly and privately use Ethereum while supporting the network by keeping it more robust and decentralized. + +### Benefits to you + +Running your own node enables you to use Ethereum in a private, self-sufficient and trustless manner. You don't need to trust the network because you can verify the data yourself with your client. "Don't trust, verify" is a popular blockchain mantra. + +- Your node verifies all the transactions and blocks against consensus rules by itself. This means you don’t have to rely on any other nodes in the network or fully trust them. +- You can use an Ethereum wallet with your own node. You can use dapps more securely and privately because you won't have to leak your addresses and balances to intermediaries. Everything can be checked with your own client. [MetaMask](https://metamask.io), [Frame](https://frame.sh/), and [many other wallets](/wallets/find-wallet/) offer RPC-importing, allowing them to use your node. +- You can run and self-host other services which depend on data from Ethereum. For example, this might be a Beacon Chain validator, software like layer 2, infrastructure, block explorers, payment processors, etc. +- You can provide your own custom [RPC endpoints](/developers/docs/apis/json-rpc/). You could even offer these endpoints publicly to the community to help them avoid big centralized providers. +- You can connect to your node using **Inter-process Communications (IPC)** or rewrite the node to load your program as a plugin. This grants low latency, which helps a lot, e.g. when processing a lot of data using web3 libraries or when you need to replace your transactions as fast as possible (i.e. frontrunning). +- You can directly stake ETH to secure the network and earn rewards. See [solo staking](/staking/solo/) to get started. + +![How you access Ethereum via your application and nodes](./nodes.png) + +### Network benefits + +A diverse set of nodes is important for Ethereum’s health, security and operational resiliency. + +- Full nodes enforce the consensus rules so they can’t be tricked into accepting blocks that don't follow them. This provides extra security in the network because if all the nodes were light nodes, which don't do full verification, validators could attack the network. +- In case of an attack which overcomes the crypto-economic defenses of [proof-of-stake](/developers/docs/consensus-mechanisms/pos/#what-is-pos), a social recovery can be performed by full nodes choosing to follow the honest chain. +- More nodes in the network result in a more diverse and robust network, the ultimate goal of decentralization, which enables a censorship-resistant and reliable system. +- Full nodes provide access to blockchain data for lightweight clients that depend on it. Light nodes don't store the whole blockchain, instead they verify data via the [state roots in block headers](/developers/docs/blocks/#block-anatomy). They can request more information from full nodes if they need it. + +If you run a full node, the whole Ethereum network benefits from it, even if you don't run a validator. + +## Running your own node + +Interested in running your own Ethereum client? + +For a beginner-friendly introduction visit our [run a node](/run-a-node) page to learn more. + +If you're more of a technical user, dive into more details and options on how to [spin up your own node](/developers/docs/nodes-and-clients/run-a-node/). + +## Alternatives + +Setting up your own node can cost you time and resources but you don’t always need to run your own instance. In this case, you can use a third party API provider. For an overview of using these services, check out [nodes as a service](/developers/docs/nodes-and-clients/nodes-as-a-service/). + +If somebody runs an Ethereum node with a public API in your community, you can point your wallets to a community node via Custom RPC and gain more privacy than with some random trusted third party. + +On the other hand, if you run a client, you can share it with your friends who might need it. + +## Execution clients + +The Ethereum community maintains multiple open-source execution clients (previously known as 'Eth1 clients', or just 'Ethereum clients'), developed by different teams using different programming languages. This makes the network stronger and more [diverse](/developers/docs/nodes-and-clients/client-diversity/). The ideal goal is to achieve diversity without any client dominating to reduce any single points of failure. + +This table summarizes the different clients. All of them pass [client tests](https://github.com/ethereum/tests) and are actively maintained to stay updated with network upgrades. + +| Client | Language | Operating systems | Networks | Sync strategies | State pruning | +| ------------------------------------------------------------------------ | ---------- | --------------------- | ------------------------- | -------------------------------------------------------------- | --------------- | +| [Geth](https://geth.ethereum.org/) | Go | Linux, Windows, macOS | Mainnet, Sepolia, Holesky | [Snap](#snap-sync), [Full](#full-sync) | Archive, Pruned | +| [Nethermind](https://www.nethermind.io/) | C#, .NET | Linux, Windows, macOS | Mainnet, Sepolia, Holesky | [Snap](#snap-sync) (without serving), Fast, [Full](#full-sync) | Archive, Pruned | +| [Besu](https://besu.hyperledger.org/en/stable/) | Java | Linux, Windows, macOS | Mainnet, Sepolia, Holesky | [Snap](#snap-sync), [Fast](#fast-sync), [Full](#full-sync) | Archive, Pruned | +| [Erigon](https://github.com/ledgerwatch/erigon) | Go | Linux, Windows, macOS | Mainnet, Sepolia, Holesky | [Full](#full-sync) | Archive, Pruned | +| [Reth](https://reth.rs/) | Rust | Linux, Windows, macOS | Mainnet, Sepolia, Holesky | [Full](#full-sync) | Archive, Pruned | +| [EthereumJS](https://github.com/ethereumjs/ethereumjs-monorepo) _(beta)_ | TypeScript | Linux, Windows, macOS | Sepolia, Holesky | [Full](#full-sync) | Pruned | + +For more on supported networks, read up on [Ethereum networks](/developers/docs/networks/). + +Each client has unique use cases and advantages, so you should choose one based on your own preferences. Diversity allows implementations to be focused on different features and user audiences. You may want to choose a client based on features, support, programming language, or licences. + +### Besu + +Hyperledger Besu is an enterprise-grade Ethereum client for public and permissioned networks. It runs all of the Ethereum Mainnet features, from tracing to GraphQL, has extensive monitoring and is supported by ConsenSys, both in open community channels and through commercial SLAs for enterprises. It is written in Java and is Apache 2.0 licensed. + +Besu's extensive [documentation](https://besu.hyperledger.org/en/stable/) will guide you through all details on its features and setups. + +### Erigon + +Erigon, formerly known as Turbo‐Geth, started as a fork of Go Ethereum oriented toward speed and disk‐space efficiency. Erigon is a completely re-architected implementation of Ethereum, currently written in Go but with implementations in other languages under development. Erigon's goal is to provide a faster, more modular, and more optimized implementation of Ethereum. It can perform a full archive node sync using around 2TB of disk space, in under 3 days. + +### Go Ethereum + +Go Ethereum (Geth for short) is one of the original implementations of the Ethereum protocol. Currently, it is the most widespread client with the biggest user base and variety of tooling for users and developers. It is written in Go, fully open source and licensed under the GNU LGPL v3. + +Learn more about Geth in its [documentation](https://geth.ethereum.org/docs/). + +### Nethermind + +Nethermind is an Ethereum implementation created with the C# .NET tech stack, licensed with LGPL-3.0, running on all major platforms including ARM. It offers great performance with: + +- an optimized virtual machine +- state access +- networking and rich features like Prometheus/Grafana dashboards, seq enterprise logging support, JSON-RPC tracing, and analytics plugins. + +Nethermind also has [detailed documentation](https://docs.nethermind.io), strong dev support, an online community and 24/7 support available for premium users. + +### Reth + +Reth (short for Rust Ethereum) is an Ethereum full node implementation that is focused on being user-friendly, highly modular, fast and efficient. Reth was originally built and driven forward by Paradigm, and is licensed under the Apache and MIT licenses. + +Reth is production ready, and suitable for usage in mission-critical environments such as staking or high-uptime services. Performs well in use cases where high performance with great margins is required such as RPC, MEV, indexing, simulations, and P2P activities. + +Learn more by checking out the [Reth Book](https://reth.rs/), or the [Reth GitHub repo](https://github.com/paradigmxyz/reth?tab=readme-ov-file#reth). + +### In development + +These clients are still in earlier stages of development and are not yet recommended for production use. + +#### EthereumJS + +The EthereumJS Execution Client (EthereumJS) is written in TypeScript and composed of a number of packages, including core Ethereum primitives represented by the Block, Transaction, and Merkle-Patricia Trie classes and core client components including an implementation of the Ethereum Virtual Machine (EVM), a blockchain class, and the DevP2P networking stack. + +Learn more about it by reading its [documentation](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master) + +## Consensus clients + +There are multiple consensus clients (previously known as 'Eth2' clients) to support the [consensus upgrades](/roadmap/beacon-chain/). They are responsible for all consensus-related logic including the fork-choice algorithm, processing attestations and managing [proof-of-stake](/developers/docs/consensus-mechanisms/pos) rewards and penalties. + +| Client | Language | Operating systems | Networks | +| ------------------------------------------------------------- | ---------- | --------------------- | --------------------------------------------------------- | +| [Lighthouse](https://lighthouse.sigmaprime.io/) | Rust | Linux, Windows, macOS | Beacon Chain, Holesky, Pyrmont, Sepolia, and more | +| [Lodestar](https://lodestar.chainsafe.io/) | TypeScript | Linux, Windows, macOS | Beacon Chain, Holesky, Sepolia, and more | +| [Nimbus](https://nimbus.team/) | Nim | Linux, Windows, macOS | Beacon Chain, Holesky, Sepolia, and more | +| [Prysm](https://docs.prylabs.network/docs/getting-started/) | Go | Linux, Windows, macOS | Beacon Chain, Gnosis, Holesky, Pyrmont, Sepolia, and more | +| [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) | Java | Linux, Windows, macOS | Beacon Chain, Gnosis, Holesky, Sepolia, and more | +| [Grandine](https://docs.grandine.io/) | Rust | Linux, Windows, macOS | Beacon Chain, Holesky, Sepolia, and more | + +### Lighthouse + +Lighthouse is a consensus client implementation written in Rust under the Apache-2.0 license. It is maintained by Sigma Prime and has been stable and production-ready since Beacon Chain genesis. It is relied upon by various enterprises, staking pools and individuals. It aims to be secure, performant and interoperable in a wide range of environments, from desktop PCs to sophisticated automated deployments. + +Documentation can be found in [Lighthouse Book](https://lighthouse-book.sigmaprime.io/) + +### Lodestar + +Lodestar is a production-ready consensus client implementation written in Typescript under the LGPL-3.0 license. It is maintained by ChainSafe Systems and is the newest of the consensus clients for solo-stakers, developers and researchers. Lodestar consists of a beacon node and validator client powered by JavaScript implementations of Ethereum protocols. Lodestar aims to improve Ethereum usability with light clients, expand accessibility to a larger group of developers and further contribute to ecosystem diversity. + +More information can be found on our [Lodestar website](https://lodestar.chainsafe.io/) + +### Nimbus + +Nimbus is a consensus client implementation written in Nim under the Apache-2.0 license. It is a production-ready client in use by solo-stakers and staking pools. Nimbus is designed for resource efficiency, making it easy to run on resource-restricted devices and enterprise infrastructure with equal ease, without compromising stability or reward performance. A lighter resource footprint means the client has a greater margin of safety when the network is under stress. + +Learn more in [Nimbus docs](https://nimbus.guide/) + +### Prysm + +Prysm is a full-featured, open source consensus client written in Go under the GPL-3.0 license. It features an optional webapp UI and prioritizes user experience, documentation, and configurability for both stake-at-home and institutional users. + +Visit [Prysm docs](https://docs.prylabs.network/docs/getting-started/) to learn more. + +### Teku + +Teku is one of the original Beacon Chain genesis clients. Alongside the usual goals (security, robustness, stability, usability, performance), Teku specifically aims to comply fully with all the various consensus client standards. + +Teku offers very flexible deployment options. The beacon node and validator client can be run together as a single process, which is extremely convenient for solo stakers, or nodes can be run separately for sophisticated staking operations. In addition, Teku is fully interoperable with [Web3Signer](https://github.com/ConsenSys/web3signer/) for signing key security and slashing protection. + +Teku is written in Java and is Apache 2.0 licensed. It is developed by the Protocols team at ConsenSys that is also responsible for Besu and Web3Signer. Learn more in [Teku docs](https://docs.teku.consensys.net/en/latest/). + +### Grandine + +Grandine is a consensus client implementation, written in Rust under the GPL-3.0 license. It is maintained by the Grandine Core Team and is fast, high-performance and lightweight. It fits a wide range of stakers from solo stakers running on low-resource devices such as Raspberry Pi to large institutional stakers running tens of thousands of validators. + +Documentation can be found in the [Grandine Book](https://docs.grandine.io/) + +## Synchronization modes + +To follow and verify current data in the network, the Ethereum client needs to sync with the latest network state. This is done by downloading data from peers, cryptographically verifying their integrity, and building a local blockchain database. + +Synchronization modes represent different approaches to this process with various trade-offs. Clients also vary in their implementation of sync algorithms. Always refer to the official documentation of your chosen client for specifics on implementation. + +### Execution layer sync modes + +The execution layer may be run in different modes to suit different use cases, from re-executing the blockchain's world state to only syncing with the tip of the chain from a trusted checkpoint. + +#### Full sync + +A full sync downloads all blocks (including headers and block bodies) and regenerates the state of the blockchain incrementally by executing every block from genesis. + +- Minimizes trust and offers the highest security by verifying every transaction. +- With an increasing number of transactions, it can take days to weeks to process all transactions. + +[Archive nodes](#archive-node) perform a full sync to build (and retain) a complete history of the state changes made by every transaction in every block. + +#### Fast sync + +Like a full sync, a fast sync downloads all blocks (including headers, transactions, and receipts). However, instead of re-processing the historical transactions, a fast sync relies on the receipts until it reaches a recent head, when it switches to importing and processing blocks to provide a full node. + +- Fast sync strategy. +- Reduces processing demand in favor of bandwidth usage. + +#### Snap sync + +Snap syncs also verify the chain block-by-block. However, instead of starting at the genesis block, a snap sync starts at a more recent 'trusted' checkpoint that is known to be part of the true blockchain. The node saves periodic checkpoints while deleting data older than a certain age. These snapshots are used to regenerate state data as needed, rather than storing it forever. + +- Fastest sync strategy, currently default in Ethereum Mainnet. +- Saves a lot of disk usage and network bandwidth without sacrificing security. + +[More on snap sync](https://github.com/ethereum/devp2p/blob/master/caps/snap.md). + +#### Light sync + +Light client mode downloads all block headers, block data, and verifies some randomly. Only syncs tip of the chain from the trusted checkpoint. + +- Gets only the latest state while relying on trust in developers and consensus mechanism. +- Client ready to use with current network state in a few minutes. + +**NB** Light sync does not yet work with proof-of-stake Ethereum - new versions of light sync should ship soon! + +[More on light clients](/developers/docs/nodes-and-clients/light-clients/) + +### Consensus layer sync modes + +#### Optimistic sync + +Optimistic sync is a post-merge synchronization strategy designed to be opt-in and backwards compatible, allowing execution nodes to sync via established methods. The execution engine can _optimistically_ import beacon blocks without fully verifying them, find the latest head, and then start syncing the chain with the above methods. Then, after the execution client has caught up, it will inform the consensus client of the validity of the transactions in the Beacon Chain. + +[More on optimistic sync](https://github.com/ethereum/consensus-specs/blob/dev/sync/optimistic.md) + +#### Checkpoint sync + +A checkpoint sync, also known as weak subjectivity sync, creates a superior user experience for syncing a Beacon Node. It's based on assumptions of [weak subjectivity](/developers/docs/consensus-mechanisms/pos/weak-subjectivity/) which enables syncing the Beacon Chain from a recent weak subjectivity checkpoint instead of genesis. Checkpoint syncs make the initial sync time significantly faster with similar trust assumptions as syncing from [genesis](/glossary/#genesis-block). + +In practice, this means your node connects to a remote service to download recent finalized states and continues verifying data from that point. The third party providing the data is trusted and should be picked carefully. + +More on [checkpoint sync](https://notes.ethereum.org/@djrtwo/ws-sync-in-practice) + +## Further reading + +- [Ethereum 101 - Part 2 - Understanding Nodes](https://kauri.io/ethereum-101-part-2-understanding-nodes/48d5098292fd4f11b251d1b1814f0bba/a) _– Wil Barnes, 13 February 2019_ +- [Running Ethereum Full Nodes: A Guide for the Barely Motivated](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux, 7 November 2019_ + +## Related topics + +- [Blocks](/developers/docs/blocks/) +- [Networks](/developers/docs/networks/) + +## Related tutorials + +- [Turn your Raspberry Pi 4 into a validator node just by flashing the MicroSD card – Installation guide](/developers/tutorials/run-node-raspberry-pi/) _– Flash your Raspberry Pi 4, plug in an ethernet cable, connect the SSD disk and power up the device to turn the Raspberry Pi 4 into a full Ethereum node running the execution layer (Mainnet) and / or the consensus layer (Beacon Chain / validator)._ + +--- + +## Developers > Docs > Nodes And Clients > Light Clients + +Running a full node is the most trustless, private, decentralized and censorship resistant way to interact with Ethereum. With a full node you keep your own copy of the blockchain that you can query instantly and you get direct access to Ethereum's peer-to-peer network. However, running a full node requires a significant amount of memory, storage and CPU. This means it is not feasible for everyone to run their own node. There are several solutions to this on the Ethereum roadmap, including statelessness, but they are several years away from being implemented. The answer in the near-term is to trade-off some of the benefits of running a full node for large performance improvements that allow nodes to run with very low hardware requirements. Nodes that make this trade-off are known as light nodes. + +## What is a light client + +A light node is a node running light client software. Instead of keeping local copies of the blockchain data and independently verifying all the changes, they request the necessary data from some provider instead. The provider might be a direct connection to a full node or via some centralized RPC server. The data is then verified by the light node, allowing it to keep up with the head of the chain. The light node only processes block headers, only occasionally downloading the actual block contents. Nodes can vary in their lightness, depending upon the combinations of light and full client software they run. For example, the lightest configuration would be to run a light execution client and a light consensus client. It is also likely that many nodes will choose to run light consensus clients with full execution clients, or vice versa. + +## How do light clients work? + +When Ethereum started using a proof-of-stake based consensus mechanism, new infrastructure was introduced specifically to support light clients. The way it works is by randomly selecting a subset of 512 validators every 1.1 days to act as a **sync committee**. The sync committee signs the header of recent blocks. Each block header contains the aggregated signature of the validators in the sync committee and a "bitfield" that shows which validators signed and which did not. Each header also includes a list of validators expected to participate in signing the next block. This means a light client can quickly see that the sync committee has signed off on the data they receive, and they can also check that the sync committee is the genuine one by comparing the one they receive from the one they were told to expect in the previous block. In this way, the light client can keep updating its knowledge of the latest Ethereum block without actually downloading the block itself, just the header which contains summary information. + +On the execution layer there is no single specification for a light execution client. The scope of a light execution client can vary from a "light mode" of a full execution client that has all the EVM and networking functionality of a full node but only verifies block headers, without downloading the associated data, or it can be a more stripped down client that relies heavily upon forwarding requests to an RPC provider to interact with Ethereum. + +## Why are light clients important? + +Light clients matter because they allow users to verify incoming data rather than blindly trusting that their data provider is correct and honest, while using just a tiny fraction of the computational resources of a full node. The data light clients receive can be checked against block headers that they know have been signed by at least 2/3 of a random set of 512 Ethereum validators. This is very strong evidence that the data is correct. + +The light client only uses a tiny amount of computing power, memory and storage so it can be run on a mobile phone, embedded in an app or as part of a browser. Light clients are a way to make trust-minimized access to Ethereum just as frictionless as trusting a third-party provider. + +Let's take a simple example. Imagine you want to check your account balance. To do this you have to make a request to an Ethereum node. That node will check its local copy of the Ethereum state for your balance and return it to you. If you don't have direct access to a node, there are centralized operators that provide this data as a service. You can send a request to them, they check their node, and send the result back to you. The problem with this is that you then have to trust the provider to be giving you the correct information. You can never really know the information is correct if you can't verify it for yourself. + +A light client addresses this issue. You still request data from some external provider, but when you receive the data back it comes with a proof that your light node can check against the information it received in the block header. This means Ethereum is verifying the correctness of your data instead of some trusted operator. + +## What innovations do light clients enable? + +The primary benefit of light clients is enabling more people to access Ethereum independently with negligible hardware requirements and minimal reliance on third parties. This is good for users because they can verify their own data and it is good for the network because it increases the number and diversity of nodes that are verifying the chain. + +The ability to run Ethereum nodes on devices with very small storage, memory and processing power is one of the major areas of innovation unlocked by light clients. Whereas today Ethereum nodes require a lot of computing resources, light clients could be embedded into browsers, run on mobile phones and perhaps even smaller devices such as smart watches. This means Ethereum wallets with embedded clients could run on a mobile phone. This means mobile wallets could be much more decentralized as they wouldn't have to trust centralized data providers for their data. + +An extension of this is enabling **internet of things (IoT)** devices. A light client could be used to quickly prove ownership of some token balance or NFT, with all the security guarantees provided by the sync committees, triggering some action on an IoT network. Imagine a [bicycle rental service](https://youtu.be/ZHNrAXf3RDE?t=929) that uses an app with an embedded light client to quickly verify that you own the rental service's NFT and if so, unlocks a bicycle for you to ride away on! + +Ethereum rollups would also benefit from light clients. One of the big problems for rollups has been hacks targeting the bridges that allow funds to transfer from Ethereum Mainnet to a rollup. One vulnerability is the oracles that rollups use to detect that a user has made a deposit into the bridge. If an oracle feeds bad data, they could trick the rollup into thinking there was a deposit to the bridge and to incorrectly release funds. A light client embedded in the rollup could be used to protect against corrupted oracles because the deposit into the bridge could come with a proof that can be verified by the rollup before releasing any tokens. The same concept could also be applied to other interchain bridges. + +Light clients could also be used to upgrade Ethereum wallets. Instead of trusting data provided from an RPC provider, your wallet could directly verify the data being presented to you using an embedded light client. This would add security to your wallet. If your RPC provider was dishonest and provided you with incorrect data, the embedded light client could tell you! + +## What is the current state of light client development? + +There are several light clients in development, including execution, consensus and combined execution/consensus light clients. These are the light client implementations we know of at the time of writing this page: + +- [Lodestar](https://github.com/ChainSafe/lodestar/tree/unstable/packages/light-client): consensus light client in TypeScript +- [Helios](https://github.com/a16z/helios): combined execution and consensus light client in Rust +- [Geth](https://github.com/ethereum/go-ethereum/tree/master/beacon/light): light mode for execution client (in development) in Go +- [Nimbus](https://nimbus.guide/el-light-client.html): consensus light client in Nim + +To our knowledge none of these are considered production-ready yet. + +There is also a lot of work being done to improve the ways that light clients can access Ethereum data. Currently, light clients rely on RPC requests to full nodes using a client/server model, but in the future the data could be requested in a more decentralized way using a dedicated network such as the [Portal Network](https://www.ethportal.net/) that could serve the data to light clients using a peer-to-peer gossip protocol. + +Other [roadmap](/roadmap/) items such as [Verkle trees](/roadmap/verkle-trees/) and [statelessness](/roadmap/statelessness/) will eventually bring the security guarantees of light clients equal to those of full clients. + +## Further reading + +- [Zsolt Felfodhi on Geth light clients](https://www.youtube.com/watch?v=EPZeFXau-RE) +- [Etan Kissling on light client networking](https://www.youtube.com/watch?v=85MeiMA4dD8) +- [Etan Kissling on light clients after The Merge](https://www.youtube.com/watch?v=ZHNrAXf3RDE) +- [Piper Merriam: The winding road to functional light clients](https://snakecharmers.ethereum.org/the-winding-road-to-functional-light-clients/) + +--- + +## Developers > Docs > Nodes And Clients > Node Architecture + +An Ethereum node is composed of two clients: an [execution client](/developers/docs/nodes-and-clients/#execution-clients) and a [consensus client](/developers/docs/nodes-and-clients/#consensus-clients). For a node to propose a new block, it must also run a [validator client](#validators). + +When Ethereum was using [proof-of-work](/developers/docs/consensus-mechanisms/pow/), an execution client was enough to run a full Ethereum node. However, since implementing [proof-of-stake](/developers/docs/consensus-mechanisms/pow/), the execution client must be used alongside another piece of software called a [consensus client](/developers/docs/nodes-and-clients/#consensus-clients). + +The diagram below shows the relationship between the two Ethereum clients. The two clients connect to their own respective peer-to-peer (P2P) networks. Separate P2P networks are needed as the execution clients gossip transactions over their P2P network, enabling them to manage their local transaction pool, whilst the consensus clients gossip blocks over their P2P network, enabling consensus and chain growth. + +![](node-architecture-text-background.png) + +_There are several options for the execution client including Erigon, Nethermind, and Besu_. + +For this two-client structure to work, consensus clients must pass bundles of transactions to the execution client. The execution client executes the transactions locally to validate that the transactions do not violate any Ethereum rules and that the proposed update to Ethereum’s state is correct. When a node is selected to be a block producer its consensus client instance requests bundles of transactions from the execution client to include in the new block and execute them to update the global state. The consensus client drives the execution client via a local RPC connection using the [Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md). + +## What does the execution client do? + +The execution client is responsible for transaction validation, handling, and gossip, along with state management and supporting the Ethereum Virtual Machine ([EVM](/developers/docs/evm/)). It is **not** responsible for block building, block gossiping or handling consensus logic. These are in the remit of the consensus client. + +The execution client creates execution payloads - the list of transactions, updated state trie, and other execution-related data. Consensus clients include the execution payload in every block. The execution client is also responsible for re-executing transactions in new blocks to ensure they are valid. Executing transactions is done on the execution client's embedded computer, known as the [Ethereum Virtual Machine (EVM)](/developers/docs/evm). + +The execution client also offers a user interface to Ethereum through [RPC methods](/developers/docs/apis/json-rpc) that enable users to query the Ethereum blockchain, submit transactions and deploy smart contracts. It's common for RPC calls to be handled by a library like [Web3js](https://docs.web3js.org/), [Web3py](https://web3py.readthedocs.io/en/v5/), or by a user-interface such as a browser wallet. + +In summary, the execution client is: + +- a user gateway to Ethereum +- home to the Ethereum Virtual Machine, Ethereum's state and transaction pool. + +## What does the consensus client do? + +The consensus client deals with all the logic that enables a node to stay in sync with the Ethereum network. This includes receiving blocks from peers and running a fork choice algorithm to ensure the node always follows the chain with the greatest accumulation of attestations (weighted by validator effective balances). Similar to the execution client, consensus clients have their own P2P network through which they share blocks and attestations. + +The consensus client does not participate in attesting to or proposing blocks - this is done by a validator, an optional add-on to a consensus client. A consensus client without a validator only keeps up with the head of the chain, allowing the node to stay synced. This enables a user to transact with Ethereum using their execution client, confident that they are on the correct chain. + +## Validators + +Staking and running the validator software makes a node eligible to be selected to propose a new block. Node operators can add a validator to their consensus clients by depositing 32 ETH in the deposit contract. The validator client comes bundled with the consensus client and can be added to a node at any time. The validator handles attestations and block proposals. It also enables a node to accrue rewards or lose ETH via penalties or slashing. + +[More on staking](/staking/). + +## Components of a node comparison + +| Execution Client | Consensus Client | Validator | +| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | +| Gossips transactions over its P2P network | Gossips blocks and attestations over its P2P network | Proposes blocks | +| Executes/re-executes transactions | Runs the fork choice algorithm | Accrues rewards/penalties | +| Verifies incoming state changes | Keeps track of the head of the chain | Makes attestations | +| Manages state and receipts tries | Manages the Beacon state (contains consensus and execution info) | Requires 32 ETH to be staked | +| Creates execution payload | Keeps track of accumulated randomness in RANDAO (an algorithm that provides verifiable randomness for validator selection and other consensus operations) | Can be slashed | +| Exposes JSON-RPC API for interacting with Ethereum | Keeps track of justification and finalization | | + +## Further reading + +- [Proof-of-stake](/developers/docs/consensus-mechanisms/pos) +- [Block proposal](/developers/docs/consensus-mechanisms/pos/block-proposal) +- [Validator rewards and penalties](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) + +--- + +## Developers > Docs > Nodes And Clients > Nodes As A Service + +## Introduction + +Running your own [Ethereum node](/developers/docs/nodes-and-clients/#what-are-nodes-and-clients) can be challenging, especially when getting started or while scaling fast. There are a [number of services](#popular-node-services) that run optimized node infrastructures for you, so you can focus on developing your application or product instead. We'll explain how node services work, the pros and cons for using them and list providers if you are interested in getting started. + +## Prerequisites + +If you don't already have an understanding of what nodes and clients are, check out [Nodes and clients](/developers/docs/nodes-and-clients/). + +## Stakers + +Solo stakers must run their own infrastructure rather than relying on third-party providers. This means running an execution client coupled with a consensus client. Before [The Merge](/roadmap/merge), it was possible to run a consensus client only and use a centralized provider for execution data; this is no longer possible - a solo staker must run both clients. However, there are services available to ease this process. + +[Read more on running a node](/developers/docs/nodes-and-clients/run-a-node/). + +The services described on this page are for non-staking nodes. + +## How do node services work? + +Node service providers run distributed node clients behind the scenes for you, so you don't have to. + +These services typically provide an API key that you can use to write to and read from the blockchain. They often include access to [Ethereum testnets](/developers/docs/networks/#ethereum-testnets) in addition to Mainnet. + +Some services offer you your own dedicated node that they manage for you, while others use load balancers to distribute activity across nodes. + +Almost all node services are extremely easy to integrate with, involving one line changes in your code to swap out your self hosted node, or even switch between the services themselves. + +Often times node services will run a variety of [node clients](/developers/docs/nodes-and-clients/#execution-clients) and [types](/developers/docs/nodes-and-clients/#node-types), allowing you to access full and archive nodes in addition to client specific methods in one API. + +It's important to note that node services do not and should not store your private keys or information. + +## What are the benefits of using a node service? + +The main benefit for using a node service is not having to spend engineering time maintaining and managing nodes yourself. This allows you to focus on building your product rather than having to worry about infrastructure maintenance. + +Running your own nodes can be very expensive from storage to bandwidth to valuable engineering time. Things like spinning up more nodes when scaling, upgrading nodes to the latest versions, and ensuring state consistency, can distract from building and spending resources on your desired web3 product. + +## What are the cons of using a Node Service? + +By using a node service you are centralizing the infrastructure aspect of your product. For this reason, projects that hold decentralization to the upmost importance might prefer self-hosting nodes rather than outsourcing to a 3rd party. + +Read more about the [benefits of running your own node](/developers/docs/nodes-and-clients/#benefits-to-you). + +## Popular node services + +Here is a list of some of the most popular Ethereum node providers, feel free to add any that are missing! Each node service offers different benefits and features in addition to free or paid tiers, you should investigate which ones best suit your needs prior to making a decision. + +- [**Alchemy**](https://alchemy.com/) + - [Docs](https://docs.alchemyapi.io/) + - Features + - Largest free tier with 300M compute units per month (~30M getLatestBlock requests) + - Multichain support for Polygon, Starknet, Optimism, Arbitrum + - Powering ~70% of the largest Ethereum dapps and DeFi transaction volume + - Real-time webhook alerts via Alchemy Notify + - Best-in-class support and reliability / stability + - Alchemy's NFT API + - Dashboard with Request Explorer, Mempool Watcher, and Composer + - Integrated testnet faucet access + - Active Discord builder community with 18k users + +- [**Allnodes**](https://www.allnodes.com/) + - [Docs](https://docs.allnodes.com/) + - Features + - No rate limits with PublicNode token created on the Allnodes portfolio page. + - Privacy focused free rpc endpoints (100+ blockchains) on [PublicNode](https://www.publicnode.com) + - Dedicated nodes without rate limits for 90+ blockchains + - Dedicated archive nodes for 30+ blockchains + - Available in 3 regions (US, EU, Asia) + - Snapshots for 100+ blockchains on [PublicNode](https://www.publicnode.com/snapshots) + - 24/7 technical support with 99.90%-99.98% uptime SLA (depends on plan). + - Pay-per-hour pricing + - Pay with Credit Card, PayPal or Crypto + +- [**All That Node**](https://allthatnode.com/) + - [Docs](https://docs.allthatnode.com/) + - Features + - 50,000 requests per day with free tier + - Support for over 40 protocols + - JSON-RPC (EVM, Tendermint), REST, and Websocket APIs supported + - Unlimited access to archive date + - 24/7 technical support and 99.9% over uptime + - Faucet available on multi chains + - Unlimited endpoint access with an limitless number of API keys + - Trace/Debug API supported + - Automated updates + +- [**Amazon Managed Blockchain**](https://aws.amazon.com/managed-blockchain/) + - [Docs](https://aws.amazon.com/managed-blockchain/resources/) + - Features + - Fully managed Ethereum nodes + - Available in six regions + - JSON-RPC over HTTP and secure WebSockets + - Supports 3 chains + - SLAs, AWS Support 24/7 + - Go-ethereum and Lighthouse + +- [**Ankr**](https://www.ankr.com/) + - [Docs](https://docs.ankr.com/) + - Features + - Ankr Protocol - open access to Public RPC API endpoints for 8+ chains + - Load balancing and node health monitoring for a fast and reliable gateway to the nearest available node + - Premium tier enabling WSS endpoint and uncapped rate limit + - One-click full node and validator node deployment for 40+ chains + - Scale as you go + - Analytics tools + - Dashboard + - RPC, HTTPS and WSS endpoints + - Direct support + +- [**Blast**](https://blastapi.io/) + - [Docs](https://docs.blastapi.io/) + - Features + - RPC and WSS support + - Multi-region node hosting + - Decentralized infrastructure + - Public API + - Dedicated Free Plan + - Multichain support (17+ blockchains) + - Archive Nodes + - 24/7 Discord Support + - 24/7 Monitoring and alerts + - An overall SLA of 99.9% + - Pay in crypto + +- [**BlockDaemon**](https://blockdaemon.com/) + - [Docs](https://ubiquity.docs.blockdaemon.com/) + - Benefits + - Dashboard + - Per node basis + - Analytics + +- [**BlockPI**](https://blockpi.io/) + - [Docs](https://docs.blockpi.io/) + - Features + - Robust & distributed node structure + - Up to 40 HTTPS and WSS endpoints + - Free signup package and monthly package + - Trace method + Archive data support + - Packages up to 90 days validity + - Custom plan and pay as you go payment + - Pay in crypto + - Direct support & Technical support + +- [**Chainbase**](https://www.chainbase.com/) + - [Docs](https://docs.chainbase.com) + - Features + - Highly available, fast, and scalable RPC service + - Multi-chain support + - Free tariffs + - User-friendly dashboard + - Provides blockchain data services beyond RPC + +- [**Chainstack**](https://chainstack.com/) + - [Docs](https://docs.chainstack.com/) + - Features + - Free shared nodes + - Shared archive nodes + - GraphQL support + - RPC and WSS endpoints + - Dedicated full and archive nodes + - Fast sync time for dedicated deployments + - Bring your cloud + - Pay-per-hour pricing + - Direct 24/7 support + +- [**DataHub**](https://datahub.figment.io) + - [Docs](https://docs.figment.io/) + - Features + - Free tier option with 3,000,000 reqs/month + - RPC and WSS endpoints + - Dedicated full and archive nodes + - Auto-Scaling (Volume Discounts) + - Free archival data + - Service Analytics + - Dashboard + - Direct 24/7 Support + - Pay in Crypto (Enterprise) + +- [**DRPC**](https://drpc.org/) + - [Docs](https://docs.drpc.org/) + - Features + - Decentralized RPC nodes + - 15+ Node providers + - Node balancing + - Unlimited compute units per month on the free tier + - Data verification + - Custom endpoints + - HTTP and WSS endpoints + - Unlimited keys (free and paid tier) + - Flexible fallback options + - [Public Endpoint](https://eth.drpc.org) + - Free shared archive nodes + +- [**GetBlock**](https://getblock.io/) + - [Docs](https://getblock.io/docs/get-started/authentication-with-api-key/) + - Features + - Access to 40+ blockchain nodes + - 40K free daily requests + - Unlimited number of API keys + - High connection speed at 1GB/sec + - Trace+Archive + - Advanced analytics + - Automated updates + - Technical support + +- [**InfStones**](https://infstones.com/) + - Features + - Free tier option + - Scale as you go + - Analytics + - Dashboard + - Unique API endpoints + - Dedicated full nodes + - Fast sync time for dedicated deployments + - Direct 24/7 support + - Access to 50+ blockchain nodes + +- [**Infura**](https://infura.io/) + - [Docs](https://infura.io/docs) + - Features + - Free tier option + - Scale as you go + - Paid archival data + - Direct Support + - Dashboard + +- [**Kaleido**](https://kaleido.io/) + - [Docs](https://docs.kaleido.io/) + - Features + - Free startier tier + - One-click Ethereum node deployment + - Customizable clients and algorithms (Geth, Quorum & Besu || PoA, IBFT & Raft) + - 500+ administrative and service APIs + - RESTful interface for Ethereum transaction submission (Apache Kafka backed) + - Outbound streams for event delivery (Apache Kafka backed) + - Deep collection of "offchain" and ancillary services (e.g. bilateral encrypted messaging transport) + - Straightforward network onboarding with governance and role-based access control + - Sophisticated user management for both administrators and end users + - Highly scalable, resilient, enterprise-grade infrastructure + - Cloud HSM private key management + - Ethereum Mainnet Tethering + - ISO 27k and SOC 2, Type 2 certifications + - Dynamic runtime configuration (e.g. adding cloud integrations, altering node ingresses, etc.) + - Support for multi-cloud, multi-region and hybrid deployment orchestrations + - Simple hourly SaaS-based pricing + - SLAs and 24x7 support + +- [**Lava Network**](https://www.lavanet.xyz/) + - [Docs](https://docs.lavanet.xyz/) + - Features + - Free Testnet Use + - Decentralized Redundancy for High Uptime + - Open-source + - Fully Decentralized SDK + - Ethers.js Integration + - Intuitive Project Management Interface + - Consensus-Based Data Integrity + - Multi-chain Support + +- [**Moralis**](https://moralis.io/) + - [Docs](https://docs.moralis.io/) + - Features + - Free shared nodes + - Free shared archive nodes + - Privacy focused (no logs policy) + - Cross chain support + - Scale as you go + - Dashboard + - Unique Ethereum SDK + - Unique API endpoints + - Direct, technical support + +- [**NodeReal MegaNode**](https://nodereal.io/) + - [Docs](https://docs.nodereal.io/docs/introduction) + - Features + - Reliable, fast and scalable RPC API services + - Enhanced API for web3 developers + - Multi-chain support + - Get started for free + +- [**NOWNodes**](https://nownodes.io/) + - [Docs](https://documenter.getpostman.com/view/13630829/TVmFkLwy) + - Features + - Access to 50+ blockchain nodes + - Free API Key + - Block Explorers + - API Response Time ⩽ 1 sec + - 24/7 Support Team + - Personal Account Manager + - Shared, archive, backup and dedicated nodes + +- [**Pocket Network**](https://www.pokt.network/) + - [Docs](https://docs.pokt.network/home/) + - Features + - Decentralized RPC Protocol and Marketplace + - 1M Requests Per Day Free Tier (per endpoint, max 2) + - [Public Endpoints](https://docs.pokt.network/developers/public-endpoints) + - Pre-Stake+ Program (if you need more than 1M requests per day) + - 15+ Blockchains Supported + - 6400+ Nodes earning POKT for serving applications + - Archival Node, Archival Node w/ Tracing, & Testnet Node Support + - Ethereum Mainnet Node Client Diversity + - No Single Point of Failure + - Zero Downtime + - Cost-Effective Near-Zero Tokenomics (stake POKT once for network bandwidth) + - No monthly sunk costs, turn your infrastructure into an asset + - Load-Balancing built into the Protocol + - Infinitely scale the number of requests per day and nodes per hour as you go + - The most private, censorship-resistant option + - Hands-on developer support + - [Pocket Portal](https://bit.ly/ETHorg_POKTportal) dashboard and analytics + +- [**QuickNode**](https://www.quicknode.com) + - [Docs](https://www.quicknode.com/docs/) + - Features + - 24/7 technical support & dev Discord community + - Geo-balanced, multi cloud/metal, low-latency network + - Multichain support (Optimism, Arbitrum, Polygon + 11 others) + - Middle-layers for speed & stability (call routing, cache, indexing) + - Smart-Contract monitoring via Webhooks + - Intuitive dashboard, analytics suite, RPC composer + - Advanced security features (JWT, masking, whitelisting) + - NFT data and analytics API + - [SOC2 Certified](https://www.quicknode.com/security) + - Suitable for Developers to Enterprises + +- [**Rivet**](https://rivet.cloud/) + - [Docs](https://rivet.readthedocs.io/en/latest/) + - Features + - Free tier option + - Scale as you go + +- [**SenseiNode**](https://senseinode.com) + - [Docs](https://docs.senseinode.com/) + - Features + - Dedicated and Share nodes + - Dashboard + - Hosting off AWS on multiple hosting providers across different locations in Latin America + - Prysm and Lighthouse clients + +- [**SettleMint**](https://console.settlemint.com/) + - [Docs](https://docs.settlemint.com/) + - Features + - Free trial + - Scale as you go + - GraphQL support + - RPC and WSS endpoints + - Dedicated full nodes + - Bring your cloud + - Analytics tools + - Dashboard + - Pay-per-hour pricing + - Direct support + +- [**Tenderly**](https://tenderly.co/web3-gateway) + - [Docs](https://docs.tenderly.co/web3-gateway/web3-gateway) + - Features + - Free tier including 25 million Tenderly Units per month + - Free access to historical data + - Up to 8x faster read-heavy workloads + - 100% consistent read access + - JSON-RPC endpoints + - UI-based RPC request builder and request preview + - Tightly integrated with Tenderly’s development, debugging, and testing tools + - Transaction simulations + - Usage analytics and filtering + - Easy access key management + - Dedicated engineering support via chat, email, and Discord + +- [**Tokenview**](https://services.tokenview.io/) + - [Docs](https://services.tokenview.io/docs?type=nodeService) + - Features + - 24/7 technical support & Dev Telegram community + - Multichain support (Bitcoin, Ethereum, Tron, BNB Smart Chain, Ethereum Classic) + - Both RPC and WSS endpoints are open to use + - Unlimited access to archive data API + - Dashboard with Request Explorer and Mempool Watcher + - NFT data API and Webhook notify + - Pay in Crypto + - External support for extra behavior requirements + +- [**Watchdata**](https://watchdata.io/) + - [Docs](https://docs.watchdata.io/) + - Features + - Data reliability + - Uninterrupted connection with no downtime + - Process automation + - Free tariffs + - High limits that suit any user + - Support for various nodes + - Resource scaling + - High processing speeds + +- [**ZMOK**](https://zmok.io/) + - [Docs](https://docs.zmok.io/) + - Features + - Front-running as a service + - Global transactions mempool with search/filtering methods + - Unlimited TX fee and infinite Gas for sending transactions + - Fastest getting of the new block and reading of the blockchain + - The best price per API call guarantee + +- [**Zeeve**](https://www.zeeve.io/) + - [Docs](https://www.zeeve.io/docs/) + - Features + - Enterprise-grade no-code automation platform providing deployment, monitoring and management of Blockchain nodes and networks + - 30+ Supported Protocols & Integrations, and adding more + - Value added web3 infrastructure services like decentralized storage, decentralized identity and Blockchain Ledger data APIs for real-world use cases + - 24/7 support and proactive monitoring ensure the health of nodes all the time. + - RPC endpoints offer authenticated access to APIs, hassle-free management with intuitive dashboard and analytics. + - Provides both managed cloud and bring your own cloud options to choose from and supports all major cloud providers like AWS, Azure, Google Cloud, Digital Ocean and on-premise. + - We use intelligent routing to hit the node closest to your user every time + + +## Further reading + +- [List of Ethereum node services](https://ethereumnodes.com/) + +## Related topics + +- [Nodes and clients](/developers/docs/nodes-and-clients/) + +## Related tutorials + +- [Getting started with Ethereum development using Alchemy](/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/) +- [Guide to sending transactions using web3 and Alchemy](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) + +--- + +## Developers > Docs > Nodes And Clients > Run A Node + +Running your own node provides you various benefits, opens new possibilities, and helps to support the ecosystem. This page will guide you through spinning up your own node and taking part in validating Ethereum transactions. + +Note that after [The Merge](/roadmap/merge), two clients are required to run an Ethereum node; an **execution layer (EL)** client and a **consensus layer (CL)** client. This page will show how to install, configure and connect these two clients to run an Ethereum node. + +## Prerequisites + +You should understand what an Ethereum node is and why you might want to run a client. This is covered in [Nodes and clients](/developers/docs/nodes-and-clients/). + +If you're new to the topic of running a node, or looking for a less technical path, we recommend first checking out our user-friendly introduction on [running an Ethereum node](/run-a-node). + +## Choosing an approach + +The first step in spinning up your node is choosing your approach. Based on requirements and various possibilities, you must select the client implementation (of both execution and consensus clients), the environment (hardware, system), and the parameters for client settings. + +This page will guide you through these decisions and help you find the most suitable way to run your Ethereum instance. + +To choose from client implementations, see all the available Mainnet ready [execution clients](/developers/docs/nodes-and-clients/#execution-clients), [consensus clients](/developers/docs/nodes-and-clients/#consensus-clients) and learn about [client diversity](/developers/docs/nodes-and-clients/client-diversity). + +Decide whether to run the software on your own [hardware or in the cloud](#local-vs-cloud), considering clients' [requirements](#requirements). + +After preparing the environment, install the chosen clients either with [beginner-friendly interface](#automatized-setup) or [manually](#manual-setup) using a terminal with advanced options. + +When the node is running and syncing, you are ready to [use it](#using-the-node), but make sure to keep an eye on its [maintenance](#operating-the-node). + +![Client setup](./diagram.png) + +### Environment and hardware + +#### Local or cloud + +Ethereum clients are able to run on consumer grade computers and don't require any special hardware, like mining machines for example. Therefore, you have various options for deploying the node based on your needs. +To simplify, let's think about running a node on both a local physical machine and a cloud server: + +- Cloud + - Providers offer high server uptime and static public IP addresses + - Getting dedicated or virtual server can be more comfortable than building your own + - Trade off is trusting a third party - server provider + - Because of the required storage size for full node, the price of a rented server might get high +- Own hardware + - More trustless and sovereign approach + - One time investment + - An option to buy preconfigured machines + - You have to physically prepare, maintain, and potentially troubleshoot the machine and networking + +Both options have different advantages summed up above. If you are looking for a cloud solution, in addition to many traditional cloud computing providers, there are also services focused on deploying nodes. Check out [nodes as a service](/developers/docs/nodes-and-clients/nodes-as-a-service/) for more options on hosted nodes. + +#### Hardware + +However, a censorship-resistant, decentralized network should not rely on cloud providers. Instead, running your node on your own local hardware is healthier for the ecosystem. [Estimations](https://www.ethernodes.org/networkType/Hosting) show a large share of nodes run on the cloud, which could become a single point of failure. + +Ethereum clients can run on your computer, laptop, server, or even a single-board computer. While running clients on your personal computer is possible, having a dedicated machine just for your node can significantly enhance its performance and security while minimizing the impact on your primary computer. + +Using your own hardware can be very easy. There are many simple options as well as advanced setups for more technical people. So let's look into the requirements and means for running Ethereum clients on your machine. + +#### Requirements + +Hardware requirements differ by client but generally are not that high since the node just needs to stay synced. Don't confuse it with mining, which requires much more computing power. Sync time and performance do improve with more powerful hardware however. + +Before installing any client, please ensure your computer has enough resources to run it. You can find the minimum and recommended requirements below. + +The bottleneck for your hardware is mostly disk space. Syncing the Ethereum blockchain is very input/output intensive and requires a lot of space. It is best to have a **solid-state drive (SSD)** with hundreds of GBs of free space to spare even after the synchronization. + +The size of the database and speed of the initial synchronization depends on the chosen client, its configuration and [sync strategy](/developers/docs/nodes-and-clients/#sync-modes). + +Also make sure your internet connection is not limited by a [bandwidth cap](https://wikipedia.org/wiki/Data_cap). It's recommended to use an unmetered connection since initial sync and data broadcasted to the network could exceed your limit. + +##### Operating system + +All clients support major operating systems - Linux, MacOS, Windows. This means you can run nodes on regular desktop or server machines with the operating system (OS) that suits you the best. Make sure your OS is up to date to avoid potential issues and security vulnerabilities. + +##### Minimum requirements + +- CPU with 2+ cores +- 8 GB RAM +- 2TB SSD +- 10+ MBit/s bandwidth + +##### Recommended specifications + +- Fast CPU with 4+ cores +- 16 GB+ RAM +- Fast SSD with 2+TB +- 25+ MBit/s bandwidth + +The sync mode and client you choose will affect space requirements, but we've estimated the disk space you'll need for each client below. + +| Client | Disk size (snap sync) | Disk size (full archive) | +| ---------- | --------------------- | ------------------------ | +| Besu | 800GB+ | 12TB+ | +| Erigon | N/A | 2.5TB+ | +| Geth | 500GB+ | 12TB+ | +| Nethermind | 500GB+ | 12TB+ | +| Reth | N/A | 2.2TB+ | + +- Note: Erigon and Reth do not offer snap sync, but Full Pruning is possible (~2TB for Erigon, ~1.2TB for Reth) + +For consensus clients, space requirement also depends on client implementation and enabled features (e.g. validator slasher) but generally count with another 200GB needed for beacon data. With a large number of validators, the bandwidth load grows as well. You can find [details on consensus client requirements in this analysis](https://mirror.xyz/0x934e6B4D7eee305F8C9C42b46D6EEA09CcFd5EDc/b69LBy8p5UhcGJqUAmT22dpvdkU-Pulg2inrhoS9Mbc). + +#### Plug-and-play solutions + +The easiest option for running a node with your own hardware is using plug-and-play boxes. Preconfigured machines from vendors offer the most straightforward experience: order, connect, run. Everything is preconfigured and runs automatically with an intuitive guide and dashboard for monitoring and controlling the software. + +- [DappNode](https://dappnode.io/) +- [Avado](https://ava.do/) + +#### Ethereum on a single-board computer + +An easy and cheap way of running an Ethereum node is to use a single board computer, even with an ARM architecture like the Raspberry Pi. [Ethereum on ARM](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/) provides easy-to-run images of multiple execution and consensus client for Raspberry Pi and other ARM boards. + +Small, affordable and efficient devices like these are ideal for running a node at home but keep in mind their limited performance. + +## Spinning up the node + +The actual client setup can be done either with automated launchers or manually, setting up client software directly. + +For less advanced users, the recommended approach is to use a launcher, software that guides you through the installation and automates the client setup process. However, if you have some experience of using a terminal, the steps for manual setup should be simple to follow. + +### Guided setup + +Multiple user-friendly projects aim to improve the experience of setting up a client. These launchers provide automatic client installation and configuration, with some even offering a graphical interface for guided setup and monitoring of clients. + +Below are a few projects which can help you install and control clients just with a few clicks: + +- [DappNode](https://docs.dappnode.io/docs/user/getting-started/choose-your-path) - DappNode doesn't come only with a machine from a vendor. The software, the actual node launcher and control center with many features can be used on arbitrary hardware. +- [EthPillar](https://www.coincashew.com/coins/overview-eth/ethpillar) - Quickest and easiest way to setup a full node. One-liner setup tool and node management TUI. Free. Open source. Public goods for Ethereum by solo stakers. ARM64 and AMD64 support. +- [eth-docker](https://eth-docker.net/) - Automated setup using Docker focused on easy and secure staking, requires basic terminal and Docker knowledge, recommended for a bit more advanced users. +- [Stereum](https://stereum.net/ethereum-node-setup/) - Launcher for installing clients on a remote server via SSH connection with a GUI setup guide, control center, and many other features. +- [NiceNode](https://www.nicenode.xyz/) - Launcher with a straightforward user experience to run a node on your computer. Just choose clients and start them with a few clicks. Still in development. +- [Sedge](https://docs.sedge.nethermind.io/docs/intro) - Node setup tool which automatically generates a Docker configuration using CLI wizard. Written in Go by Nethermind. + +### Manual clients setup + +The other option is to download, verify, and configure the client software manually. Even if some clients offer a graphical interface, a manual setup still requires basic skills with the terminal but offers much more versatility. + +As explained before, setting up your own Ethereum node will require running a pair of consensus and execution clients. Some clients might include a light client of the other kind and sync without any other software needed. However, full trustless verification requires both implementations. + +#### Getting the client software + +First, you need to obtain your preferred [execution client](/developers/docs/nodes-and-clients/#execution-clients) and [consensus client](/developers/docs/nodes-and-clients/#consensus-clients) software. + +You can simply download an executable application or installation package that suits your operating system and architecture. Always verify the signatures and checksums of downloaded packages. Some clients also offer repositories or Docker images for easier installation and updates. All of the clients are open source, so you can also build them from source. This is a more advanced method, but in some cases, it might be required. + +Instructions for installing each client are provided in the documentation linked in the client lists above. + +Here are the release pages of clients where you can find their pre-built binaries or instructions on installation: + +##### Execution clients + +- [Besu](https://github.com/hyperledger/besu/releases) +- [Erigon](https://github.com/ledgerwatch/erigon/releases) +- [Geth](https://geth.ethereum.org/downloads/) +- [Nethermind](https://downloads.nethermind.io/) +- [Reth](https://reth.rs/installation/installation.html) + +It is also worth noting that client diversity is an [issue on the execution layer](/developers/docs/nodes-and-clients/client-diversity/#execution-layer). It is recommended that readers consider running a minority execution client. + +##### Consensus clients + +- [Lighthouse](https://github.com/sigp/lighthouse/releases/latest) +- [Lodestar](https://chainsafe.github.io/lodestar/run/getting-started/installation#build-from-source/) (Doesn't provide a pre-built binary, only a Docker image or to be build from source) +- [Nimbus](https://github.com/status-im/nimbus-eth2/releases/latest) +- [Prysm](https://github.com/prysmaticlabs/prysm/releases/latest) +- [Teku](https://github.com/ConsenSys/teku/releases) + +[Client diversity](/developers/docs/nodes-and-clients/client-diversity/) is critical for consensus nodes running validators. If the majority of validators are running a single client implementation, network security is at risk. It is therefore recommended to consider choosing a minority client. + +[See the latest network client usage](https://clientdiversity.org/) and learn more about [client diversity](/developers/docs/nodes-and-clients/client-diversity). + +##### Verifying the software + +When downloading software from the internet, it's recommended to verify its integrity. This step is optional but especially with crucial infrastructure piece like the Ethereum client, it's important to be aware of potential attack vectors and avoid them. If you downloaded a pre-built binary, you need to trust it and risk that an attacker could swap the executable for a malicious one. + +Developers sign released binaries with their PGP keys so you can cryptographically verify you are running exactly the software they created. You just need to obtain public keys used by developers, which can be found on client release pages or in documentation. After downloading the client release and its signature, you can use a PGP implementation, e.g. [GnuPG](https://gnupg.org/download/index.html) to easily verify them. Check out a tutorial on verifying open-source software using `gpg` on [linux](https://www.tecmint.com/verify-pgp-signature-downloaded-software/) or [Windows/MacOS](https://freedom.press/training/verifying-open-source-software/). + +Another form of verification is to make sure that the hash, a unique cryptographic fingerprint, of the software you downloaded matches the one provided by developers. This is even easier than using PGP, and some clients offer only this option. Just run the hash function on the downloaded software and compare it to the one from the release page. For example: + +```sh +sha256sum teku-22.6.1.tar.gz + +9b2f8c1f8d4dab0404ce70ea314ff4b3c77e9d27aff9d1e4c1933a5439767dde +``` + +#### Client setup + +After installing, downloading, or compiling the client software, you are ready to run it. This only means it has to be executed with the proper configuration. Clients offer rich configuration options, which can enable various features. + +Let's start with options that can significantly influence client performance and data usage. [Sync modes](/developers/docs/nodes-and-clients/#sync-modes) represent different methods of downloading and validating blockchain data. Before starting the node, you should decide what network and sync mode to use. The most important things to consider are the disk space, and sync time the client will need. Pay attention to the client's docs to determine which sync mode is the default. If that doesn't suit you, pick another one based on the level of security, available data, and cost. Apart from the synchronization algorithm, you can also set pruning of different kinds of old data. Pruning enables deleting outdated data, e.g. removing state trie nodes that are unreachable from recent blocks. + +Other basic configuration options are, e.g. choosing a network - Mainnet or testnets, enabling HTTP endpoint for RPC or WebSockets, etc. You can find all features and options in the client's documentation. Various client configurations can be set by executing the client with the corresponding flags directly in the CLI or config file. Each client is a bit different; please always refer to its official documentation or help page for details on config options. + +For testing purposes, you might prefer to run a client on one of the testnet networks. [See overview of supported networks](/developers/docs/nodes-and-clients/#execution-clients). + +Examples of running execution clients with basic configuration can be found in next section. + +#### Starting the execution client + +Before starting the Ethereum client software, perform a last check that your environment is ready. For example, make sure: + +- There is enough disk space considering the chosen network and sync mode. +- Memory and CPU is not halted by other programs. +- Operating system is updated to the latest version. +- System has the correct time and date. +- Your router and firewall accept connections on listening ports. By default Ethereum clients use a listener (TCP) port and a discovery (UDP) port, both on 30303 by default. + +Run your client on a testnet first to help make sure everything is working correctly. + +You need to declare any client settings that aren't default at the start. You can use flags or the config file to declare your preferred configuration. Set of features and config syntax of each client differs. Check out your client's documentation for the specifics. + +Execution and consensus clients communicate via an authenticated endpoint specified in [Engine API](https://github.com/ethereum/execution-apis/tree/main/src/engine). In order to connect to a consensus client, the execution client must generate a [`jwtsecret`](https://jwt.io/) at a known path. For security and stability reasons, clients should run on the same machine, and both clients must know this path as it is used to authenticate a local RPC connection between them. The execution client must also define a listening port for authenticated APIs. + +This token is generated automatically by the client software, but in some cases, you might need to do it yourself. You can generate it using [OpenSSL](https://www.openssl.org/): + +```sh +openssl rand -hex 32 > jwtsecret +``` + +#### Running an execution client + +This section will guide you through starting execution clients. It only serves as an example of a basic configuration, which will start the client with these settings: + +- Specifies network to connect to, Mainnet in our examples + - You can instead choose [one of testnets](/developers/docs/networks/) for preliminary testing of your setup +- Defines data directory, where all the data including blockchain will be stored + - Make sure to substitute the path with a real one, e.g. pointing to your external drive +- Enables interfaces for communicating with the client + - Including JSON-RPC and Engine API for communication with consensus client +- Defines path to `jwtsecret` for authenticated API + - Make sure to substitute the example path with a real one which can be accessed by clients, e.g. `/tmp/jwtsecret` + +Please keep in mind that this is just a basic example, all other settings will be set to default. Pay attention to the documentation of each client to learn about default values, settings, and features. For more features, for example for running validators, monitoring, etc., please refer to the documentation of the specific client. + +> Note that backslashes `\` in examples are only for formatting purposes; config flags can be defined in a single line. + +##### Running Besu + +This example starts Besu on Mainnet, stores blockchain data in default format at `/data/ethereum`, enables JSON-RPC and Engine RPC for connecting consensus client. Engine API is authenticated with token `jwtsecret` and only calls from `localhost` are allowed. + +```sh +besu --network=mainnet \ + --data-path=/data/ethereum \ + --rpc-http-enabled=true \ + --engine-rpc-enabled=true \ + --engine-host-allowlist="*" \ + --engine-jwt-enabled=true \ + --engine-jwt-secret=/path/to/jwtsecret +``` + +Besu also comes with a launcher option which will ask a series of questions and generate the config file. Run the interactive launcher using: + +```sh +besu --Xlauncher +``` + +[Besu's documentation](https://besu.hyperledger.org/public-networks/get-started/start-node/) contains additional options and configuration details. + +##### Running Erigon + +This example starts Erigon on Mainnet, stores blockchain data at `/data/ethereum`, enables JSON-RPC, defines which namespaces are allowed and enables authentication for connecting the consensus client which is defined by the `jwtsecret` path. + +```sh +erigon --chain mainnet \ + --datadir /data/ethereum \ + --http --http.api=engine,eth,web3,net \ + --authrpc.jwtsecret=/path/to/jwtsecret +``` + +Erigon by default performs a full sync with 8GB HDD which will result in more than 2TB of archive data. Make sure `datadir` is pointing to disk with enough free space or look into `--prune` flag which can trim different kinds of data. Check the Erigon's `--help` to learn more. + +##### Running Geth + +This example starts Geth on Mainnet, stores blockchain data at `/data/ethereum`, enables JSON-RPC and defines which namespaces are allowed. It also enables authentication for connecting consensus client which requires path to `jwtsecret` and also option defining which connections are allowed, in our example only from `localhost`. + +```sh +geth --mainnet \ + --datadir "/data/ethereum" \ + --http --authrpc.addr localhost \ + --authrpc.vhosts="localhost" \ + --authrpc.port 8551 + --authrpc.jwtsecret=/path/to/jwtsecret +``` + +Check [docs for all configuration options](https://geth.ethereum.org/docs/fundamentals/command-line-options) and learn more about [running Geth with a consensus client](https://geth.ethereum.org/docs/getting-started/consensus-clients). + +##### Running Nethermind + +Nethermind offers various [installation options](https://docs.nethermind.io/get-started/installing-nethermind). The package comes with various binaries, including a Launcher with a guided setup, which will help you to create the configuration interactively. Alternatively, you find Runner which is the executable itself and you can just run it with config flags. JSON-RPC is enabled by default. + +```sh +Nethermind.Runner --config mainnet \ + --datadir /data/ethereum \ + --JsonRpc.JwtSecretFile=/path/to/jwtsecret +``` + +Nethermind docs offer a [complete guide](https://docs.nethermind.io/first-steps-with-nethermind/running-nethermind-post-merge) on running Nethermind with consensus client. + +An execution client will initiate its core functions, chosen endpoints, and start looking for peers. After successfully discovering peers, the client starts synchronization. The execution client will await a connection from consensus client. Current blockchain data will be available once the client is successfully synced to the current state. + +##### Running Reth + +This example starts Reth on Mainnet, using default data location. Enables JSON-RPC and Engine RPC authentication for connecting the consensus client which is defined by the `jwtsecret` path, with only calls from `localhost` are allowed. + +```sh +reth node \ + --authrpc.jwtsecret /path/to/jwtsecret \ + --authrpc.addr 127.0.0.1 \ + --authrpc.port 8551 +``` + +See [Configuring Reth](https://reth.rs/run/config.html?highlight=data%20directory#configuring-reth) to learn more about default data directories. [Reth's documentation](https://reth.rs/run/mainnet.html) contains additional options and configuration details. + +#### Starting the consensus client + +The consensus client must be started with the right port configuration to establish a local RPC connection to the execution client. The consensus clients have to be run with the exposed execution client port as configuration argument. + +The consensus client also needs the path to the execution client's `jwt-secret` in order to authenticate the RPC connection between them. Similar to execution examples above, each consensus client has a configuration flag which takes the jwt token file path as an argument. This must be consistent with the `jwtsecret` path provided to the execution client. + +If you plan to run a validator, make sure to add a configuration flag specifying the Ethereum address of the fee recipient. This is where ether rewards for your validator accumulate. Each consensus client has an option, e.g. `--suggested-fee-recipient=0xabcd1`, that takes an Ethereum address as an argument. + +When starting a Beacon Node on a testnet, you can save significant syncing time by using a public endpoint for [Checkpoint sync](https://notes.ethereum.org/@launchpad/checkpoint-sync). + +#### Running a consensus client + +##### Running Lighthouse + +Before running Lighthouse, learn more on how to install and configure it in [Lighthouse Book](https://lighthouse-book.sigmaprime.io/installation.html). + +```sh +lighthouse beacon_node \ + --network mainnet \ + --datadir /data/ethereum \ + --http \ + --execution-endpoint http://127.0.0.1:8551 \ + --execution-jwt /path/to/jwtsecret +``` + +##### Running Lodestar + +Install Lodestar software by compiling it or downloading the Docker image. Learn more in [docs](https://chainsafe.github.io/lodestar/) and more comprehensive [setup guide](https://hackmd.io/@philknows/rk5cDvKmK). + +```sh +lodestar beacon \ + --rootDir="/data/ethereum" \ + --network=mainnet \ + --eth1.enabled=true \ + --execution.urls="http://127.0.0.1:8551" \ + --jwt-secret="/path/to/jwtsecret" +``` + +##### Running Nimbus + +Nimbus comes with both consensus and execution clients. It can be run on various devices even with very modest computing power. +After [installing dependencies and Nimbus itself](https://nimbus.guide/quick-start.html), you can run its consensus client: + +```sh +nimbus_beacon_node \ + --network=mainnet \ + --web3-url=http://127.0.0.1:8551 \ + --rest \ + --jwt-secret="/path/to/jwtsecret" +``` + +##### Running Prysm + +Prysm comes with script which allows easy automatic installation. Details can be found in the [Prysm docs](https://docs.prylabs.network/docs/install/install-with-script). + +```sh +./prysm.sh beacon-chain \ + --mainnet \ + --datadir /data/ethereum \ + --execution-endpoint=http://localhost:8551 \ + --jwt-secret=/path/to/jwtsecret +``` + +##### Running Teku + +```sh +teku --network mainnet \ + --data-path "/data/ethereum" \ + --ee-endpoint http://localhost:8551 \ + --ee-jwt-secret-file "/path/to/jwtsecret" +``` + +When a consensus client connects to the execution client to read the deposit contract and identify validators, it also connects to other Beacon Node peers and begins syncing consensus slots from genesis. Once the Beacon Node reaches the current epoch, the Beacon API becomes usable for your validators. Learn more about [Beacon Node APIs](https://eth2docs.vercel.app/). + +### Adding Validators + +A consensus client serves as a Beacon Node for validators to connect. Each consensus client has its own validator software described in detail in its respective documentation. + +Running your own validator allows for [solo staking](/staking/solo/), the most impactful and trustless method to support the Ethereum network. However, this requires a deposit of 32 ETH. To run a validator on your own node with a smaller amount, a decentralized pool with permissionless node operators, such as [Rocket Pool](https://rocketpool.net/node-operators), might interest you. + +The easiest way to get started with staking and validator key generation is to use the [Holesky Testnet Staking Launchpad](https://holesky.launchpad.ethereum.org/), which allows you to test your setup by [running nodes on Holesky](https://notes.ethereum.org/@launchpad/holesky). When you're ready for Mainnet, you can repeat these steps using the [Mainnet Staking Launchpad](https://launchpad.ethereum.org/). + +Look into [staking page](/staking) for an overview about staking options. + +### Using the node + +Execution clients offer [RPC API endpoints](/developers/docs/apis/json-rpc/) that you can use to submit transactions, interact with or deploy smart contracts on the Ethereum network in various ways: + +- Manually calling them with a suitable protocol (e.g. using `curl`) +- Attaching a provided console (e.g. `geth attach`) +- Implementing them in applications using web3 libraries, e.g. [web3.py](https://web3py.readthedocs.io/en/stable/overview.html#overview), [ethers](https://github.com/ethers-io/ethers.js/) + +Different clients have different implementations of the RPC endpoints. But there is a standard JSON-RPC which you can use with every client. For an overview [read the JSON-RPC docs](/developers/docs/apis/json-rpc/). Applications that need information from the Ethereum network can use this RPC. For example, popular wallet MetaMask lets you [connect to your own RPC endpoint](https://metamask.zendesk.com/hc/en-us/articles/360015290012-Using-a-Local-Node) which has strong privacy and security benefits. + +The consensus clients all expose a [Beacon API](https://ethereum.github.io/beacon-APIs) that can be used to check the status of the consensus client or download blocks and consensus data by sending requests using tools such as [Curl](https://curl.se). More information on this can be found in the documentation for each consensus client. + +#### Reaching RPC + +The default port for the execution client JSON-RPC is `8545` but you can modify the ports of local endpoints in the configuration. By default, the RPC interface is only reachable on the localhost of your computer. To make it remotely accessible, you might want to expose it to the public by changing the address to `0.0.0.0`. This will make it reachable over local network and public IP addresses. In most cases you'll also need to set up port forwarding on your router. + +Approach exposing ports to the internet with caution as this will let anyone on the internet control your node. Malicious actors could access your node to bring down your system or steal your funds if you're using your client as a wallet. + +A way around this is to prevent potentially harmful RPC methods from being modifiable. For example, with Geth, you can declare modifiable methods with a flag: `--http.api web3,eth,txpool`. + +Access to the RPC interface can be extended through the development of edge layer APIs or web server applications, like Nginx, and connecting them to your client's local address and port. Leveraging a middle layer can also allow developers the ability to setup a certificate for secure `https` connections to the RPC interface. + +Setting up a web server, a proxy, or external facing Rest API is not the only way to provide access to the RPC endpoint of your node. Another privacy-preserving way to set up a publicly reachable endpoint is to host the node on your own [Tor](https://www.torproject.org/) onion service. This will let you reach the RPC outside your local network without a static public IP address or opened ports. However, using this configuration may only allow the RPC endpoint to be accessible via the Tor network which is not supported by all the applications and might result in connection issues. + +To do this, you have to create your own [onion service](https://community.torproject.org/onion-services/). Checkout [the documentation](https://community.torproject.org/onion-services/setup/) on onion service setup to host your own. You can point it to a web server with proxy to the RPC port or just directly to the RPC. + +Lastly, and one of the most popular ways to provide access to internal networks is through a VPN connection. Depending on your use case and the quantity of users needing access to your node, a secure VPN connection might be an option. [OpenVPN](https://openvpn.net/) is a full-featured SSL VPN which implements OSI layer 2 or 3 secure network extension using the industry standard SSL/TLS protocol, supports flexible client authentication methods based on certificates, smart cards, and/or username/password credentials, and allows user or group-specific access control policies using firewall rules applied to the VPN virtual interface. + +### Operating the node + +You should regularly monitor your node to make sure it's running properly. You may need to do occasional maintenance. + +#### Keeping a node online + +Your node doesn't have to be online all the time, but you should keep it online as much as possible to keep it in sync with the network. You can shut it down to restart it, but keep in mind that: + +- Shutting down can take a few minutes if the recent state is still being written on disk. +- Forced shut downs can damage the database requiring you to resync the entire node. +- Your client will go out of sync with the network and will need to resync when you restart it. While the node can begin syncing from were it was last shutdown, the process can take time depending on how long it has been offline. + +_This doesn't apply on consensus layer validator nodes._ Taking your node offline will affect all services dependent on it. If you are running a node for _staking_ purposes you should try to minimize downtime as much as possible. + +#### Creating client services + +Consider creating a service to run your clients automatically on startup. For example, on Linux servers, good practice would be to create a service, e.g. with `systemd`, that executes the client with proper config, under a user with limited privileges and automatically restarts. + +#### Updating clients + +You need to keep your client software up-to-date with the latest security patches, features, and [EIPs](/eips/). Especially before [hard forks](/history/), make sure you are running the correct client versions. + +> Before important network updates, EF publishes a post on its [blog](https://blog.ethereum.org). You can [subscribe to these announcements](https://blog.ethereum.org/category/protocol#subscribe) to get a notification to your mail when your node needs an update. + +Updating clients is very simple. Each client has specific instructions in their documentation, but the process is generally just to download the latest version and restart the client with the new executable. The client should pick up where it left off, but with the updates applied. + +Each client implementation has a human-readable version string used in the peer-to-peer protocol but is also accessible from the command line. This version string lets users check they are running the correct version and allows block explorers and other analytical tools interested in quantifying the distribution of specific clients over the network. Please refer to the individual client documentation for more information about version strings. + +#### Running additional services + +Running your own node lets you use services that require direct access to Ethereum client RPC. These are services built on top of Ethereum like [layer 2 solutions](/developers/docs/scaling/#layer-2-scaling), backend for wallets, block explorers, developer tools and other Ethereum infrastructure. + +#### Monitoring the node + +To properly monitor your node, consider collecting metrics. Clients provide metrics endpoints so you can get comprehensive data about your node. Use tools like [InfluxDB](https://www.influxdata.com/get-influxdb/) or [Prometheus](https://prometheus.io/) to create databases which you can turn into visualizations and charts in software like [Grafana](https://grafana.com/). There are many setups for using this software and different Grafana dashboards for you to visualise your node and the network as a whole. For example, check out [tutorial on monitoring Geth](/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/). + +As part of your monitoring, make sure to keep an eye on your machine's performance. During your node's initial sync, the client software may be very heavy on CPU and RAM. In addition to Grafana, you can use the tools your OS offers like `htop` or `uptime` to do this. + +## Further reading + +- [Ethereum Staking Guides](https://github.com/SomerEsat/ethereum-staking-guides) - _Somer Esat, updated often_ +- [Guide | How to setup a validator for Ethereum staking on mainnet](https://www.coincashew.com/coins/overview-eth/guide-or-how-to-setup-a-validator-on-eth2-mainnet) _– CoinCashew, updated often_ +- [ETHStaker guides on running validators on testnets](https://github.com/remyroy/ethstaker#guides) – _ETHStaker, updated regularly_ +- [Sample AWS Blockchain Node Runner app for Ethereum Nodes](https://aws-samples.github.io/aws-blockchain-node-runners/docs/Blueprints/Ethereum) - _AWS, updated often_ +- [The Merge FAQ for node operators](https://notes.ethereum.org/@launchpad/node-faq-merge) - _July 2022_ +- [Analyzing the hardware requirements to be an Ethereum full validated node](https://medium.com/coinmonks/analyzing-the-hardware-requirements-to-be-an-ethereum-full-validated-node-dc064f167902) _– Albert Palau, 24 September 2018_ +- [Running Ethereum Full Nodes: A Guide for the Barely Motivated](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux, 7 November 2019_ +- [Running a Hyperledger Besu Node on the Ethereum Mainnet: Benefits, Requirements, and Setup](https://pegasys.tech/running-a-hyperledger-besu-node-on-the-ethereum-mainnet-benefits-requirements-and-setup/) _– Felipe Faraggi, 7 May 2020_ +- [Deploying Nethermind Ethereum Client with Monitoring Stack](https://medium.com/nethermind-eth/deploying-nethermind-ethereum-client-with-monitoring-stack-55ce1622edbd) _– Nethermind.eth, 8 July 2020_ + +## Related topics + +- [Nodes and clients](/developers/docs/nodes-and-clients/) +- [Blocks](/developers/docs/blocks/) +- [Networks](/developers/docs/networks/) + +--- + +## Developers > Docs > Oracles + +Oracles are applications that produce data feeds that make offchain data sources available to the blockchain for smart contracts. This is necessary because Ethereum-based smart contracts cannot, by default, access information stored outside the blockchain network. + +Giving smart contracts the ability to execute using offchain data extends the utility and value of decentralized applications. For instance, onchain prediction markets rely on oracles to provide information about outcomes that they use to validate user predictions. Suppose Alice bets 20 ETH on who will become the next U.S. President. In that case, the prediction-market dapp needs an oracle to confirm election results and determine if Alice is eligible for a payout. + +## Prerequisites + +This page assumes the reader is familiar with Ethereum fundamentals, including [nodes](/developers/docs/nodes-and-clients/), [consensus mechanisms](/developers/docs/consensus-mechanisms/), and the [EVM](/developers/docs/evm/). You should also have a good grasp of [smart contracts](/developers/docs/smart-contracts/) and [smart contract anatomy](/developers/docs/smart-contracts/anatomy/), especially [events](/glossary/#events). + +## What is a blockchain oracle? + +Oracles are applications that source, verify, and transmit external information (i.e. information stored offchain) to smart contracts running on the blockchain. Besides “pulling” offchain data and broadcasting it on Ethereum, oracles can also “push” information from the blockchain to external systems, e.g., unlocking a smart lock once the user sends a fee via an Ethereum transaction. + +Without an oracle, a smart contract would be limited entirely to onchain data. + +Oracles differ based on the source of data (one or multiple sources), trust models (centralized or decentralized), and system architecture (immediate-read, publish-subscribe, and request-response). We can also distinguish between oracles based on whether they retrieve external data for use by onchain contracts (input oracles), send information from the blockchain to the offchain applications (output oracles), or perform computational tasks offchain (computational oracles). + +## Why do smart contracts need oracles? + +Many developers see smart contracts as code running at specific addresses on the blockchain. However, a more [general view of smart contracts](/smart-contracts/) is that they are self-executing software programs capable of enforcing agreements between parties once specific conditions are met - hence the term “smart contracts.” + +But using smart contracts to enforce agreements between people isn't straightforward, given that Ethereum is deterministic. A [deterministic system](https://en.wikipedia.org/wiki/Deterministic_algorithm) is one that always produces the same results given an initial state and a particular input, meaning there is no randomness or variation in the process of computing outputs from inputs. + +To achieve deterministic execution, blockchains limit nodes to reaching consensus on simple binary (true/false) questions using _only_ data stored on the blockchain itself. Examples of such questions include: + +- “Did the account owner (identified by a public key) sign this transaction with the paired private key?” +- “Does this account have enough funds to cover the transaction?” +- “Is this transaction valid in the context of this smart contract?”, etc. + +If blockchains received information from external sources (i.e. from the real world), determinism would be impossible to achieve, preventing nodes from agreeing on the validity of changes to the blockchain’s state. Take for example a smart contract that executes a transaction based on the current ETH-USD exchange rate obtained from a traditional price API. This figure is likely to change frequently (not to mention that the API could get deprecated or hacked), meaning nodes executing the same contract code would arrive at different results. + +For a public blockchain like Ethereum, with thousands of nodes around the world processing transactions, determinism is critical. With no central authority serving as a source of truth, nodes need mechanisms for arriving at the same state after applying the same transactions. A case whereby node A executes a smart contract’s code and gets "3" as a result, while node B gets "7" after running the same transaction would cause consensus to break down and eliminate Ethereum’s value as a decentralized computing platform. + +This scenario also highlights the problem with designing blockchains to pull information from external sources. Oracles, however, solve this problem by taking information from offchain sources and storing it on the blockchain for smart contracts to consume. Since information stored onchain is unalterable and publicly available, Ethereum nodes can safely use the oracle imported offchain data to compute state changes without breaking consensus. + +To do this, an oracle is typically made up of a smart contract running onchain and some offchain components. The onchain contract receives requests for data from other smart contracts, which it passes to the offchain component (called an oracle node). This oracle node can query data sources—using application programming interfaces (APIs), for example—and send transactions to store the requested data in the smart contract's storage. + +Essentially, a blockchain oracle bridges the information gap between the blockchain and the external environment, creating “hybrid smart contracts”. A hybrid smart contract is one that functions based on a combination of onchain contract code and offchain infrastructure. Decentralized prediction markets are an excellent example of hybrid smart contracts. Other examples might include crop insurance smart contracts that pay out when a set of oracles determine that certain weather phenomena have taken place. + +## What is the oracle problem? + +Oracles solve an important problem, but also introduce some complications, e.g.: + +- How do we verify that the injected information was extracted from the correct source or hasn’t been tampered with? + +- How do we ensure that this data is always available and updated regularly? + +The so-called “oracle problem” demonstrates the issues that come with using blockchain oracles to send inputs to smart contracts. Data from an oracle must be correct for a smart contract to execute correctly. Further, having to ‘trust’ oracle operators to provide accurate information undermines the 'trustless' aspect of smart contracts. + +Different oracles offer different solutions to the oracle problem, which we explore later. Oracles are typically evaluated on how well they can handle the following challenges: + +1. **Correctness**: An oracle should not cause smart contracts to trigger state changes based on invalid offchain data. An oracle must guarantee _authenticity_ and _integrity_ of data. Authenticity means the data was gotten from the correct source, while integrity means the data remained intact (i.e. wasn’t altered) before being sent onchain. + +2. **Availability**: An oracle should not delay or prevent smart contracts from executing actions and triggering state changes. This means that data from an oracle must be _available on request_ without interruption. + +3. **Incentive compatibility**: An oracle should incentivize offchain data providers to submit correct information to smart contracts. Incentive compatibility involves _attributability_ and _accountability_. Attributability allows for linking a piece of external information to its provider, while accountability bonds data providers to the information they give, so they can be rewarded or penalized based on the quality of information provided. + +## How does a blockchain oracle service work? + +### Users + +Users are entities (i.e., smart contracts) that need information external to the blockchain to complete specific actions. The basic workflow of an oracle service starts with the user sending a data request to the oracle contract. Data requests will usually answer some or all of the following questions: + +1. What sources can offchain nodes consult for the requested information? + +2. How do reporters process information from data sources and extract useful data points? + +3. How many oracle nodes can participate in retrieving the data? + +4. How should discrepancies in oracle reports be managed? + +5. What method should be implemented in filtering submissions and aggregating reports into a single value? + +### Oracle contract + +The oracle contract is the onchain component for the oracle service. It listens for data requests from other contracts, relays data queries to oracle nodes, and broadcasts returned data to client contracts. This contract may also perform some computation on the returned data points to produce an aggregate value to send to the requesting contract. + +The oracle contract exposes some functions which client contracts call when making a data request. Upon receiving a new query, the smart contract will emit a [log event](/developers/docs/smart-contracts/anatomy/#events-and-logs) with details of the data request. This notifies offchain nodes subscribed to the log (usually using something like the JSON-RPC `eth_subscribe` command), who proceed to retrieve data defined in the log event. + +Below is an [example oracle contract](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e) by Pedro Costa. This is a simple oracle service that can query offchain APIs upon request by other smart contracts and store the requested information on the blockchain: + +```solidity +pragma solidity >=0.4.21 string) answers; //answers provided by the oracles + mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted) + } + + //event that triggers oracle outside of the blockchain + event NewRequest ( + uint id, + string urlToQuery, + string attributeToFetch + ); + + //triggered when there's a consensus on the final result + event UpdatedRequest ( + uint id, + string urlToQuery, + string attributeToFetch, + string agreedValue + ); + + function createRequest ( + string memory _urlToQuery, + string memory _attributeToFetch + ) + public + + + //called by the oracle to record its answer + function updateRequest ( + uint _id, + string memory _valueRetrieved + ) public + tmpI++; + } + + uint currentQuorum = 0; + + //iterate through oracle list and check if enough oracles(minimum quorum) + //have voted the same answer as the current one + for(uint i = 0; i = minQuorum) + } + } + } + } +} +``` + +### Oracle nodes + +The oracle node is the offchain component of the oracle service. It extracts information from external sources, such as APIs hosted on third-party servers, and puts it onchain for consumption by smart contracts. Oracle nodes listen for events from the onchain oracle contract and proceed to complete the task described in the log. + +A common task for oracle nodes is sending a [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) request to an API service, parsing the response to extract relevant data, formatting into a blockchain-readable output, and sending it onchain by including it in a transaction to the oracle contract. The oracle node may also be required to attest to the validity and integrity of submitted information using “authenticity proofs”, which we explore later. + +Computational oracles also rely on offchain nodes to perform computational tasks that would be impractical to execute onchain, given gas costs and block size limits. For example, the oracle node may be tasked with generating a verifiably random figure (e.g., for blockchain-based games). + +## Oracle design patterns + +Oracles come in different types, including _immediate-read_, _publish-subscribe_, and _request-response_, with the latter two being the most popular among Ethereum smart contracts. Here we briefly describe the publish-subscribe and request-response models. + +### Publish-subscribe oracles + +This type of oracle exposes a “data feed” which other contracts can regularly read for information. The data in this case is expected to change frequently, so client contracts must listen for updates to the data in the oracle’s storage. An example is an oracle that provides the latest ETH-USD price information to users. + +### Request-response oracles + +A request-response setup allows the client contract to request arbitrary data other than that provided by a publish-subscribe oracle. Request-response oracles are ideal when the dataset is too large to be stored in a smart contract’s storage, and/or users will only need a small part of the data at any point in time. + +Although more complex than publish-subscribe models, request-response oracles are basically what we described in the previous section. The oracle will have an onchain component that receives a data request and passes it to an offchain node for processing. + +Users initiating data queries must cover the cost of retrieving information from the offchain source. The client contract must also provide funds to cover gas costs incurred by the oracle contract in returning the response via the callback function specified in the request. + +## Centralized vs. decentralized oracles + +### Centralized oracles + +A centralized oracle is controlled by a single entity responsible for aggregating offchain information and updating the oracle contract's data as requested. Centralized oracles are efficient since they rely on a single source of truth. They may function better in cases where proprietary datasets are published directly by the owner with a widely accepted signature. However, they bring downsides as well: + +#### Low correctness guarantees + +With centralized oracles, there's no way to confirm if the information provided is correct or not. Even "reputable" providers can go rogue or get hacked. If the oracle becomes corrupt, smart contracts will execute based on bad data. + +#### Poor availability + +Centralized oracles aren't guaranteed to always make offchain data available to other smart contracts. If the provider decides to turn off the service or a hacker hijacks the oracle's offchain component, your smart contract is at risk of a denial of service (DoS) attack. + +#### Poor incentive compatibility + +Centralized oracles often have poorly designed or non-existent incentives for the data provider to send accurate/unaltered information. Paying an oracle for correctness does not guarantee honesty. This problem gets bigger as the amount of value controlled by smart contracts increases. + +### Decentralized oracles + +Decentralized oracles are designed to overcome the limitations of centralized oracles by eliminating single points of failure. A decentralized oracle service comprises multiple participants in a peer-to-peer network that form consensus on offchain data before sending it to a smart contract. + +A decentralized oracle should (ideally) be permissionless, trustless, and free from administration by a central party; in reality, decentralization among oracles is on a spectrum. There are semi-decentralized oracle networks where anyone can participate, but with an “owner” that approves and removes nodes based on historical performance. Fully decentralized oracle networks also exist: these usually run as standalone blockchains and have defined consensus mechanisms for coordinating nodes and punishing misbehavior. + +Using decentralized oracles comes with the following benefits: + +### High correctness guarantees + +Decentralized oracles attempt to achieve correctness of data using different approaches. This includes using proofs attesting to the authenticity and integrity of the returned information and requiring multiple entities to collectively agree on the validity of offchain data. + +#### Authenticity proofs + +Authenticity proofs are cryptographic mechanisms that enable independent verification of information retrieved from external sources. These proofs can validate the source of the information and detect possible alterations to the data after retrieval. + +Examples of authenticity proofs include: + +**Transport Layer Security (TLS) proofs**: Oracle nodes often retrieve data from external sources using a secure HTTP connection based on the Transport Layer Security (TLS) protocol. Some decentralized oracles use authenticity proofs to verify TLS sessions (i.e., confirm the exchange of information between a node and a specific server) and confirm that the contents of the session were not altered. + +**Trusted Execution Environment (TEE) attestations**: A [trusted execution environment](https://en.wikipedia.org/wiki/Trusted_execution_environment) (TEE) is a sandboxed computational environment that is isolated from the operational processes of its host system. TEEs ensure that whatever application code or data stored/used in the computation environment retains integrity, confidentiality, and immutability. Users can also generate an attestation to prove an application instance is running within the trusted execution environment. + +Certain classes of decentralized oracles require oracle node operators to provide TEE attestations. This confirms to a user that the node operator is running an instance of oracle client in a trusted execution environment. TEEs prevent external processes from altering or reading an application’s code and data, hence, those attestations prove that the oracle node has kept the information intact and confidential. + +#### Consensus-based validation of information + +Centralized oracles rely on a single source of truth when providing data to smart contracts, which introduces the possibility of publishing inaccurate information. Decentralized oracles solve this problem by relying on multiple oracle nodes to query offchain information. By comparing data from multiple sources, decentralized oracles reduce the risk of passing invalid information to onchain contracts. + +Decentralized oracles, however, must deal with discrepancies in information retrieved from multiple offchain sources. To minimize differences in information and ensure the data passed to the oracle contract reflects the collective opinion of oracle nodes, decentralized oracles use the following mechanisms: + +##### Voting/staking on accuracy of data + +Some decentralized oracle networks require participants to vote or stake on the accuracy of answers to data queries (e.g., "Who won the 2020 US election?") using the network’s native token. An aggregation protocol then aggregates the votes and stakes and takes the answer supported by the majority as the valid one. + +Nodes whose answers deviate from the majority answer are penalized by having their tokens distributed to others who provide more correct values. Forcing nodes to provide a bond before providing data incentivizes honest responses since they are assumed to be rational economic actors intent on maximizing returns. + +Staking/voting also protects decentralized oracles from [Sybil attacks](/glossary/#sybil-attack) where malicious actors create multiple identities to game the consensus system. However, staking cannot prevent “freeloading” (oracle nodes copying information from others) and “lazy validation” (oracle nodes following the majority without verifying the information themselves). + +##### Schelling point mechanisms + +[Schelling point]() is a game-theory concept that assumes multiple entities will always default to a common solution to a problem in absence of any communication. Schelling-point mechanisms are often used in decentralized oracle networks to enable nodes reach consensus on answers to data requests. + +An early idea for this was [SchellingCoin](https://blog.ethereum.org/2014/03/28/schellingcoin-a-minimal-trust-universal-data-feed/), a proposed data feed where participants submit responses to "scalar" questions (questions whose answers are described by magnitude, e.g., "what is the price of ETH?"), along with a deposit. Users who provide values between the 25th and 75th [percentile](https://en.wikipedia.org/wiki/Percentile) are rewarded, while those whose values deviate largely from the median value are penalized. + +While SchellingCoin doesn’t exist today, a number of decentralized oracles—notably [Maker Protocol’s Oracles](https://docs.makerdao.com/smart-contract-modules/oracle-module)—use the schelling-point mechanism to improve accuracy of oracle data. Each Maker Oracle consists of an offchain P2P network of nodes ("relayers" and "feeds") who submit market prices for collateral assets and an onchain “Medianizer” contract that calculates the median of all provided values. Once the specified delay period is over, this median value becomes the new reference price for the associated asset. + +Other examples of oracles that use Schelling point mechanisms include [Chainlink Offchain Reporting](https://docs.chain.link/architecture-overview/off-chain-reporting) and [Witnet](https://witnet.io/). In both systems, responses from oracle nodes in the peer-to-peer network are aggregated into a single aggregate value, such as a mean or median. Nodes are rewarded or punished according to the extent to which their responses align with or deviate from the aggregate value. + +Schelling point mechanisms are attractive because they minimize onchain footprint (only one transaction needs to be sent) while guaranteeing decentralization. The latter is possible because nodes must sign off on the list of submitted responses before it is fed into the algorithm that produces the mean/median value. + +### Availability + +Decentralized oracle services ensure high availability of offchain data to smart contracts. This is achieved by decentralizing both the source of offchain information and nodes responsible for transferring the information onchain. + +This ensures fault-tolerance since the oracle contract can rely on multiple nodes (who also rely on multiple data sources) to execute queries from other contracts. Decentralization at the source _and_ node-operator level is crucial—a network of oracle nodes serving information retrieved from the same source will run into the same problem as a centralized oracle. + +It is also possible for stake-based oracles to slash node operators who fail to respond quickly to data requests. This significantly incentivizes oracle nodes to invest in fault-tolerant infrastructure and provide data in timely fashion. + +### Good incentive compatibility + +Decentralized oracles implement various incentive designs to prevent [Byzantine](https://en.wikipedia.org/wiki/Byzantine_fault) behavior among oracle nodes. Specifically, they achieve _attributability_ and _accountability_: + +1. Decentralized oracle nodes are often required to sign the data they provide in response to data requests. This information helps with evaluating the historical performance of oracle nodes, such that users can filter out unreliable oracle nodes when making data requests. An example is Witnet’s [Algorithmic Reputation System](https://docs.witnet.io/intro/about/architecture#algorithmic-reputation-system). + +2. Decentralized oracles—as explained earlier—may require nodes to place a stake on their confidence in the truth of data they submit. If the claim checks out, this stake can be returned along with rewards for honest service. But it can also be slashed in case the information is incorrect, which provides some measure of accountability. + +## Applications of oracles in smart contracts + +The following are common use-cases for oracles in Ethereum: + +### Retrieving financial data + +[Decentralized finance](/defi/) (DeFi) applications allow for peer-to-peer lending, borrowing, and trading of assets. This often requires getting different financial information, including exchange rate data (for calculating the fiat value of cryptocurrencies or comparing token prices) and capital markets data (for calculating the value of tokenized assets, such as gold or the US dollar). + +A DeFi lending protocol, for example, needs to query current market prices for assets (e.g., ETH) deposited as collateral. This lets the contract determine the value of collateral assets and determine how much it can borrow from the system. + +Popular “price oracles” (as they are often called) in DeFi include Chainlink Price Feeds, Compound Protocol’s [Open Price Feed](https://compound.finance/docs/prices), Uniswap’s [Time-Weighted Average Prices (TWAPs)](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles), and [Maker Oracles](https://docs.makerdao.com/smart-contract-modules/oracle-module). + +Builders should understand the caveats that come with these price oracles before integrating them into their project. This [article](https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles/) provides a detailed analysis of what to consider when planning to use any of the price oracles mentioned. + +Below is an example of how you can retrieve the latest ETH price in your smart contract using a Chainlink price feed: + +```solidity +pragma solidity ^0.6.7; + +import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; + +contract PriceConsumerV3 + + /** + * Returns the latest price + */ + function getLatestPrice() public view returns (int) +} +``` + +### Generating verifiable randomness + +Certain blockchain applications, such as blockchain-based games or lottery schemes, require a high level of unpredictability and randomness to work effectively. However, the deterministic execution of blockchains eliminates randomness. + +The original approach was to use pseudorandom cryptographic functions, such as `blockhash`, but these could be [manipulated by miners](https://ethereum.stackexchange.com/questions/3140/risk-of-using-blockhash-other-miners-preventing-attack#:~:text=So%20while%20the%20miners%20can,to%20one%20of%20the%20players.) solving the proof-of-work algorithm. Also, Ethereum’s [switch to proof-of-stake](/roadmap/merge/) means developers can no longer rely on `blockhash` for onchain randomness. The Beacon Chain’s [RANDAO mechanism](https://eth2book.info/altair/part2/building_blocks/randomness) provides an alternative source of randomness instead. + +It is possible to generate the random value offchain and send it onchain, but doing so imposes high trust requirements on users. They must believe the value was truly generated via unpredictable mechanisms and wasn’t altered in transit. + +Oracles designed for offchain computation solve this problem by securely generating random outcomes offchain that they broadcast onchain along with cryptographic proofs attesting to the unpredictability of the process. An example is [Chainlink VRF](https://docs.chain.link/docs/chainlink-vrf/) (Verifiable Random Function), which is a provably fair and tamper-proof random number generator (RNG) useful for building reliable smart contracts for applications that rely on unpredictable outcomes. Another example is [API3 QRNG](https://docs.api3.org/explore/qrng/) that serves Quantum random number generation (QRNG) is a public method of Web3 RNG based on quantum phenomena, served with the courtesy of the Australian National University (ANU). + +### Getting outcomes for events + +With oracles, creating smart contracts that respond to real-world events is easy. Oracle services make this possible by allowing contracts to connect to external APIs through offchain components and consume information from those data sources. For example, the prediction dapp mentioned earlier may request an oracle to return election results from a trusted offchain source (e.g., the Associated Press). + +Using oracles to retrieve data based on real-world outcomes enables other novel use cases; for example, a decentralized insurance product needs accurate information about weather, disasters, etc. to work effectively. + +### Automating smart contracts + +Smart contracts do not run automatically; rather, an externally owned account (EOA), or another contract account, must trigger the right functions to execute the contract’s code. In most cases, the bulk of the contract’s functions are public and can be invoked by EOAs and other contracts. + +But there are also _private functions_ within a contract that are inaccessible to others;, but that are critical to a dapp's overall functionality. Examples include a `mintERC721Token()` function that periodically mints new NFTs for users, a function for awarding payouts in a prediction market, or a function for unlocking staked tokens in a DEX. + +Developers will need to trigger such functions at intervals to keep the application running smoothly. However, this might lead to more hours lost on mundane tasks for developers, which is why automating execution of smart contracts is attractive. + +Some decentralized oracle networks offer automation services, which allow offchain oracle nodes to trigger smart contract functions according to parameters defined by the user. Typically, this requires “registering” the target contract with the oracle service, providing funds to pay the oracle operator, and specifying the conditions or times to trigger the contract. + +Chainlink’s [Keeper Network](https://chain.link/keepers) provides options for smart contracts to outsource regular maintenance tasks in a trust minimized and decentralized manner. Read the official [Keeper's documentation](https://docs.chain.link/docs/chainlink-keepers/introduction/) for information on making your contract Keeper-compatible and using the Upkeep service. + +## How to use blockchain oracles + +There are multiple oracle applications you can integrate into your Ethereum dapp: + +**[Chainlink](https://chain.link/)** - _Chainlink decentralized oracle networks provide tamper-proof inputs, outputs, and computations to support advanced smart contracts on any blockchain._ + +**[RedStone Oracles](https://redstone.finance/)** - _RedStone is a decentralized modular oracle that provides gas-optimized data feeds. It specializes in offering price feeds for emerging assets, such as liquid staking tokens (LSTs), liquid restaking tokens (LRTs), and Bitcoin staking derivatives._ + +**[Chronicle](https://chroniclelabs.org/)** - _Chronicle overcomes the current limitations of transferring data onchain by developing truly scalable, cost-efficient, decentralized, and verifiable oracles._ + +**[Witnet](https://witnet.io/)** - _Witnet is a permissionless, decentralized, and censorship-resistant oracle helping smart contracts to react to real world events with strong crypto-economic guarantees._ + +**[UMA Oracle](https://uma.xyz)** - _UMA's optimistic oracle allows smart contracts to quickly and receive any kind of data for different applications, including insurance, financial derivatives, and prediction markets._ + +**[Tellor](https://tellor.io/)** - _Tellor is a transparent and permissionless oracle protocol for your smart contract to easily get any data whenever it needs it._ + +**[Band Protocol](https://bandprotocol.com/)** - _Band Protocol is a cross-chain data oracle platform that aggregates and connects real-world data and APIs to smart contracts._ + +**[Paralink](https://paralink.network/)** - _Paralink provides an open source and decentralized oracle platform for smart contracts running on Ethereum and other popular blockchains._ + +**[Pyth Network](https://pyth.network/)** - _The Pyth network is a first-party financial oracle network designed to publish continuous real-world data onchain in a tamper-resistant, decentralized, and self-sustainable environment._ + +**[API3 DAO](https://www.api3.org/)** - _API3 DAO is delivering first-party oracle solutions that deliver greater source transparency, security and scalability in a decentralized solution for smart contracts_ + +**[Supra](https://supra.com/)** - A vertically integrated toolkit of cross-chain solutions that interlink all blockchains, public (L1s and L2s) or private (enterprises), providing decentralized oracle price feeds that can be used for onchain and offchain use-cases. + +## Further reading + +**Articles** + +- [What Is a Blockchain Oracle?](https://chain.link/education/blockchain-oracles) — _Chainlink_ +- [What is a Blockchain Oracle?](https://betterprogramming.pub/what-is-a-blockchain-oracle-f5ccab8dbd72) — _Patrick Collins_ +- [Decentralised Oracles: a comprehensive overview](https://medium.com/fabric-ventures/decentralised-oracles-a-comprehensive-overview-d3168b9a8841) — _Julien Thevenard_ +- [Implementing a Blockchain Oracle on Ethereum](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e) – _Pedro Costa_ +- [Why can't smart contracts make API calls?](https://ethereum.stackexchange.com/questions/301/why-cant-contracts-make-api-calls) — _StackExchange_ +- [Why we need decentralized oracles](https://newsletter.banklesshq.com/p/why-we-need-decentralized-oracles) — _Bankless_ +- [So you want to use a price oracle](https://samczsun.com/so-you-want-to-use-a-price-oracle/) — _samczsun_ + +**Videos** + +- [Oracles and the Expansion of Blockchain Utility](https://youtu.be/BVUZpWa8vpw) — _Real Vision Finance_ +- [The differences between first party and third party oracles](https://blockchainoraclesummit.io/first-party-vs-third-party-oracles/) - _Blockchain Oracle Summit_ + +**Tutorials** + +- [How to Fetch the Current Price of Ethereum in Solidity](https://blog.chain.link/fetch-current-crypto-price-data-solidity/) — _Chainlink_ +- [Consuming Oracle Data](https://docs.chroniclelabs.org/Developers/tutorials/Remix) — _Chronicle_ + +**Example projects** + +- [Full Chainlink starter project for Ethereum in Solidity](https://github.com/hackbg/chainlink-fullstack) — _HackBG_ + +--- + +## Developers > Docs > Programming Languages > Dart + +## Getting started with smart contracts and the Solidity language + +## Tutorials + +- [Flutter and Blockchain – Hello World Dapp](https://www.geeksforgeeks.org/flutter-and-blockchain-hello-world-dapp/) takes you through all the steps to get started: + 1. Writing a smart contract in [Solidity](https://soliditylang.org/) + 2. Writing a user interface in Dart +- [Building a Mobile dapp with Flutter](https://medium.com/dash-community/building-a-mobile-dapp-with-flutter-be945c80315a) is a lot shorter, which might be better + if you already know the basics +- If you prefer to learn by watching a video, you can watch [Build Your First Blockchain Flutter App](https://www.youtube.com/watch?v=3Eeh3pJ6PeA), which is about an hour long +- If you are impatient, you might prefer [Building a Blockchain Decentralized-app with Flutter and Dart on Ethereum](https://www.youtube.com/watch?v=jaMFEOCq_1s), which is only about twenty minutes +- [Integrating MetaMask in Flutter application with Web3Modal by WalletConnect](https://www.youtube.com/watch?v=v_M2buHCpc4) - this short video takes you through the steps of integrating MetaMask into your Flutter applications with [Web3Modal](https://pub.dev/packages/web3modal_flutter) library by WalletConnect +- [Mobile Blockchain Developer Bootcamp Course With Solidity & Flutter](https://youtube.com/playlist?list=PL4V4Unlk5luhQ26ERO6hWEbcUwHDSSmVH) - full stack mobile blockchain developer course playlist + +## Working with Ethereum clients + +You can use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. +There are at least two currently maintained libraries for Dart to use the +[JSON-RPC API](/developers/docs/apis/json-rpc/) for Ethereum. + +1. [Web3dart from simonbutler.eu](https://pub.dev/packages/web3dart) +1. [Ethereum 5.0.0 from darticulate.com](https://pub.dev/packages/ethereum) + +There are also additional libraries that allow you to manipulate specific Ethereum addresses, +or that let you retrieve prices of various cryptocurrencies. +[You can see the full list here](https://pub.dev/dart/packages?q=ethereum). + +--- + +## Developers > Docs > Programming Languages > Delphi + +Learn how to develop for Ethereum using the Delphi programming language + + + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets in order to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +Build decentralized applications on top of Ethereum and interact with smart contracts using the Delphi programming language! + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Delphi with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Beginner references and links + +**Introducing the Delphereum library** + +- [What is Delphereum?](https://github.com/svanas/delphereum/blob/master/README.md) +- [Connecting Delphi to a local (in-memory) blockchain](https://medium.com/@svanas/connecting-delphi-to-a-local-in-memory-blockchain-9a1512d6c5b0) +- [Connecting Delphi to Ethereum Mainnet](https://medium.com/@svanas/connecting-delphi-to-the-ethereum-main-net-5faf1feffd83) +- [Connecting Delphi to Smart Contracts](https://medium.com/@svanas/connecting-delphi-to-smart-contracts-3146b12803a1) + +**Want to skip setup for now, and jump straight to the samples?** + +- [A 3-minute Smart Contract and Delphi - Part 1](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-61d998571d) +- [A 3-minute Smart Contract and Delphi - Part 2](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-part-2-446925faa47b) + +## Intermediate articles + +- [Generating an Ethereum-signed message signature in Delphi](https://medium.com/@svanas/generating-an-ethereum-signed-message-signature-in-delphi-75661ce5031b) +- [Transferring ether with Delphi](https://medium.com/@svanas/transferring-ether-with-delphi-b5f24b1a98a4) +- [Transferring ERC-20 tokens with Delphi](https://medium.com/@svanas/transferring-erc-20-tokens-with-delphi-bb44c05b295d) + +## Advanced use patterns + +- [Delphi and Ethereum Name Service (ENS)](https://medium.com/@svanas/delphi-and-ethereum-name-service-ens-4443cd278af7) +- [QuikNode, Ethereum and Delphi](https://medium.com/@svanas/quiknode-ethereum-and-delphi-f7bfc9671c23) +- [Delphi and the Ethereum Dark Forest](https://svanas.medium.com/delphi-and-the-ethereum-dark-forest-5b430da3ad93) +- [Swap one token for another in Delphi](https://svanas.medium.com/swap-one-token-for-another-in-delphi-bcb999c47f7) + +Looking for more resources? Check out [ethereum.org/developers](/developers/). + +--- + +## Developers > Docs > Programming Languages > Dot Net + +Learn how to develop for Ethereum using .NET-based projects and tooling + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets in order to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +Build decentralized applications on top of Ethereum and interact with smart contracts using tools and languages from the Microsoft technology stack - Supporting C#, # Visual Basic .NET, F#, on tooling such as VSCode and Visual Studio, across .NET Framework/.NET Core/.NET Standard. Deploy an Ethereum blockchain on Azure using Microsoft Azure Blockchain in minutes. Bring the love of .NET to Ethereum! + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating .NET with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Beginner references and links + +**Introducing the Nethereum library and VS Code Solidity** + +- [Nethereum, Getting Started](https://docs.nethereum.com/en/latest/getting-started/) +- [Installing VS Code Solidity](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) +- [A .NET Developer’s Workflow for Creating and Calling Ethereum Smart Contracts](https://medium.com/coinmonks/a-net-developers-workflow-for-creating-and-calling-ethereum-smart-contracts-44714f191db2) +- [Smart contracts integration with Nethereum](https://kauri.io/#collections/Getting%20Started/smart-contracts-integration-with-nethereum/#smart-contracts-integration-with-nethereumm) +- [Interfacing .NET and Ethereum Blockchain Smart Contracts with Nethereum](https://medium.com/my-blockchain-development-daily-journey/interfacing-net-and-ethereum-blockchain-smart-contracts-with-nethereum-2fa3729ac933), also in [中文版](https://medium.com/my-blockchain-development-daily-journey/%E4%BD%BF%E7%94%A8nethereum%E9%80%A3%E6%8E%A5-net%E5%92%8C%E4%BB%A5%E5%A4%AA%E7%B6%B2%E5%8D%80%E5%A1%8A%E9%8F%88%E6%99%BA%E8%83%BD%E5%90%88%E7%B4%84-4a96d35ad1e1) +- [Nethereum - An open source .NET integration library for blockchain](https://kauri.io/#collections/a%20hackathon%20survival%20guide/nethereum-an-open-source-.net-integration-library/) +- [Writing Ethereum Transactions to SQL Database Using Nethereum](https://medium.com/coinmonks/writing-ethereum-transactions-to-sql-database-using-nethereum-fd94e0e4fa36) +- [See how to easily deploy Ethereum smart contracts using C# and VisualStudio](https://koukia.ca/deploy-ethereum-smart-contracts-using-c-and-visualstudio-5be188ae928c) + +**Want to skip setup for now, and jump straight to the samples?** + +- [Playground](http://playground.nethereum.com/) - Interact with Ethereum and learn how to use Nethereum through the browser. + - Query Account Balance [C#](http://playground.nethereum.com/csharp/id/1001) [VB.NET](http://playground.nethereum.com/vb/id/2001) + - Query ERC20 Smart Contract Balance [C#](http://playground.nethereum.com/csharp/id/1005) [VB.NET](http://playground.nethereum.com/vb/id/2004) + - Transfer ether to an Account [C#](http://playground.nethereum.com/csharp/id/1003) [VB.NET](http://playground.nethereum.com/vb/id/2003) + - ... And more! + +## Intermediate articles + +- [Nethereum Workbook/Sample List](http://docs.nethereum.com/en/latest/Nethereum.Workbooks/docs/) +- [Deploy Your Own Development Testchains](https://github.com/Nethereum/Testchains) +- [VSCode Codegen Plugin for Solidity](https://docs.nethereum.com/en/latest/nethereum-codegen-vscodesolidity/) +- [Unity and Ethereum: Why and How](https://www.raywenderlich.com/5509-unity-and-ethereum-why-and-how) +- [Create ASP.NET Core Web API for Ethereum dapps](https://tech-mint.com/blockchain/create-asp-net-core-web-api-for-ethereum-dapps/) +- [Using Nethereum Web3 to Implement a Supply Chain Tracking System](http://blog.pomiager.com/post/using-nethereum-web3-to-implement-a-supply-chain-traking-system4) +- [Nethereum Block Processing](https://nethereum.readthedocs.io/en/latest/nethereum-block-processing-detail/), with [C# Playground sample](http://playground.nethereum.com/csharp/id/1025) +- [Nethereum Websocket Streaming](https://nethereum.readthedocs.io/en/latest/nethereum-subscriptions-streaming/) +- [Kaleido and Nethereum](https://kaleido.io/kaleido-and-nethereum/) +- [Quorum and Nethereum](https://github.com/Nethereum/Nethereum/blob/master/src/Nethereum.Quorum/README.md) + +## Advanced use patterns + +- [Azure Key Vault And Nethereum](https://github.com/Azure-Samples/bc-community-samples/tree/master/akv-nethereum) +- [Nethereum.DappHybrid](https://github.com/Nethereum/Nethereum.DappHybrid) +- [Ujo Nethereum backend reference architecture](https://docs.nethereum.com/en/latest/nethereum-ujo-backend-sample/) + +## .NET projects, tools and other fun stuff + +- [Nethereum Playground](http://playground.nethereum.com/) - _Compile, create, and run Nethereum code snippets in browser_ +- [Nethereum Codegen Blazor](https://github.com/Nethereum/Nethereum.CodeGen.Blazor) - _Nethereum codegen with UI in Blazor_ +- [Nethereum Blazor](https://github.com/Nethereum/NethereumBlazor) - _A .NET Wasm SPA light blockchain explorer and simple wallet_ +- [Wonka Business Rules Engine](https://docs.nethereum.com/en/latest/wonka/) - _A business rules engine (for both the .NET platform and the Ethereum platform) that is inherently metadata-driven_ +- [Nethermind](https://github.com/NethermindEth/nethermind) - _A .NET Core Ethereum client for Linux, Windows, MacOS_ +- [eth-utils](https://github.com/ethereum/eth-utils/) - _utility functions for working with Ethereum related codebases_ +- [TestChains](https://github.com/Nethereum/TestChains) - _Pre-configured .NET devchains for fast response (PoA)_ + +Looking for more resources? Check out [ethereum.org/developers](/developers/). + +## .NET community contributors + +At Nethereum, we mostly hang out on [Gitter](https://gitter.im/Nethereum/Nethereum) where everyone is welcome to ask/answer questions, get help, or just chill. Feel free to do a PR or open an issue on the [Nethereum GitHub repository](https://github.com/Nethereum), or just browse through the many side/sample projects we have. You can also find us on [Discord](https://discord.gg/jQPrR58FxX)! + +If you are new to Nethermind and need help getting started, join our [Discord](http://discord.gg/PaCMRFdvWT). Our developers are on hand to answer your questions. Don't hesitate to open a PR or raise any issues on the [Nethermind GitHub repository](https://github.com/NethermindEth/nethermind). + +## Other aggregated lists + +[Official Nethereum Site](https://nethereum.com/) +[Official Nethermind Site](https://nethermind.io/) + +--- + +## Developers > Docs > Programming Languages > Elixir + +Learn how to develop for Ethereum using Elixir-based projects and tooling. + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustless, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Elixir with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Beginner articles + +- [Finally understanding Ethereum accounts](https://dev.to/q9/finally-understanding-ethereum-accounts-1kpe) +- [Ethers — A first-class Ethereum Web3 library for Elixir](https://medium.com/@alisinabh/announcing-ethers-a-first-class-ethereum-web3-library-for-elixir-1d64e9409122) + +## Intermediate articles + +- [How to sign raw Ethereum contract transactions with Elixir](https://kohlerjp.medium.com/how-to-sign-raw-ethereum-contract-transactions-with-elixir-f8822bcc813b) +- [Ethereum Smart Contracts and Elixir](https://medium.com/agile-alpha/ethereum-smart-contracts-and-elixir-c7c4b239ddb4) + +## Elixir projects and tools + +### Active + +- [block_keys](https://github.com/ExWeb3/block_keys) - _BIP32 & BIP44 Implementation in Elixir (Multi-Account Hierarchy for Deterministic Wallets)_ +- [ethereumex](https://github.com/mana-ethereum/ethereumex) - _Elixir JSON-RPC client for the Ethereum blockchain_ +- [ethers](https://github.com/ExWeb3/elixir_ethers) - _A comprehensive Web3 library for interacting with smart contracts on Ethereum using Elixir_ +- [ethers_kms](https://github.com/ExWeb3/elixir_ethers_kms) - _A KMS signer library for Ethers (sign transactions with AWS KMS)_ +- [ex_abi](https://github.com/poanetwork/ex_abi) - _Ethereum ABI parser/decoder/encoder implementation in Elixir_ +- [ex_keccak](https://github.com/ExWeb3/ex_keccak) - _Elixir library for computing Keccak SHA3-256 hashes using a NIF built tiny-keccak Rust crate_ +- [ex_rlp](https://github.com/mana-ethereum/ex_rlp) - _Elixir implementation of Ethereum's RLP (Recursive Length Prefix) encoding_ + +### Archived / No longer maintained + +- [eth](https://hex.pm/packages/eth) - _Ethereum utilities for Elixir_ +- [exw3](https://github.com/hswick/exw3) - _High level Ethereum RPC Client for Elixir_ +- [mana](https://github.com/mana-ethereum/mana) - _Ethereum full node implementation written in Elixir_ + +Looking for more resources? Check out [our Developer's home](/developers/). + +## Elixir community contributors + +The [Elixir's Slack #ethereum channel](https://elixir-lang.slack.com/archives/C5RPZ3RJL) is a host to a rapidly growing community and is the dedicated resource for discussions on any of the above projects and related topics. + +--- + +## Developers > Docs > Programming Languages > Golang + +Learn how to develop for Ethereum using Go-based projects and tooling + +Use Ethereum to create decentralized applications (or "dapps"). These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They are decentralized, meaning that they run on a peer-to-peer network and there is no single point of failure. No single entity or person controls them and they are nearly impossible to censor. They can control digital assets in order to create new kinds of applications. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Go with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [Contract Tutorial](https://github.com/ethereum/go-ethereum/wiki/Contract-Tutorial) + +## Beginner articles and books + +- [Getting Started with Geth](https://medium.com/@tzhenghao/getting-started-with-geth-c1a30b8d6458) +- [Use Golang to Connect to Ethereum](https://www.youtube.com/watch?v=-7uChuO_VzM) +- [Deploy Ethereum Smart Contracts Using Golang](https://www.youtube.com/watch?v=pytGqQmDslE) +- [A Step By Step Guide To Testing and Deploying Ethereum Smart Contracts in Go](https://hackernoon.com/a-step-by-step-guide-to-testing-and-deploying-ethereum-smart-contracts-in-go-9fc34b178d78) +- [eBook: Ethereum Development with Go](https://goethereumbook.org/) - _Develop Ethereum applications with Go_ + +## Intermediate articles and docs + +- [Go Ethereum Documentation](https://geth.ethereum.org/docs/) - _The documentation for the official Ethereum Golang_ +- [Erigon Programmer's Guide](https://github.com/ledgerwatch/erigon/blob/devel/docs/programmers_guide/guide.md) - _Illustrated guide including the state tree, multi-proofs, and transaction processing_ +- [Erigon and Stateless Ethereum](https://youtu.be/3-Mn7OckSus?t=394) - _2020 Ethereum Community Conference (EthCC 3)_ +- [Erigon: optimising Ethereum clients](https://www.youtube.com/watch?v=CSpc1vZQW2Q) - _2018 Devcon 4_ +- [Go Ethereum GoDoc](https://godoc.org/github.com/ethereum/go-ethereum) +- [Creating a dapp in Go with Geth](https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/creating-a-dapp-in-go-with-geth/) +- [Work with Ethereum Private Network with Golang and Geth](https://myhsts.org/tutorial-learn-how-to-work-with-ethereum-private-network-with-golang-with-geth.php) +- [Unit testing Solidity contracts on Ethereum with Go](https://medium.com/coinmonks/unit-testing-solidity-contracts-on-ethereum-with-go-3cc924091281) +- [Quick reference for using Geth as a library](https://medium.com/coinmonks/web3-go-part-1-31c68c68e20e) + +## Advanced use patterns + +- [The GETH Simulated Backend](https://kauri.io/#collections/An%20ethereum%20test%20toolkit%20in%20Go/the-geth-simulated-backend/#_top) +- [Blockchain-as-a-Service Apps Using Ethereum and Quorum](https://blockchain.dcwebmakers.com/blockchain-as-a-service-apps-using-ethereum-and-quorum.html) +- [Distributed Storage IPFS and Swarm in Ethereum Blockchain Applications](https://blockchain.dcwebmakers.com/work-with-distributed-storage-ipfs-and-swarm-in-ethereum.html) +- [Mobile Clients: Libraries and Inproc Ethereum Nodes](https://github.com/ethereum/go-ethereum/wiki/Mobile-Clients:-Libraries-and-Inproc-Ethereum-Nodes) +- [Native dapps: Go bindings to Ethereum contracts](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) + +## Go projects and tools + +- [Geth / Go Ethereum](https://github.com/ethereum/go-ethereum) - _Official Go implementation of the Ethereum protocol_ +- [Go Ethereum Code Analysis](https://github.com/ZtesoftCS/go-ethereum-code-analysis) - _Review and analysis of Go Ethereum source code_ +- [Erigon](https://github.com/ledgerwatch/erigon) - _Faster derivative of Go Ethereum, with a focus on archive nodes_ +- [Golem](https://github.com/golemfactory/golem) - _Golem is creating a global market for computing power_ +- [Quorum](https://github.com/jpmorganchase/quorum) - _A permissioned implementation of Ethereum supporting data privacy_ +- [Prysm](https://github.com/prysmaticlabs/prysm) - _Ethereum 'Serenity' 2.0 Go Implementation_ +- [Eth Tweet](https://github.com/yep/eth-tweet) - _Decentralized Twitter: A microblogging service running on the Ethereum blockchain_ +- [Plasma MVP Golang](https://github.com/kyokan/plasma) — _Golang implementation and extension of the Minimum Viable Plasma specification_ +- [Open Ethereum Mining Pool](https://github.com/sammy007/open-ethereum-pool) - _An open source Ethereum mining pool_ +- [Ethereum HD Wallet](https://github.com/miguelmota/go-ethereum-hdwallet) - _Ethereum HD Wallet derivations in Go_ +- [Multi Geth](https://github.com/multi-geth/multi-geth) - _Support for many species of Ethereum networks_ +- [Geth Light Client](https://github.com/zsfelfoldi/go-ethereum/wiki/Geth-Light-Client) - _Light Ethereum Subprotocol's Geth implementation_ +- [Ethereum Golang SDK](https://github.com/everFinance/goether) - _A simple Ethereum wallet implementation and utilities in Golang_ +- [Covalent Golang SDK](https://github.com/covalenthq/covalent-api-sdk-go) - _Efficient blockchain data access via Go SDK for 200+ blockchains_ + +Looking for more resources? Check out [ethereum.org/developers](/developers/) + +## Go community contributors + +- [Geth Discord](https://discordapp.com/invite/nthXNEv) +- [Geth Gist](https://gitter.im/ethereum/go-ethereum) +- [Gophers Slack](https://invite.slack.golangbridge.org/) - [#ethereum channel](https://gophers.slack.com/messages/C9HP1S9V2) +- [StackExchange - Ethereum](https://ethereum.stackexchange.com/) +- [Multi Geth Gitter](https://gitter.im/ethoxy/multi-geth) +- [Ethereum Gitter](https://gitter.im/ethereum/home) +- [Geth light Client Gitter](https://gitter.im/ethereum/light-client) + +## Other aggregated lists + +- [Awesome Ethereum](https://github.com/btomashvili/awesome-ethereum) +- [Consensys: A Definitive List of Ethereum Developer Tools](https://media.consensys.net/an-definitive-list-of-ethereum-developer-tools-2159ce865974) | [GitHub source](https://github.com/ConsenSys/ethereum-developer-tools-list) + +--- + +## Developers > Docs > Programming Languages + +A common misconception is that developers must write [smart contracts](/developers/docs/smart-contracts/) in order to build on Ethereum. This is false. +One of the beauties of the Ethereum network and community is that you're able to [participate](/community/) in just about any programming language. + +Ethereum and its community embrace open source. You can find community projects - client implementations, APIs, development frameworks, testing tools - in a wide variety of languages. + +## Choose your language + +Select your programming language of choice to find projects, resources, and virtual communities: + +- [Ethereum for Dart developers](/developers/docs/programming-languages/dart/) +- [Ethereum for Delphi developers](/developers/docs/programming-languages/delphi/) +- [Ethereum for .NET developers](/developers/docs/programming-languages/dot-net/) +- [Ethereum for Elixir developers](/developers/docs/programming-languages/elixir/) +- [Ethereum for Go developers](/developers/docs/programming-languages/golang/) +- [Ethereum for Java developers](/developers/docs/programming-languages/java/) +- [Ethereum for JavaScript developers](/developers/docs/programming-languages/javascript/) +- [Ethereum for Python developers](/developers/docs/programming-languages/python/) +- [Ethereum for Ruby developers](/developers/docs/programming-languages/ruby/) +- [Ethereum for Rust developers](/developers/docs/programming-languages/rust/) + +### What if my language is not supported + +If you want to link to resources or point to a virtual community for an additional programming language you can request a new page by [opening an issue](https://github.com/ethereum/ethereum-org-website/issues/new/choose). + +If you just want to write code to interface with the blockchain using a currently unsupported language +you can use the [JSON-RPC interface](/developers/docs/apis/json-rpc/) to connect to the Ethereum network. Any programming +language that can use TCP/IP can use this interface. + +--- + +## Developers > Docs > Programming Languages > Java + +Learn how to develop for Ethereum using Java-based projects and tooling + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets in order to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Java with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers.](/developers/) + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Working with Ethereum clients + +Learn how to use [Web3J](https://github.com/web3j/web3j) and Hyperledger Besu, two leading Java Ethereum Clients + +- [Connecting to an Ethereum client with Java, Eclipse, and Web3J](https://kauri.io/article/b9eb647c47a546bc95693acc0be72546/connecting-to-an-ethereum-client-with-java-eclipse-and-web3j) +- [Manage an Ethereum account with Java and Web3j](https://kauri.io/article/925d923e12c543da9a0a3e617be963b4/manage-an-ethereum-account-with-java-and-web3j) +- [Generate a Java Wrapper from your Smart Contract](https://kauri.io/article/84475132317d4d6a84a2c42eb9348e4b/generate-a-java-wrapper-from-your-smart-contract) +- [Interacting with an Ethereum Smart Contract](https://kauri.io/article/14dc434d11ef4ee18bf7d57f079e246e/interacting-with-an-ethereum-smart-contract-in-java) +- [Listening for Ethereum Smart Contract Events](https://kauri.io/article/760f495423db42f988d17b8c145b0874/listening-for-ethereum-smart-contract-events-in-java) +- [Using Besu (Pantheon), the Java Ethereum Client with Linux](https://kauri.io/article/276dd27f1458443295eea58403fd6965/using-pantheon-the-java-ethereum-client-with-linux) +- [Running a Hyperledger Besu (Pantheon) Node in Java Integration Tests](https://kauri.io/article/7dc3ecc391e54f7b8cbf4e5fa0caf780/running-a-pantheon-node-in-java-integration-tests) +- [Web3j Cheat Sheet]() + +Learn how to use [ethers-kt](https://github.com/Kr1ptal/ethers-kt), an async, high-performance Kotlin library for interacting with EVM-based blockchains. Targeting JVM and Android platforms. +- [Transfer ERC20 tokens](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/abi/TransferERC20.kt) +- [UniswapV2 swap with event listening](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/tokenswapwitheventlistening/TokenSwapWithEventListening.kt) +- [ETH / ERC20 balance tracker](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/balancetracker/BalanceTracker.kt) + +## Intermediate articles + +- [Managing storage in a Java application with IPFS](https://kauri.io/article/3e8494f4f56f48c4bb77f1f925c6d926/managing-storage-in-a-java-application-with-ipfs) +- [Manage ERC20 tokens in Java with Web3j](https://kauri.io/article/d13e911bbf624108b1d5718175a5e0a0/manage-erc20-tokens-in-java-with-web3j) +- [Web3j Transaction Managers](https://kauri.io/article/4cb780bb4d0846438d11885a25b6d7e7/web3j-transaction-managers) + +## Advanced use patterns + +- [Using Eventeum to build a Java smart contract data cache](https://kauri.io/article/fe81ee9612eb4e5a9ab72790ef24283d/using-eventeum-to-build-a-java-smart-contract-data-cache) + +## Java projects and tools + +- [Hyperledger Besu (Pantheon) (Ethereum Client)](https://docs.pantheon.pegasys.tech/en/stable/) +- [Web3J (Library for Interacting with Ethereum Clients)](https://github.com/web3j/web3j) +- [ethers-kt (Async, high-performance Kotlin/Java/Android library for EVM-based blockchains.)](https://github.com/Kr1ptal/ethers-kt) +- [Eventeum (Event Listener)](https://github.com/ConsenSys/eventeum) +- [Mahuta (IPFS Dev Tools)](https://github.com/ConsenSys/mahuta) + +Looking for more resources? Check out [ethereum.org/developers.](/developers/) + +## Java community contributors + +- [IO Builders](https://io.builders) +- [Kauri](https://kauri.io) +- [Besu HL chat](https://chat.hyperledger.org/channel/besu) + +--- + +## Developers > Docs > Programming Languages > Javascript + +JavaScript is among the most popular languages in the Ethereum ecosystem. In fact, there's a [team](https://github.com/ethereumjs) dedicated to bringing as much of Ethereum to JavaScript as possible. + +There are opportunities to write JavaScript (or something close) at [all levels of the stack](/developers/docs/ethereum-stack/). + +## Interact with Ethereum + +### JavaScript API libraries + +If you'd like to write JavaScript to query the blockchain, send transactions and more, the most convenient way to do this is using a [JavaScript API library](/developers/docs/apis/javascript/). These APIs allow developers to easily interact with the [nodes in the Ethereum network](/developers/docs/nodes-and-clients/). + +You can use these libraries to interact with smart contracts on Ethereum so it's possible to build a dapp where you just use JavaScript to interact with pre-existing contracts. + +**Check out** + +- [Web3.js](https://web3js.readthedocs.io/) +- [Ethers.js](https://docs.ethers.io/) _– includes Ethereum wallet implementation and utilities in JavaScript and TypeScript._ +- [viem](https://viem.sh) – a TypeScript Interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum. + +### Smart contracts + +If you're a JavaScript developer and want to write your own smart contract, you may want to get familiar with [Solidity](https://solidity.readthedocs.io). This is the most popular smart contract language and it's syntactically similar to JavaScript, which may make it easier to learn. + +More on [smart contracts](/developers/docs/smart-contracts/). + +## Understand the protocol + +### The Ethereum virtual machine + +There is a JavaScript implementation of [Ethereum's virtual machine](/developers/docs/evm/). It supports the latest fork rules. Fork rules refer to changes made to the EVM as a result of planned upgrades. + +It's split out into various JavaScript packages that you can check out to better understand: + +- Accounts +- Blocks +- The blockchain itself +- Transactions +- And more... + +This will help you understand things like "what's the data structure of an account?". + +If you prefer to read code, this JavaScript could be a great alternative to reading through our docs. + +**Check out the EVM** +[`@ethereumjs/evm`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/evm) + +### Nodes and clients + +An Ethereumjs client is in active development that lets you dig into how Ethereum clients work in a language you understand; JavaScript! + +**Check out the client** +[`@ethereumjs/client`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/client) + +## Other projects + +There are also plenty of other things going on in the land of Ethereum JavaScript, including: + +- libraries of wallet utilities. +- tools to generate, import, and export Ethereum keys. +- an implementation of the `merkle-patricia-tree` – a data structure outlined in the Ethereum yellow paper. + +Dig into whatever interests you most over at the [EthereumJS repo](https://github.com/ethereumjs) + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Programming Languages > Python + +Learn how to develop for Ethereum using Python-based projects and tooling + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets in order to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Python with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [The state of Python in blockchain 2023 report](https://tradingstrategy.ai/blog/the-state-of-python-in-blockchain-in-2023) + +## Beginner articles + +- [web3.py Overview](https://web3py.readthedocs.io/en/latest/overview.html) +- [Ethereum Python Ecosystem Tour](https://snakecharmers.ethereum.org/python-ecosystem/) +- [A (Python) Developer's Guide to Ethereum](https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/) +- [Prize-Worthy: An Ethereum Python Hackathon Guide](https://snakecharmers.ethereum.org/prize-worthy/) +- [An Introduction to Smart Contracts with Vyper](https://kauri.io/#collections/Getting%20Started/an-introduction-to-smart-contracts-with-vyper/) +- [How to develop Ethereum contract using Python Flask?](https://medium.com/coinmonks/how-to-develop-ethereum-contract-using-python-flask-9758fe65976e) +- [Intro to Web3.py · Ethereum For Python Developers](https://www.dappuniversity.com/articles/web3-py-intro) +- [How to call a Smart Contract function using Python and web3.py](https://stackoverflow.com/questions/57580702/how-to-call-a-smart-contract-function-using-python-and-web3-py) + +## Intermediate articles + +- [Friends of web3.py: Intro to Ape](https://snakecharmers.ethereum.org/intro-to-ape/) +- [Dapp Development for Python Programmers](https://levelup.gitconnected.com/dapps-development-for-python-developers-f52b32b54f28) +- [Creating a Python Ethereum Interface: Part 1](https://hackernoon.com/creating-a-python-ethereum-interface-part-1-4d2e47ea0f4d) +- [Ethereum Smart Contracts in Python: a comprehensive(ish) guide](https://hackernoon.com/ethereum-smart-contracts-in-python-a-comprehensive-ish-guide-771b03990988) + +## Advanced use patterns + +- [web3.py Patterns: Real-Time Event Subscriptions](https://snakecharmers.ethereum.org/subscriptions/) +- [web3.py Patterns: WebSocketProvider](https://snakecharmers.ethereum.org/websocketprovider/) +- [Compiling, deploying and calling Ethereum smartcontract using Python](https://yohanes.gultom.id/2018/11/28/compiling-deploying-and-calling-ethereum-smartcontract-using-python/) +- [Analyze Solidity Smart Contracts with Slither](https://kauri.io/#collections/DevOps/analyze-solidity-smart-contracts-with-slither/#analyze-solidity-smart-contracts-with-slither) +- [Blockchain Fintech Tutorial: Lending and Borrowing With Python](https://blog.chain.link/blockchain-fintech-defi-tutorial-lending-borrowing-python/) + +## Archived articles + +- [Deploy your own ERC20 Token with Python and Brownie](https://betterprogramming.pub/python-blockchain-token-deployment-tutorial-create-an-erc20-77a5fd2e1a58) +- [Using Brownie and Python to deploy Smart Contracts](https://dev.to/patrickalphac/using-brownie-for-to-deploy-smart-contracts-1kkp) +- [Creating NFTs on OpenSea with Brownie](https://www.freecodecamp.org/news/how-to-make-an-nft-and-render-on-opensea-marketplace/) + +## Python projects and tools + +### Active: + +- [Web3.py](https://github.com/ethereum/web3.py) - _Python library for interacting with Ethereum_ +- [Vyper](https://github.com/ethereum/vyper/) - _Pythonic Smart Contract Language for the EVM_ +- [Ape](https://github.com/ApeWorX/ape) - _The smart contract development tool for Pythonistas, Data Scientists, and Security Professionals_ +- [py-evm](https://github.com/ethereum/py-evm) - _implementation of the Ethereum Virtual Machine_ +- [eth-tester](https://github.com/ethereum/eth-tester) - _tools for testing Ethereum-based applications_ +- [eth-utils](https://github.com/ethereum/eth-utils/) - _utility functions for working with Ethereum related codebases_ +- [py-solc-x](https://pypi.org/project/py-solc-x/) - _Python wrapper around the solc solidity compiler with 0.5.x support_ +- [pymaker](https://github.com/makerdao/pymaker) - _Python API for Maker contracts_ +- [siwe](https://github.com/spruceid/siwe-py) - _Sign in with Ethereum (siwe) for Python_ +- [Web3 DeFi for Ethereum integrations](https://github.com/tradingstrategy-ai/web3-ethereum-defi) - _A Python package with ready integrations for ERC-20, Uniswap and other popular projects_ +- [Wake](https://getwake.io) - _All-in-one Python framework for contracts testing, fuzzing, deployment, vulnerability scanning and code navigation (language server - [Tools for Solidity](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity))_ + +### Archived / No longer maintained: + +- [Trinity](https://github.com/ethereum/trinity) - _Ethereum Python client_ +- [Mamba](https://github.com/arjunaskykok/mamba) - _framework to write, compile, and deploy smart contracts written in Vyper language_ +- [Brownie](https://github.com/eth-brownie/brownie) - _Python framework for deploying, testing and interacting with Ethereum smart contracts_ +- [pydevp2p](https://github.com/ethereum/pydevp2p) - _implementation of the Ethereum P2P stack_ +- [py-wasm](https://github.com/ethereum/py-wasm) - _Python implementation of the web assembly interpreter_ + +Looking for more resources? Check out [ethereum.org/developers](/developers/). + +## Projects using Python tooling + +The following Ethereum-based projects use tools mentioned on this page. The related open-source repositories serve as a good reference for example code and best practices. + +- [Yearn Finance](https://yearn.finance/) and [Yearn Vault Contracts repository](https://github.com/yearn/yearn-vaults) +- [Curve](https://www.curve.finance/) and [Curve smart contracts repository](https://github.com/curvefi/curve-contract) +- [BadgerDAO](https://badger.com/) and [smart contracts using Brownie toolchain](https://github.com/Badger-Finance/badger-system) +- [Sushi](https://sushi.com/) uses [Python in managing and deploying their vesting contracts](https://github.com/sushiswap/sushi-vesting-protocols) +- [Alpha Finance](https://alphafinance.io/), of Alpha Homora fame, uses [Brownie to test and deploy smart contracts](https://github.com/AlphaFinanceLab/alpha-staking-contract) + +## Python Community discussion + +- [Ethereum Python Community Discord](https://discord.gg/9zk7snTfWe) for Web3.py and other Python framework discussion +- [Vyper Discord](https://discord.gg/SdvKC79cJk) for Vyper smart contract programming discussion + +## Other aggregated lists + +The Vyper wiki has an [incredible list of resources for Vyper](https://github.com/vyperlang/vyper/wiki/Vyper-tools-and-resources) + +--- + +## Developers > Docs > Programming Languages > Ruby + +Learn how to develop for Ethereum using Ruby-based projects and tooling. + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustless, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Ruby with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Beginner articles + +- [Finally understanding Ethereum accounts](https://dev.to/q9/finally-understanding-ethereum-accounts-1kpe) +- [Finally Authenticating Rails Users with MetaMask](https://dev.to/q9/finally-authenticating-rails-users-with-metamask-3fj) +- [Sign-In with Ethereum - Ruby Library and Rails Examples Release](https://blog.spruceid.com/sign-in-with-ethereum-ruby-library-release-and-rails-examples/) +- [How to connect to the Ethereum network using Ruby](https://www.quicknode.com/guides/web3-sdks/how-to-connect-to-the-ethereum-network-using-ruby) +- [How to generate a new Ethereum address in Ruby](https://www.quicknode.com/guides/web3-sdks/how-to-generate-a-new-ethereum-address-in-ruby) + +## Intermediate articles + +- [Blockchain App with Ruby](https://www.nopio.com/blog/blockchain-app-ruby/) +- [Use the Ruby, connected to Ethereum, to execute the Smart Contract](https://titanwolf.org/Network/Articles/Article?AID=87285822-9b25-49d5-ba2a-7ad95fff7ef9) + +## Ruby projects and tools + +### Active + +- [eth.rb](https://github.com/q9f/eth.rb) - _Ruby library and RPC-client to handle Ethereum accounts, messages, and transactions_ +- [keccak.rb](https://github.com/q9f/keccak.rb) - _The Keccak (SHA3) hash used by Ethereum_ +- [siwe-ruby](https://github.com/spruceid/siwe-ruby) - _Ruby implementation of Sign-In with Ethereum_ +- [siwe_rails](https://github.com/spruceid/siwe_rails) - _Rails gem that adds SIWE local sign in routes_ +- [siwe-rails-examples](https://github.com/spruceid/siwe-rails-examples) - _SIWE example using Ruby on Rails with custom controller_ +- [omniauth-siwe](https://github.com/spruceid/omniauth-siwe) - _OmniAuth strategy for Sign In With Ethereum (SIWE)_ +- [omniauth-nft](https://github.com/valthon/omniauth-nft) - _OmniAuth strategy for authenticating via NFT ownership_ +- [ethereum-on-rails](https://github.com/q9f/ethereum-on-rails) - _Ethereum on Rails template which allows to connect MetaMask to Ruby on Rails_ + +### Archived / No longer maintained + +- [web3-eth](https://github.com/spikewilliams/vtada-ethereum) - _Calling RPC methods of Ethereum node with Ruby_ +- [ethereum_tree](https://github.com/longhoangwkm/ethereum_tree) - _Ruby library to generate ETH addresses from a Hierarchical Deterministic wallet according to the BIP32 standard_ +- [etherlite](https://github.com/budacom/etherlite) - _Ethereum integration for Ruby on Rails_ +- [ethereum.rb](https://github.com/EthWorks/ethereum.rb) - _Ruby Ethereum client using the JSON-RPC interface for sending transactions, creating and interacting with contracts as well as useful toolkit to work with Ethereum node_ +- [omniauth-ethereum.rb](https://github.com/q9f/omniauth-ethereum.rb) - _Implements the Ethereum provider strategy for OmniAuth_ + +Looking for more resources? Check out [our Developer's home](/developers/). + +## Ruby community contributors + +The [Ethereum Ruby Telegram group](https://t.me/ruby_eth) is a host to a rapidly growing community and is the dedicated resource for discussions on any of the above projects and related topics. + +--- + +## Developers > Docs > Programming Languages > Rust + +Learn how to develop for Ethereum using Rust-based projects and tooling + +Use Ethereum to create decentralized applications (or "dapps") that utilize the benefits of cryptocurrency and blockchain technology. These dapps can be trustworthy, meaning that once they are deployed to Ethereum, they will always run as programmed. They can control digital assets in order to create new kinds of financial applications. They can be decentralized, meaning that no single entity or person controls them and are nearly impossible to censor. + +## Getting started with smart contracts and the Solidity language + +**Take your first steps to integrating Rust with Ethereum** + +Need a more basic primer first? Check out [ethereum.org/learn](/learn/) or [ethereum.org/developers](/developers/). + +- [Blockchain Explained](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [Understanding Smart Contracts](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [Write your First Smart Contract](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) +- [Learn How to Compile and Deploy Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) + +## Beginner articles + +- [The Rust Ethereum Client](https://openethereum.github.io/) \* **Note that OpenEthereum [has been deprecated](https://medium.com/openethereum/gnosis-joins-erigon-formerly-turbo-geth-to-release-next-gen-ethereum-client-c6708dd06dd) and is no longer being maintained.** Use it with caution and preferably switch to another client implementation. +- [Sending Transaction to Ethereum Using Rust](https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/sending-ethereum-transactions-with-rust/) +- [A step-by-step tutorial on how to write contracts in rust Wasm for Kovan](https://github.com/paritytech/pwasm-tutorial) + +## Intermediate articles + +## Advanced use patterns + +- [pwasm_ethereum externs library to interact with Ethereum-like network](https://github.com/openethereum/pwasm-ethereum) +- [Build A Decentralized Chat Using JavaScript and Rust](https://medium.com/perlin-network/build-a-decentralized-chat-using-javascript-rust-webassembly-c775f8484b52) +- [Build a Decentralized Todo App Using Vue.js & Rust](https://medium.com/@jjmace01/build-a-decentralized-todo-app-using-vue-js-rust-webassembly-5381a1895beb) + +- [Build a blockchain in Rust](https://blog.logrocket.com/how-to-build-a-blockchain-in-rust/) + +## Rust projects and tools + +- [pwasm-ethereum](https://github.com/paritytech/pwasm-ethereum) - _Collection of externs to interact with ethereum-like network_ +- [Lighthouse](https://github.com/sigp/lighthouse) - _Fast Ethereum consensus layer client_ +- [Ethereum WebAssembly](https://ewasm.readthedocs.io/en/mkdocs/) - _Proposed redesign of the Ethereum smart contract execution layer using a deterministic subset of WebAssembly_ +- [oasis_std](https://docs.rs/oasis-std/latest/oasis_std/index.html) - _OASIS API reference_ +- [Solaris](https://github.com/paritytech/sol-rs) - _Solidity Smart Contracts unit test harness using the native Parity Client EVM._ +- [SputnikVM](https://github.com/rust-blockchain/evm) - _Rust Ethereum Virtual Machine Implementation_ +- [Wavelet](https://wavelet.perlin.net/docs/smart-contracts) - _Wavelet smart contract in Rust_ +- [Foundry](https://github.com/foundry-rs/foundry) - _Toolkit for Ethereum application development_ +- [Alloy](https://alloy.rs) - _High-performance, well-tested & documented libraries for interacting with Ethereum and other EVM-based chains._ +- [Ethers_rs](https://github.com/gakonst/ethers-rs) - _Ethereum library and wallet implementation_ +- [SewUp](https://github.com/second-state/SewUp) - _A library to help you build your Ethereum webassembly contract with Rust and just like develop in a common backend_ +- [Substreams](https://github.com/streamingfast/substreams) - _Parallelized blockchain data indexing technology_ +- [Reth](https://github.com/paradigmxyz/reth) Reth (short for Rust Ethereum) is a new Ethereum full-node implementation +- [Awesome Ethereum Rust](https://github.com/Vid201/awesome-ethereum-rust) - _A curated collection of projects in the Ethereum ecosystem written in Rust_ + +Looking for more resources? Check out [ethereum.org/developers.](/developers/) + +## Rust community contributors + +- [Ethereum WebAssembly](https://gitter.im/ewasm/Lobby) +- [Oasis Gitter](https://gitter.im/Oasis-official/Lobby) +- [Parity Gitter](https://gitter.im/paritytech/parity) +- [Enigma](https://discord.gg/SJK32GY) + +--- + +## Developers > Docs > Scaling + +## Scaling overview + +As the number of people using Ethereum has grown, the blockchain has reached certain capacity limitations. This has driven up the cost of using the network, creating the need for "scaling solutions." There are multiple solutions being researched, tested and implemented that take different approaches to achieve similar goals. + +The main goal of scalability is to increase transaction speed (faster finality) and transaction throughput (higher number of transactions per second) without sacrificing decentralization or security (more on the [Ethereum vision](/roadmap/vision/)). On the layer 1 Ethereum blockchain, high demand leads to slower transactions and nonviable [gas prices](/developers/docs/gas/). Increasing the network capacity in terms of speed and throughput is fundamental to the meaningful and mass adoption of Ethereum. + +While speed and throughput are important, it is essential that scaling solutions enabling these goals remain decentralized and secure. Keeping the barrier to entry low for node operators is critical in preventing a progression towards centralized and insecure computing power. + +Conceptually we first categorize scaling as either onchain scaling or offchain scaling. + +## Prerequisites + +You should have a good understanding of all the foundational topics. Implementing scaling solutions is advanced as the technology is less battle-tested, and continues to be researched and developed. + +## Onchain scaling + +Onchain scaling requires changes to the Ethereum protocol (layer 1 [Mainnet](/glossary/#mainnet)). For a long time, sharding the blockchain was expected to scale Ethereum. This was going to involve splitting the blockchain into discrete pieces (shards) to be verified by subsets of validators. However, scaling by layer-2 rollups has taken over as the primary scaling technique. This is supported by the addition of a new cheaper form of data attached to Ethereum blocks that is specially designed to make rollups cheap for users. + +### Sharding + +Sharding is the process of splitting a database. Subsets of validators would be responsible for individual shards rather than keeping track of all of Ethereum. Sharding was on the Ethereum [roadmap](/roadmap/) for a long time, and was once intended to be shipped before The Merge to proof-of-stake. However, the rapid development of [layer 2 rollups](#layer-2-scaling) and the invention of [Danksharding](/roadmap/danksharding) (adding blobs of rollup data to Ethereum blocks that can be very efficiently verified by validators) has led the Ethereum community to favour rollup-centric scaling instead of scaling by sharding. This will also help to keep Ethereum's consensus logic simpler. + +## Offchain scaling + +Offchain solutions are implemented separately from layer 1 Mainnet - they require no changes to the existing Ethereum protocol. Some solutions, known as "layer 2" solutions, derive their security directly from layer 1 Ethereum consensus, such as [optimistic rollups](/developers/docs/scaling/optimistic-rollups/), [zero-knowledge rollups](/developers/docs/scaling/zk-rollups/) or [state channels](/developers/docs/scaling/state-channels/). Other solutions involve the creation of new chains in various forms that derive their security separately from Mainnet, such as [sidechains](#sidechains), [validiums](#validium), or [plasma chains](#plasma). These solutions communicate with Mainnet but derive their security differently to obtain a variety of goals. + +### Layer 2 scaling + +This category of offchain solutions derives its security from Mainnet Ethereum. + +Layer 2 is a collective term for solutions designed to help scale your application by handling transactions off the Ethereum Mainnet (layer 1) while taking advantage of the robust decentralized security model of Mainnet. Transaction speed suffers when the network is busy, making the user experience poor for certain types of dapps. And as the network gets busier, gas prices increase as transaction senders aim to outbid each other. This can make using Ethereum very expensive. + +Most layer 2 solutions are centered around a server or cluster of servers, each of which may be referred to as a node, validator, operator, sequencer, block producer, or similar term. Depending on the implementation, these layer 2 nodes may be run by the individuals, businesses or entities that use them, or by a 3rd party operator, or by a large group of individuals (similar to Mainnet). Generally speaking, transactions are submitted to these layer 2 nodes instead of being submitted directly to layer 1 (Mainnet). For some solutions, the layer 2 instance then batches them into groups before anchoring them to layer 1, after which they are secured by layer 1 and cannot be altered. The details of how this is done vary significantly between different layer 2 technologies and implementations. + +A specific layer 2 instance may be open and shared by many applications, or may be deployed by one project and dedicated to supporting only their application. + +#### Why is layer 2 needed? + +- Increased transactions per second greatly improves user experience, and reduces network congestion on Mainnet Ethereum. +- Transactions are rolled up into a single transaction to Mainnet Ethereum, reducing gas fees for users and making Ethereum more inclusive and accessible for people everywhere. +- Any updates to scalability should not be at the expense of decentralization or security – layer 2 builds on top of Ethereum. +- There are application-specific layer 2 networks that bring their own set of efficiencies when working with assets at scale. + +[More on layer 2](/layer-2/). + +#### Rollups + +Rollups perform transaction execution outside layer 1 and then the data is posted to layer 1 where consensus is reached. As transaction data is included in layer 1 blocks, this allows rollups to be secured by native Ethereum security. + +There are two types of rollups with different security models: + +- **Optimistic rollups**: assumes transactions are valid by default and only runs computation, via a [**fraud proof**](/glossary/#fraud-proof), in the event of a challenge. [More on Optimistic rollups](/developers/docs/scaling/optimistic-rollups/). +- **Zero-knowledge rollups**: runs computation offchain and submits a [**validity proof**](/glossary/#validity-proof) to the chain. [More on zero-knowledge rollups](/developers/docs/scaling/zk-rollups/). + +#### State channels + +State channels utilize multisig contracts to enable participants to transact quickly and freely offchain, then settle finality with Mainnet. This minimizes network congestion, fees, and delays. The two types of channels are currently state channels and payment channels. + +Learn more about [state channels](/developers/docs/scaling/state-channels/). + +### Sidechains + +A sidechain is an independent EVM-compatible blockchain that runs in parallel to Mainnet. These are compatible with Ethereum via two-way bridges and run under their own chosen rules of consensus and block parameters. + +Learn more about [Sidechains](/developers/docs/scaling/sidechains/). + +### Plasma + +A plasma chain is a separate blockchain that is anchored to the main Ethereum chain and uses fraud proofs (like [optimistic rollups](/developers/docs/scaling/optimistic-rollups/)) to arbitrate disputes. + +Learn more about [Plasma](/developers/docs/scaling/plasma/). + +### Validium + +A Validium chain uses validity proofs like zero-knowledge rollups but data is not stored on the main layer 1 Ethereum chain. This can lead to 10k transactions per second per Validium chain and multiple chains can be run in parallel. + +Learn more about [Validium](/developers/docs/scaling/validium/). + +## Why are so many scaling solutions needed? + +- Multiple solutions can help reduce the overall congestion on any one part of the network and also prevent single points of failure. +- The whole is greater than the sum of its parts. Different solutions can exist and work in harmony, allowing for an exponential effect on future transaction speed and throughput. +- Not all solutions require utilizing the Ethereum consensus algorithm directly, and alternatives can offer benefits that would otherwise be difficult to obtain. +- No one scaling solution is enough to fulfill the [Ethereum vision](/roadmap/vision/). + +## More of a visual learner? + + + +_Note the explanation in the video uses the term "Layer 2" to refer to all offchain scaling solutions, while we differentiate "Layer 2" as an offchain solution that derives its security through layer 1 Mainnet consensus._ + + + +## Further reading + +- [A rollup-centric Ethereum roadmap](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698) _Vitalik Buterin_ +- [Up-to-date analytics on Layer 2 scaling solutions for Ethereum](https://www.l2beat.com/) +- [Evaluating Ethereum layer 2 Scaling Solutions: A Comparison Framework](https://medium.com/matter-labs/evaluating-ethereum-l2-scaling-solutions-a-comparison-framework-b6b2f410f955) +- [An Incomplete Guide to Rollups](https://vitalik.eth.limo/general/2021/01/05/rollup.html) +- [Ethereum-powered ZK-Rollups: World Beaters](https://hackmd.io/@canti/rkUT0BD8K) +- [Optimistic Rollups vs ZK Rollups](https://limechain.tech/blog/optimistic-rollups-vs-zk-rollups/) +- [Zero-Knowledge Blockchain Scalability](https://www.archblock.com/poland/assets/download/zero-knowledge-blockchain-scaling-ethworks.pdf) +- [Why rollups + data shards are the only sustainable solution for high scalability](https://polynya.medium.com/why-rollups-data-shards-are-the-only-sustainable-solution-for-high-scalability-c9aabd6fbb48) +- [What kind of Layer 3s make sense?](https://vitalik.eth.limo/general/2022/09/17/layer_3.html) +- [Data Availability Or: How Rollups Learned To Stop Worrying And Love Ethereum](https://research.2077.xyz/data-availability-or-how-rollups-learned-to-stop-worrying-and-love-ethereum) +- [The Practical Guide to Ethereum Rollups](https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Scaling > Optimistic Rollups + +Optimistic rollups are layer 2 (L2) protocols designed to extend the throughput of Ethereum's base layer. They reduce computation on the main Ethereum chain by processing transactions offchain, offering significant improvements in processing speeds. Unlike other scaling solutions, such as [sidechains](/developers/docs/scaling/sidechains/), optimistic rollups derive security from Mainnet by publishing transaction results onchain, or [plasma chains](/developers/docs/scaling/plasma/), which also verify transactions on Ethereum with fraud proofs, but store transaction data elsewhere. + +As computation is the slow, expensive part of using Ethereum, optimistic rollups can offer up to 10-100x improvements in scalability. Optimistic rollups also write transactions to Ethereum as `calldata` or in [blobs](/roadmap/danksharding/), reducing gas costs for users. + +## Prerequisites + +You should have read and understood our pages on [Ethereum scaling](/developers/docs/scaling/) and [layer 2](/layer-2/). + +## What is an optimistic rollup? + +An optimistic rollup is an approach to scaling Ethereum that involves moving computation and state storage offchain. Optimistic rollups execute transactions outside of Ethereum, but post transaction data to Mainnet as `calldata` or in [blobs](/roadmap/danksharding/). + +Optimistic rollup operators bundle multiple offchain transactions together in large batches before submitting to Ethereum. This approach enables spreading fixed costs across multiple transactions in each batch, reducing fees for end-users. Optimistic rollups also use compression techniques to reduce the amount of data posted on Ethereum. + +Optimistic rollups are considered “optimistic” because they assume offchain transactions are valid and don't publish proofs of validity for transaction batches posted onchain. This separates optimistic rollups from [zero-knowledge rollups](/developers/docs/scaling/zk-rollups) that publish cryptographic [proofs of validity](/glossary/#validity-proof) for offchain transactions. + +Optimistic rollups instead rely on a fraud-proving scheme to detect cases where transactions are not calculated correctly. After a rollup batch is submitted on Ethereum, there's a time window (called a challenge period) during which anyone can challenge the results of a rollup transaction by computing a [fraud proof](/glossary/#fraud-proof). + +If the fraud proof succeeds, the rollup protocol re-executes the transaction(s) and updates the rollup's state accordingly. The other effect of a successful fraud proof is that the sequencer responsible for including the incorrectly executed transaction in a block receives a penalty. + +If the rollup batch remains unchallenged (i.e., all transactions are correctly executed) after the challenge period elapses, it is deemed valid and accepted on Ethereum. Others can continue to build on an unconfirmed rollup block, but with a caveat: transaction results will be reversed if based on an incorrectly executed transaction published previously. + +## How do optimistic rollups interact with Ethereum? + +Optimistic rollups are [offchain scaling solutions](/developers/docs/scaling/#offchain-scaling) built to operate on top of Ethereum. Each optimistic rollup is managed by a set of smart contracts deployed on the Ethereum network. Optimistic rollups process transactions off the main Ethereum chain, but post offchain transactions (in batches) to an onchain rollup contract. Like the Ethereum blockchain, this transaction record is immutable and forms the "optimistic rollup chain." + +The architecture of an optimistic rollup comprises the following parts: + +**Onchain contracts**: The optimistic rollups's operation is controlled by smart contracts running on Ethereum. This includes contracts that store rollup blocks, monitor state updates on the rollup, and track user deposits. In this sense, Ethereum serves as the base layer or "layer 1" for optimistic rollups. + +**Offchain virtual machine (VM)**: Although contracts managing the optimistic rollup protocol run on Ethereum, the rollup protocol performs computation and state storage on another virtual machine separate from the [Ethereum Virtual Machine](/developers/docs/evm/). The offchain VM is where applications live and state changes are executed; it serves as the upper layer or "layer 2" for an optimistic rollup. + +As optimistic rollups are designed to run programs either written or compiled for the EVM, the offchain VM incorporates many EVM design specs. Additionally, fraud proofs computed onchain allows the Ethereum network to enforce the validity of state changes computed in the offchain VM. + +Optimistic rollups are described as 'hybrid scaling solutions' because, while they exist as separate protocols, their security properties are derived from Ethereum. Among other things, Ethereum guarantees the correctness of a rollup’s offchain computation and the availability of data behind the computation. This makes optimistic rollups more secure than pure offchain scaling protocols (e.g., [sidechains](/developers/docs/scaling/sidechains/)) that do not rely on Ethereum for security. + +Optimistic rollups rely on the main Ethereum protocol for the following: + +### Data availability + +As mentioned, optimistic rollups post transaction data to Ethereum as `calldata` or [blobs](/roadmap/danksharding/). Since the rollup chain's execution is based on submitted transactions, anyone can use this information—anchored on Ethereum’s base layer—to execute the rollup’s state and verify the correctness of state transitions. + +[Data availability](/developers/docs/data-availability/) is critical because without access to state data, challengers cannot construct fraud proofs to dispute invalid rollup operations. With Ethereum providing data availability, the risk of rollup operators getting away with malicious acts (e.g., submitting invalid blocks) is reduced. + +### Censorship resistance + +Optimistic rollups also rely on Ethereum for censorship resistance. In an optimistic rollup a centralized entity (the operator) is responsible for processing transactions and submitting rollup blocks to Ethereum. This has some implications: + +- Rollup operators can censor users by going offline completely, or by refusing to either produce blocks that include certain transactions in them. + +- Rollup operators can prevent users from withdrawing funds deposited in the rollup contract by withholding state data necessary to Merkle proofs of ownership. Withholding state data can also conceal the rollup’s state from users and prevent them from interacting with the rollup. + +Optimistic rollups solve this problem by forcing operators to publish data associated with state updates on Ethereum. Publishing rollup data onchain has the following benefits: + +- If an optimistic rollup operator goes offline or stops producing transaction batches, another node can use available data to reproduce the rollup’s last state and continue block production. + +- Users can use transaction data to create Merkle proofs proving ownership of funds and withdraw their assets from the rollup. + +- Users can also submit their transactions on L1 instead of to the sequencer, in which case the sequencer has to include the transaction within a certain time limit to continue to produce valid blocks. + +### Settlement + +Another role Ethereum plays in the context of optimistic rollups is that of a settlement layer. A settlement layer anchors the entire blockchain ecosystem, establishes security, and provides objective finality if a dispute occurs on another chain (optimistic rollups in this case) that requires arbitration. + +Ethereum Mainnet provides a hub for optimistic rollups to verify fraud proofs and resolve disputes. Moreover, transactions conducted on the rollup are only final _after_ the rollup block is accepted on Ethereum. Once a rollup transaction is committed to Ethereum’s base layer, it cannot be rolled back (except in the highly unlikely case of a chain reorganization). + +## How do optimistic rollups work? + +### Transaction execution and aggregation + +Users submit transactions to “operators”, which are nodes responsible for processing transactions on the optimistic rollup. Also known as a “validator” or “aggregator”, the operator aggregates transactions, compresses the underlying data, and publishes the block on Ethereum. + +Although anyone can become a validator, optimistic rollup validators must provide a bond before producing blocks, much like a [proof-of-stake system](/developers/docs/consensus-mechanisms/pos/). This bond can be slashed if the validator posts an invalid block or builds on an old-but-invalid block (even if their block is valid). This way optimistic rollups utilize cryptoeconomic incentives to ensure validators act honestly. + +Other validators on the optimistic rollup chain are expected to execute the submitted transactions using their copy of the rollup’s state. If a validator’s final state is different from the operator’s proposed state, they can start a challenge and compute a fraud proof. + +Some optimistic rollups may forgo a permissionless validator system and use a single “sequencer” to execute the chain. Like a validator, the sequencer processes transactions, produces rollup blocks, and submits rollup transactions to the L1 chain (Ethereum). + +The sequencer is different from a regular rollup operator because they have greater control over the ordering of transactions. Also, the sequencer has priority access to the rollup chain and is the only entity authorized to submit transactions to the onchain contract. Transactions from non-sequencer nodes or regular users are simply queued up in a separate inbox until the sequencer includes them in a new batch. + +#### Submitting rollup blocks to Ethereum + +As mentioned, the operator of an optimistic rollup bundles offchain transactions into a batch and sends it to Ethereum for notarization. This process involves compressing transaction-related data and publishing it on Ethereum as `calldata` or in blobs. + +`calldata` is a non-modifiable, non-persistent area in a smart contract that behaves mostly like [memory](/developers/docs/smart-contracts/anatomy/#memory). While `calldata` persists onchain as part of the blockchain's [history logs](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs), it is not stored as a part of Ethereum's state. Because `calldata` does not touch any part of Ethereum's state, it is cheaper than state for storing data onchain. + +The `calldata` keyword is also used in Solidity to pass arguments to a smart contract function at execution time. `calldata` identifies the function being called during a transaction and holds inputs to the function in the form of an arbitrary sequence of bytes. + +In the context of optimistic rollups, `calldata` is used to send compressed transaction data to the onchain contract. The rollup operator adds a new batch by calling the required function in the rollup contract and passing the compressed data as function arguments. Using `calldata` reduces user fees since most costs that rollups incur come from storing data onchain. + +Here is [an example](https://etherscan.io/tx/0x9102bfce17c58b5fc1c974c24b6bb7a924fb5fbd7c4cd2f675911c27422a5591) of a rollup batch submission to show how this concept works. The sequencer invoked the `appendSequencerBatch()` method and passed the compressed transaction data as inputs using `calldata`. + +Some rollups now use blobs to post batches of transactions to Ethereum. + +Blobs are non-modifiable and non-persistent (just like `calldata`) but are pruned from history after ~18 days. For more information on blobs, see [Danksharding](/roadmap/danksharding). + +### State commitments + +At any point in time, the optimistic rollup’s state (accounts, balances, contract code, etc.) is organized as a [Merkle tree](/whitepaper/#merkle-trees) called a “state tree”. The root of this Merkle tree (state root), which references the rollup’s latest state, is hashed and stored in the rollup contract. Every state transition on the chain produces a new rollup state, which an operator commits to by computing a new state root. + +The operator is required to submit both old state roots and new state roots when posting batches. If the old state root matches the existing state root in the onchain contract, the latter is discarded and replaced with the new state root. + +The rollup operator is also required to commit a Merkle root for the transaction batch itself. This allows anyone to prove the inclusion of a transaction in the batch (on L1) by presenting a [Merkle proof](/developers/tutorials/merkle-proofs-for-offline-data-integrity/). + +State commitments, especially state roots, are necessary for proving the correctness of state changes in an optimistic rollup. The rollup contract accepts new state roots from operators immediately after they are posted, but can later delete invalid state roots to restore the rollup to its correct state. + +### Fraud proving + +As explained, optimistic rollups allow anyone to publish blocks without providing proofs of validity. However, to ensure the chain remains safe, optimistic rollups specify a time window during which anyone can dispute a state transition. Hence, rollup blocks are called “assertions” since anyone can dispute their validity. + +If someone disputes an assertion, then the rollup protocol will initiate the fraud proof computation. Every type of fraud proof is interactive—someone must post an assertion before another person can challenge it. The difference lies in how many rounds of interaction are required to compute the fraud proof. + +Single-round interactive proving schemes replay disputed transactions on L1 to detect invalid assertions. The rollup protocol emulates the re-execution of the disputed transaction on L1 (Ethereum) using a verifier contract, with the computed state root determining who wins the challenge. If the challenger's claim about the rollup’s correct state is correct, the operator is penalized by having their bond slashed. + +However, re-executing transactions on L1 to detect fraud requires publishing state commitments for individual transactions and increases the data rollups must publish onchain. Replaying transactions also incurs significant gas costs. For these reasons, optimistic rollups are switching to multi-round interactive proving, which achieves the same objective (i.e., detecting invalid rollup operations) with more efficiency. + +#### Multi-round interactive proving + +Multi-round interactive proving involves a back-and-forth protocol between the asserter and challenger overseen by an L1 verifier contract, which ultimately decides the lying party. After an L2 node challenges an assertion, the asserter is required to divide the disputed assertion into two equal halves. Each individual assertion in this case will contain as many steps of computation as the other. + +The challenger will then choose what assertion it wants to challenge. The dividing process (called a “bisection protocol”) continues until both parties are disputing an assertion about a _single_ step of execution. At this point, the L1 contract will resolve the dispute by evaluating the instruction (and its result) to catch the fraudulent party. + +The asserter is required to provide a “one-step proof” verifying the validity of the disputed single-step computation. If the asserter fails to provide the one-step proof, or the L1 verifier deems the proof invalid, they lose the challenge. + +Some notes about this type of fraud proof: + +1. Multi-round interactive fraud proving is considered efficient because it minimizes the work the L1 chain must do in dispute arbitration. Instead of replaying the entire transaction, the L1 chain only needs to re-execute one step in the rollup's execution. + +2. Bisection protocols reduce the amount of data posted onchain (no need to publish state commits for every transaction). Also, optimistic rollup transactions are not constrained by Ethereum's gas limit. Conversely, optimistic rollups re-executing transactions must make sure an L2 transaction has a lower gas limit to emulate its execution within a single Ethereum transaction. + +3. Part of the malicious asserter's bond is awarded to the challenger, while the other part is burned. The burning prevents collusion among validators; if two validators collude to initiate bogus challenges, they will still forfeit a considerable chunk of the entire stake. + +4. Multi-round interactive proving requires both parties (the asserter and the challenger) to make moves within the specified time window. Failure to act before the deadline expires causes the defaulting party to forfeit the challenge. + +#### Why fraud proofs matter for optimistic rollups + +Fraud proofs are important because they facilitate _trustless finality_ in optimistic rollups. Trustless finality is a quality of optimistic rollups that guarantees that a transaction—so long as it’s valid—will eventually be confirmed. + +Malicious nodes can try to delay the confirmation of a valid rollup block by starting false challenges. However, fraud proofs will eventually prove the rollup block’s validity and cause it to be confirmed. + +This also relates to another security property of optimistic rollups: the validity of the chain relies on the existence of _one_ honest node. The honest node can advance the chain correctly by either posting valid assertions or disputing invalid assertions. Whatever the case, malicious nodes who enter into disputes with the honest node will lose their stakes during the fraud proving process. + +### L1/L2 interoperability + +Optimistic rollups are designed for interoperability with Ethereum Mainnet and allow users to pass messages and arbitrary data between L1 and L2. They are also compatible with the EVM, so you can port existing [dapps](/developers/docs/dapps/) to optimistic rollups or create new dapps using Ethereum development tools. + +#### 1. Asset movement + +##### Entering the rollup + +To use an optimistic rollup, users deposit ETH, ERC-20 tokens, and other accepted assets in the rollup’s [bridge](/developers/docs/bridges/) contract on L1. The bridge contract will relay the transaction to L2, where an equivalent amount of assets is minted and sent to the user’s chosen address on the optimistic rollup. + +User-generated transactions (like an L1 > L2 deposit) are usually queued until the sequencer re-submits them to the rollup contract. However, to preserve censorship resistance, optimistic rollups allow users to submit a transaction directly to the onchain rollup contract if it has been delayed past the maximum time allowed. + +Some optimistic rollups adopt a more straightforward approach to prevent sequencers from censoring users. Here, a block is defined by all transactions submitted to the L1 contract since the previous block (e.g., deposits) in addition to the transactions processed on the rollup chain. If a sequencer ignores an L1 transaction, it will publish the (provably) wrong state root; therefore, sequencers cannot delay user-generated messages once posted on L1. + +##### Exiting the rollup + +Withdrawing from an optimistic rollup to Ethereum is more difficult owing to the fraud proving scheme. If a user initiates an L2 > L1 transaction to withdraw funds escrowed on L1, they must wait until the challenge period—lasting roughly seven days—elapses. Nevertheless, the withdrawal process itself is fairly straightforward. + +After the withdrawal request is initiated on the L2 rollup, the transaction is included in the next batch, while the user’s assets on the rollup are burned. Once the batch is published on Ethereum, the user can compute a Merkle proof verifying the inclusion of their exit transaction in the block. Then it is a matter of waiting through the delay period to finalize the transaction on L1 and withdraw funds to Mainnet. + +To avoid waiting a week before withdrawing funds to Ethereum, optimistic rollup users can employ a **liquidity provider** (LP). A liquidity provider assumes ownership of a pending L2 withdrawal and pays the user on L1 (in exchange for a fee). + +Liquidity providers can check the validity of the user’s withdrawal request (by executing the chain themselves) before releasing funds. This way they have assurances that the transaction will be confirmed eventually (i.e., trustless finality). + +#### 2. EVM compatibility + +For developers, the advantage of optimistic rollups is their compatibility—or, better still, equivalence—with the [Ethereum Virtual Machine (EVM)](/developers/docs/evm/). EVM-compatible rollups comply with specifications in the [Ethereum Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) and support the EVM at the bytecode level. + +EVM-compatibility in optimistic rollups has the following benefits: + +i. Developers can migrate existing smart contracts on Ethereum to optimistic rollup chains without having to modify codebases extensively. This can save development teams time when deploying Ethereum smart contracts on L2. + +ii. Developers and project teams using optimistic rollups can take advantage of Ethereum's infrastructure. This includes programming languages, code libraries, testing tools, client software, deployment infrastructure, and so on. + +Using existing tooling is important because these tools have been extensively audited, debugged, and improved over the years. It also removes the need for Ethereum developers to learn how to build with an entirely new development stack. + +#### 3. Cross-chain contract calls + +Users (externally owned accounts) interact with L2 contracts by submitting a transaction to the rollup contract or having a sequencer or validator do it for them. Optimistic rollups also allow contract accounts on Ethereum to interact with L2 contracts using bridging contracts to relay messages and pass data between L1 and L2. This means you can program an L1 contract on Ethereum Mainnet to invoke functions belonging to contracts on an L2 optimistic rollup. + +Cross-chain contract calls happen asynchronously—meaning the call is initiated first, then executed at a later time. This is different from calls between the two contracts on Ethereum, where the call produces results immediately. + +An example of a cross-chain contract call is the token deposit described earlier. A contract on L1 escrows the user's tokens and sends a message to a paired L2 contract to mint an equal amount of tokens on the rollup. + +As cross-chain message calls result in contract execution, the sender is usually required to cover [gas costs](/developers/docs/gas/) for computation. It is advisable to set a high gas limit to prevent the transaction from failing on the target chain. The token bridging scenario is a good example; if the L1 side of the transaction (depositing the tokens) works, but the L2 side (minting new tokens) fails due to low gas, the deposit becomes irrecoverable. + +Finally, we should note that L2 > L1 message calls between contracts need to account for delays (L1 > L2 calls are typically executed after some minutes). This is because messages sent to Mainnet from the optimistic rollup cannot be executed until the challenge window expires. + +## How do optimistic rollup fees work? + +Optimistic rollups use a gas fee scheme, much like Ethereum, to denote how much users pay per transaction. Fees charged on optimistic rollups depends on the following components: + +1. **State write**: Optimistic rollups publish transaction data and block headers (consisting of the previous block header hash, state root, batch root) to Ethereum as a `blob`, or "binary large object". [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) introduced a cost-effective solution for including data onchain. A `blob` is a new transaction field that allows rollups to post compressed state transition data to Ethereum L1. Unlike `calldata`, which remains permanently onchain, blobs are short-lived and can be pruned from clients after [4096 epochs](https://github.com/ethereum/consensus-specs/blob/81f3ea8322aff6b9fb15132d050f8f98b16bdba4/configs/mainnet.yaml#L147) (approximately 18 days). By using blobs to post batches of compressed transactions, optimistic rollups can significantly reduce the cost of writing transactions to L1. + +2. **Blob gas used**: Blob-carrying transactions employ a dynamic fee mechanism similar to the one introduced by [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559). The gas fee for type-3 transactions takes into account the base fee for blobs, which is determined by the network based on blob-space demand and the blob-space usage of the transaction being sent. + +3. **L2 operator fees**: This is the amount paid to the rollup nodes as compensation for computational costs incurred in processing transactions, much like gas fees on Ethereum. Rollup nodes charge lower transaction fees since L2s have higher processing capacities and aren't faced with the network congestions that force validators on Ethereum to prioritize transactions with higher fees. + +Optimistic rollups apply several mechanisms to reducing fees for users, including batching transactions and compressing `calldata` to reduce data publication costs. You can check the [L2 fee tracker](https://l2fees.info/) for a real-time overview of how much it costs to use Ethereum-based optimistic rollups. + +## How do optimistic rollups scale Ethereum? + +As explained, optimistic rollups publish compressed transaction data on Ethereum to guarantee data availability. The ability to compress data published onchain is crucial to scaling throughput on Ethereum with optimistic rollups. + +The main Ethereum chain places limits on how much data blocks can hold, denominated in gas units (the [average block size](/developers/docs/blocks/#block-size) is 15 million gas). While this restricts how much gas each transaction can use, it also means we can increase transactions processed per block by reducing transaction-related data—directly improving scalability. + +Optimistic rollups use several techniques to achieve transaction data compression and improve TPS rates. For example, this [article](https://vitalik.eth.limo/general/2021/01/05/rollup.html) compares the data a basic user transaction (sending ether) generates on Mainnet vs how much data the same transaction generates on a rollup: + +| Parameter | Ethereum (L1) | Rollup (L2) | +| --------- | ---------------------- | ------------- | +| Nonce | ~3 | 0 | +| Gasprice | ~8 | 0-0.5 | +| Gas | 3 | 0-0.5 | +| To | 21 | 4 | +| Value | 9 | ~3 | +| Signature | ~68 (2 + 33 + 33) | ~0.5 | +| From | 0 (recovered from sig) | 4 | +| **Total** | **~112 bytes** | **~12 bytes** | + +Doing some rough calculations on these figures can help show the scalability improvements afforded by an optimistic rollup: + +1. The target size for every block is 15 million gas and it costs 16 gas to verify one byte of data. Dividing the average block size by 16 gas (15,000,000/16) shows the average block can hold **937,500 bytes of data**. +2. If a basic rollup transaction uses 12 bytes, then the average Ethereum block can process **78,125 rollup transactions** (937,5000/12) or **39 rollup batches** (if each batch holds an average of 2,000 transactions). +3. If a new block is produced on Ethereum every 15 seconds, then the rollup's processing speeds would amount to roughly **5,208 transactions per second**. This is done by dividing the number of basic rollup transactions an Ethereum block can hold (**78,125**) by the average block time (**15 seconds**). + +This is a fairly optimistic estimate, given that optimistic rollup transactions cannot possibly comprise an entire block on Ethereum. However, it can give a rough idea of how much scalability gains that optimistic rollups can afford Ethereum users (current implementations offer up to 2,000 TPS). + +The introduction of [data sharding](/roadmap/danksharding/) on Ethereum is expected to improve scalability in optimistic rollups. Because rollup transactions must share blockspace with other non-rollup transactions, their processing capacity is limited by data throughput on the main Ethereum chain. Danksharding will increase the space available to L2 chains to publish data per block, using cheaper, impermanent "blob" storage instead of expensive, permanent `CALLDATA`. + +### Pros and cons of optimistic rollups + +| Pros | Cons | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Offers massive improvements in scalability without sacrificing security or trustlessness. | Delays in transaction finality due to potential fraud challenges. | +| Transaction data is stored on the layer 1 chain, improving transparency, security, censorship-resistance, and decentralization. | Centralized rollup operators (sequencers) can influence transaction ordering. | +| Fraud proving guarantees trustless finality and allows honest minorities to secure the chain. | If there are no honest nodes a malicious operator can steal funds by posting invalid blocks and state commitments. | +| Computing fraud proofs is open to regular L2 node, unlike validity proofs (used in ZK-rollups) that require special hardware. | Security model relies on at least one honest node executing rollup transactions and submitting fraud proofs to challenge invalid state transitions. | +| Rollups benefit from "trustless liveness" (anyone can force the chain to advance by executing transactions and posting assertions) | Users must wait for the one-week challenge period to expire before withdrawing funds back to Ethereum. | +| Optimistic rollups rely on well-designed cryptoeconomic incentives to increase security on the chain. | Rollups must post all transaction data onchain, which can increase costs. | +| Compatibility with EVM and Solidity allows developers to port Ethereum-native smart contracts to rollups or use existing tooling to create new dapps. | + +### A visual explanation of optimistic rollups + +More of a visual learner? Watch Finematics explain optimistic rollups: + + + +## Further reading on optimistic rollups + +- [How do optimistic rollups work (The Complete guide)](https://www.alchemy.com/overviews/optimistic-rollups) +- [What is a Blockchain Rollup? A Technical Introduction](https://www.ethereum-ecosystem.com/blog/what-is-a-blockchain-rollup-a-technical-introduction) +- [The Essential Guide to Arbitrum](https://www.bankless.com/the-essential-guide-to-arbitrum) +- [The Practical Guide To Ethereum Rollups](https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) +- [The State Of Fraud Proofs In Ethereum L2s](https://research.2077.xyz/the-state-of-fraud-proofs-in-ethereum-l2s) +- [How does Optimism's Rollup really work?](https://www.paradigm.xyz/2021/01/how-does-optimism-s-rollup-really-work) +- [OVM Deep Dive](https://medium.com/ethereum-optimism/ovm-deep-dive-a300d1085f52) +- [What is the Optimistic Virtual Machine?](https://www.alchemy.com/overviews/optimistic-virtual-machine) + +--- + +## Developers > Docs > Scaling > Plasma + +A Plasma chain is a separate blockchain anchored to Ethereum Mainnet but executing transactions offchain with its own mechanism for block validation. Plasma chains are sometimes referred to as "child" chains, essentially smaller copies of the Ethereum Mainnet. Plasma chains use [fraud proofs](/glossary/#fraud-proof) (like [optimistic rollups](/developers/docs/scaling/optimistic-rollups/)) to arbitrate disputes. + +Merkle trees enable the creation of an endless stack of these chains that can work to offload bandwidth from parent chains (including Ethereum Mainnet). However, while these chains derive some security from Ethereum (via fraud proofs), their security and efficiency are affected by several design limitations. + +## Prerequisites + +You should have a good understanding of all the foundational topics and a high-level understanding of [Ethereum scaling](/developers/docs/scaling/). + +## What is Plasma? + +Plasma is a framework for improving scalability in public blockchains like Ethereum. As described in the original [Plasma whitepaper](http://plasma.io/plasma.pdf), Plasma chains are built atop another blockchain (called a "root chain"). Each "child chain" extends from the root chain and is generally managed by a smart contract deployed on the parent chain. + +The Plasma contract functions, among other things, as a [bridge](/developers/docs/bridges/) allowing users to move assets between Ethereum Mainnet and the plasma chain. Although this makes them similar to [sidechains](/developers/docs/scaling/sidechains/), plasma chains benefit—at least, to some extent—from Ethereum Mainnet's security. This is unlike sidechains that are solely responsible for their security. + +## How does Plasma work? + +The basic components of the Plasma framework are: + +### Offchain computation + +Ethereum's current processing speed is limited to ~ 15-20 transactions per second, reducing the short-term possibility of scaling to handle more users. This problem exists mainly because Ethereum's [consensus mechanism](/developers/docs/consensus-mechanisms/) requires many peer-to-peer nodes to verify every update to the blockchain's state. + +Although Ethereum's consensus mechanism is necessary for security, it may not apply to every use case. For example, Alice may not need her daily payments to Bob for a cup of coffee verified by the entire Ethereum network since some trust exists between both parties. + +Plasma supposes that Ethereum Mainnet doesn't need to verify all transactions. Instead, we can process transactions off Mainnet, freeing nodes from having to validate every transaction. + +Offchain computation is necessary since Plasma chains can optimize for speed and cost. For example, a Plasma chain may—and most often does—use a single "operator" to manage the ordering and execution of transactions. With just one entity verifying transactions, processing times on a plasma chain are faster than Ethereum Mainnet. + +### State commitments + +While Plasma executes transactions offchain, they are settled on the main Ethereum execution layer—otherwise, Plasma chains cannot benefit from Ethereum's security guarantees. But finalizing offchain transactions without knowing the state of the plasma chain would break the security model and allow the proliferation of invalid transactions. This is why the operator, the entity responsible for producing blocks on the plasma chain, is required to publish "state commitments" on Ethereum periodically. + +A [commitment scheme](https://en.wikipedia.org/wiki/Commitment_scheme) is a cryptographic technique for committing to a value or statement without revealing it to another party. Commitments are "binding" in the sense that you cannot change the value or statement once you've committed to it. State commitments in Plasma take the form of "Merkle roots" (derived from a [Merkle tree](/whitepaper/#merkle-trees)) which the operator sends at intervals to the Plasma contract on the Ethereum chain. + +Merkle roots are cryptographic primitives that enable compressing of large amounts of information. A Merkle root (also called a "block root" in this case) could represent all the transactions in a block. Merkle roots also make it easier to verify that a small piece of data is part of the larger dataset. For instance, a user can produce a [Merkle proof](/developers/tutorials/merkle-proofs-for-offline-data-integrity/#main-content) to prove the inclusion of a transaction in a specific block. + +Merkle roots are important for providing information about the offchain's state to Ethereum. You can think of Merkle roots as "save points": the operator is saying, "This is the state of the Plasma chain at x point in time, and this is the Merkle root as proof." The operator is committing to the _current state_ of the plasma chain with a Merkle root, which is why it is called a "state commitment". + +### Entries and exits + +For Ethereum users to take advantage of Plasma, there needs to be a mechanism for moving funds between Mainnet and plasma chains. We cannot arbitrarily send ether to an address on the plasma chain, though—these chains are incompatible, so the transaction would either fail or lead to lost funds. + +Plasma uses a master contract running on Ethereum to process user entries and exits. This master contract is also responsible for tracking state commitments (explained earlier) and punishing dishonest behavior via fraud proofs (more on this later). + +#### Entering the plasma chain + +To enter the plasma chain, Alice (the user) will have to deposit ETH or any ERC-20 token in the plasma contract. The plasma operator, who watches contract deposits, recreates an amount equal to Alice's initial deposit and releases it to her address on the plasma chain. Alice is required to attest to receiving the funds on the child chain and can then use these funds for transactions. + +#### Exiting the plasma chain + +Exiting the plasma chain is more complex than entering it for several reasons. The biggest one is that, while Ethereum has information about the plasma chain's state, it cannot verify if the information is true or not. A malicious user could make an incorrect assertion ("I have 1000 ETH") and get away with providing fake proofs to back up the claim. + +To prevent malicious withdrawals, a "challenge period" is introduced. During the challenge period (usually a week), anyone can challenge a withdrawal request using a fraud-proof. If the challenge succeeds, then the withdrawal request is denied. + +However, it is usually the case that users are honest and make correct claims about the funds they own. In this scenario, Alice will initiate a withdrawal request on the root chain (Ethereum) by submitting a transaction to the plasma contract. + +She must also provide a Merkle proof verifying that a transaction creating her funds on the Plasma chain was included in a block. This is necessary for iterations of Plasma, such as [Plasma MVP](https://www.learnplasma.org/en/learn/mvp.html), that use a [Unspent Transaction Output (UTXO)](https://en.wikipedia.org/wiki/Unspent_transaction_output) model. + +Others, like [Plasma Cash](https://www.learnplasma.org/en/learn/cash.html), represent funds as [non-fungible tokens](/developers/docs/standards/tokens/erc-721/) instead of UTXOs. Withdrawing, in this case, requires proof of ownership of tokens on the Plasma chain. This is done by submitting the two latest transactions involving the token and providing a Merkle proof verifying the inclusion of those transactions in a block. + +The user must also add a bond to the withdrawal request as a guarantee of honest behavior. If a challenger proves Alice's withdrawal request invalid, her bond is slashed, and some of it goes to the challenger as a reward. + +If the challenge period elapses without anyone providing a fraud-proof, Alice's withdrawal request is considered valid, allowing her to retrieve deposits from the Plasma contract on Ethereum. + +### Dispute arbitration + +Like any blockchain, plasma chains need a mechanism for enforcing the integrity of transactions in case participants act maliciously (e.g. double-spending funds). To this end, plasma chains use fraud proofs to arbitrate disputes concerning the validity of state transitions and penalize bad behavior. Fraud proofs are used as a mechanism through which a Plasma child chain files a complaint to its parent chain or to the root chain. + +A fraud-proof is simply a claim that a particular state transition is invalid. An example is if a user (Alice) tries to spend the same funds twice. Perhaps she spent the UTXO in a transaction with Bob and wants to spend the same UTXO (which is now Bob's) in another transaction. + +To prevent the withdrawal, Bob will construct a fraud-proof by providing evidence of Alice spending the said UTXO in a previous transaction and a Merkle proof of the transaction's inclusion in a block. The same process works in Plasma Cash—Bob would need to provide proof that Alice earlier transferred the tokens she's trying to withdraw. + +If Bob's challenge succeeds, Alice's withdrawal request is canceled. However, this approach relies on Bob's ability to watch the chain for withdrawal requests. If Bob is offline, then Alice can process the malicious withdrawal once the challenge period elapses. + +## The mass exit problem in plasma + +The mass exit problem occurs when a large number of users try to withdraw from a plasma chain at the same time. Why this problem exists has to do with one of Plasma's biggest problems: **data unavailability**. + +Data availability is the ability to verify that the information for a proposed block was actually published on the blockchain network. A block is "unavailable" if the producer publishes the block itself but withholds data used to create the block. + +Blocks must be available if nodes are to be able to download the block and verify the validity of transactions. Blockchains ensure data availability by forcing block producers to post all transaction data onchain. + +Data availability also helps with securing offchain scaling protocols that build on Ethereum's base layer. By forcing operators on these chains to publish transaction data on Ethereum, anyone can challenge invalid blocks by constructing fraud proofs referencing the correct state of the chain. + +Plasma chains primarily store transaction data with the operator and **do not publish any data on Mainnet** (i.e., besides periodic state commitments). This means users must rely on the operator to provide block data if they need to create fraud proofs challenging invalid transactions. If this system works, then users can always use fraud proofs to secure funds. + +The problem starts when the operator, not just any user, is the party acting maliciously. Because the operator is in sole control of the blockchain, they have more incentive to advance invalid state transitions on a larger scale, such as stealing funds belonging to users on the plasma chain. + +In this case, using the classic fraud-proof system does not work. The operator could easily make an invalid transaction transferring Alice and Bob's funds to their wallet and hide the data necessary for creating the fraud-proof. This is possible because the operator isn't required to make data available to users or Mainnet. + +Therefore, the most optimistic solution is to attempt a "mass exit" of users from the plasma chain. The mass exit slows down the malicious operator's plan to steal funds and provides some measure of protection for users. Withdrawal requests are ordered based on when each UTXO (or token) was created, preventing malicious operators from front-running honest users. + +Nonetheless, we still need a way to verify the validity of withdrawal requests during a mass exit—to prevent opportunistic individuals from cashing in on the chaos processing invalid exits. The solution is simple: require users to post the last **valid state of the chain** to exit their money. + +But this approach still has problems. For instance, if all users on a plasma chain need to exit (which is possible in the case of a malicious operator), then the entire valid state of the plasma chain must be dumped on Ethereum's base layer at once. With the arbitrary size of plasma chains (high throughput = more data) and constraints on Ethereum's processing speeds, this is not an ideal solution. + +Although exit games sound nice in theory, real-life mass exits will likely trigger network-wide congestion on Ethereum itself. Besides harming Ethereum's functionality, a poorly coordinated mass exit means that users may be unable to withdraw funds before the operator drains every account on the plasma chain. + +## Pros and cons of plasma + +| Pros | Cons | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Offers high throughput and low cost per transaction. | Does not support general computation (cannot run smart contracts). Only basic token transfers, swaps, and a few other transaction types are supported via predicate logic. | +| Good for transactions between arbitrary users (no overhead per user pair if both are established on the plasma chain) | Need to periodically watch the network (liveness requirement) or delegate this responsibility to someone else to ensure the security of your funds. | +| Plasma chains can be adapted to specific use-cases that are unrelated to the main chain. Anyone, including businesses, can customize Plasma smart contracts to provide scalable infrastructure that works in different contexts. | Relies on one or more operators to store data and serve it upon request. | +| Reduces load on Ethereum Mainnet by moving computation and storage offchain. | Withdrawals are delayed by several days to allow for challenges. For fungible assets, this can be mitigated by liquidity providers, but there is an associated capital cost. | +| | If too many users try to exit simultaneously, Ethereum Mainnet could get congested. | + +## Plasma vs layer 2 scaling protocols + +While Plasma was once considered a useful scaling solution for Ethereum, it has since been dropped in favor of [layer 2 (L2) scaling protocols](/layer-2/). L2 scaling solutions remedy several of Plasma's problems: + +### Efficiency + +[Zero-Knowledge rollups](/developers/docs/scaling/zk-rollups) generate cryptographic proofs of the validity of each batch of transactions processed offchain. This prevents the users (and operators) from advancing invalid state transitions, eliminating the need for challenge periods and exit games. It also means users don't have to watch the chain periodically to secure their funds. + +### Support for smart contracts + +Another problem with the plasma framework was [the inability to support the execution of Ethereum smart contracts](https://ethresear.ch/t/why-smart-contracts-are-not-feasible-on-plasma/2598/4). As a result, most implementations of Plasma were mostly built for simple payments or the exchange of ERC-20 tokens. + +Conversely, optimistic rollups, are compatible with the [Ethereum Virtual Machine](/developers/docs/evm/) and can run Ethereum-native [smart contracts](/developers/docs/smart-contracts/), making them a useful and _secure_ solution for scaling [decentralized applications](/developers/docs/dapps/). Similarly, plans are underway to [create a zero-knowledge implementation of the EVM (zkEVM)](https://ethresear.ch/t/a-zk-evm-specification/11549) that would allow ZK-rollups to process arbitrary logic and execute smart contracts. + +### Data unavailability + +As explained earlier, plasma suffers from a data availability problem. If a malicious operator advanced an invalid transition on the plasma chain, users would be unable to challenge it since the operator can withhold data needed to create the fraud-proof. Rollups solve this problem by forcing operators to post transaction data on Ethereum, allowing anyone to verify the chain's state and create fraud proofs if necessary. + +### Mass exit problem + +ZK-rollups and optimistic rollups both solve Plasma's mass exit problem in various ways. For example, a ZK-rollup relies on cryptographic mechanisms that ensure operators cannot steal user funds under any scenario. + +Similarly, optimistic rollups impose a delay period on withdrawals during which anyone can initiate a challenge and prevent malicious withdrawal requests. While this is similar to Plasma, the difference is that verifiers have access to data needed to create fraud proofs. Thus, there's no need for rollup users to engage in a frenzied, "first-to-get-out" migration to Ethereum Mainnet. + +## How does Plasma differ from sidechains and sharding? + +Plasma, sidechains, and sharding are fairly similar because they all connect to Ethereum Mainnet in some way. However, the level and strength of these connections vary, which affects the security properties of each scaling solution. + +### Plasma vs sidechains + +A [sidechain](/developers/docs/scaling/sidechains/) is an independently operated blockchain connected to Ethereum Mainnet via a two-way bridge. [Bridges](/bridges/) allow users to exchange tokens between the two blockchains to transact on the sidechain, reducing congestion on Ethereum Mainnet and improving scalability. +Sidechains use a separate consensus mechanism and are typically much smaller than Ethereum Mainnet. As a result, bridging assets to these chains involves increased risk; given the lack of security guarantees inherited from Ethereum Mainnet in the sidechain model, users risk the loss of funds in an attack on the sidechain. + +Conversely, plasma chains derive their security from Mainnet. This makes them measurably more secure than sidechains. Both sidechains and plasma chains can have different consensus protocols, but the difference is that plasma chains publish Merkle roots for each block on Ethereum Mainnet. Block roots are small pieces of information we can use to verify information about transactions that happen on a plasma chain. If an attack happens on a plasma chain, users can safely withdraw their funds back to Mainnet using the appropriate proofs. + +### Plasma vs sharding + +Both plasma chains and shard chains periodically publish cryptographic proofs to Ethereum Mainnet. However, both have different security properties. + +Shard chains commit "collation headers" to Mainnet containing detailed information about each data shard. Nodes on Mainnet verify and enforce the validity of data shards, reducing the possibility of invalid shard transitions and protecting the network against malicious activity. + +Plasma is different because Mainnet only receives minimal information about the state of child chains. This means Mainnet cannot effectively verify transactions conducted on child chains, making them less secure. + +**Note** that sharding the Ethereum blockchain is no longer on the roadmap. It has been superseded by scaling via rollups and [Danksharding](/roadmap/danksharding). + +### Use Plasma + +Multiple projects provide implementations of Plasma that you can integrate into your dapps: + +- [Polygon](https://polygon.technology/) (previously Matic Network) + +## Further reading + +- [Learn Plasma](https://www.learnplasma.org/en/) +- [A quick reminder of what "shared security" means and why it's so important](https://old.reddit.com/r/ethereum/comments/sgd3zt/a_quick_reminder_of_what_shared_security_means/) +- [Sidechains vs Plasma vs Sharding](https://vitalik.eth.limo/general/2019/06/12/plasma_vs_sharding.html) +- [Understanding Plasma, Part 1: The Basics](https://www.theblockcrypto.com/amp/post/10793/understanding-plasma-part-1-the-basics) +- [The Life and Death of Plasma](https://medium.com/dragonfly-research/the-life-and-death-of-plasma-b72c6a59c5ad#) + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Scaling > Sidechains + +A sidechain is a separate blockchain that runs independent of Ethereum and is connected to Ethereum Mainnet by a two-way bridge. Sidechains can have separate block parameters and [consensus algorithms](/developers/docs/consensus-mechanisms/), which are often designed for efficient processing of transactions. Using a sidechain involves trade-offs, though, as they do not inherit Ethereum's security properties. Unlike [layer 2 scaling solutions](/layer-2/), sidechains do not post state changes and transaction data back to Ethereum Mainnet. + +Sidechains also sacrifice some measure of decentralization or security to achieve high throughput ([scalability trilemma](https://vitalik.eth.limo/general/2021/05/23/scaling.html)). Ethereum is, however, committed to scaling without compromising on decentralization and security as outlined in its [vision statement](/roadmap/vision/) for upgrades. + +## How do sidechains work? + +Sidechains are independent blockchains, with different histories, development roadmaps, and design considerations. While a sidechain may share some surface-level similarities with Ethereum, it has several distinctive features. + +### Consensus algorithms + +One of the qualities that make sidechains unique (i.e., different from Ethereum) is the consensus algorithm used. Sidechains don't rely on Ethereum for consensus and can choose alternative consensus protocols that suit their needs. Some examples of consensus algorithms used on sidechains include: + +- [Proof-of-authority](/developers/docs/consensus-mechanisms/poa/) +- [Delegated proof-of-stake](https://en.bitcoin.it/wiki/Delegated_proof_of_stake) +- [Byzantine fault tolerance](https://decrypt.co/resources/byzantine-fault-tolerance-what-is-it-explained). + +Like Ethereum, sidechains have validating nodes that verify and process transactions, produce blocks, and store the blockchain state. Validators are also responsible for maintaining consensus across the network and securing it against malicious attacks. + +#### Block parameters + +Ethereum places limits on [block times](/developers/docs/blocks/#block-time) (i.e., the time it takes to produce new blocks) and [block sizes](/developers/docs/blocks/#block-size) (i.e., the amount of data contained per block denominated in gas). Conversely, sidechains often adopt different parameters, such as faster block times and higher gas limits, to achieve high throughput, fast transactions, and low fees. + +While this has some benefits, it has critical implications for network decentralization and security. Block parameters, like fast block times and big block sizes, increase the difficulty of running a full node—leaving a few "supernodes" responsible for securing the chain. In such a scenario, the possibility of validator collusion or a malicious takeover of the chain increases. + +For blockchains to scale without harming decentralization, running a node must be open to everyone—not necessarily parties with specialized hardware. This is why efforts are underway to ensure everyone can [run a full node](/developers/docs/nodes-and-clients/#why-should-i-run-an-ethereum-node) on the Ethereum network. + +### EVM compatibility + +Some sidechains are EVM-compatible and are able to execute contracts developed for the [Ethereum Virtual Machine (EVM)](/developers/docs/evm/). EVM-compatible sidechains support smart contracts [written in Solidity](/developers/docs/smart-contracts/languages/), as well as other EVM smart contract languages, which means smart contracts written for Ethereum Mainnet will also work on EVM-compatible sidechains. + +This means if you want to use your [dapp](/developers/docs/dapps/) on a sidechain, it's just a matter of deploying your [smart contract](/developers/docs/smart-contracts/) to this sidechain. It looks, feels, and acts just like Mainnet—you write contracts in Solidity, and interact with the chain via the sidechains RPC. + +Because sidechains are EVM-compatible, they are considered a useful [scaling solution](/developers/docs/scaling/) for Ethereum-native dapps. With your dapp on a sidechain, users can enjoy lower gas fees and faster transactions, especially if Mainnet is congested. + +However, as explained previously, using a sidechain involves significant trade-offs. Each sidechain is responsible for its security and doesn't inherit Ethereum's security properties. This increases the possibility of malicious behavior which can affect your users or put their funds at risk. + +### Asset movement + +In order for a separate blockchain to become a sidechain to Ethereum Mainnet it needs the ability to facilitate the transfer of assets from and to Ethereum Mainnet. This interoperability with Ethereum is achieved using a blockchain bridge. [Bridges](/bridges/) use smart contracts deployed on Ethereum Mainnet and a sidechain to control the bridging of funds between them. + +While bridges help users move funds between Ethereum and the sidechain, the assets are not physically moved across the two chains. Instead, mechanisms that typically involve minting and burning are used for transferring value across chains. More on [how bridges work](/developers/docs/bridges/#how-do-bridges-work). + +## Pros and cons of sidechains + +| Pros | Cons | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| The technology underpinning sidechains is well-established and benefits from extensive research and improvements in design. | Sidechains trade off some measure of decentralization and trustlessness for scalability. | +| Sidechains support general computation and offer EVM compatibility (they can run Ethereum-native dapps). | A sidechain uses a separate consensus mechanism and doesn't benefit from Ethereum's security guarantees. | +| Sidechains use different consensus models to efficiently process transactions and lower transaction fees for users. | Sidechains require higher trust assumptions (e.g., a quorum of malicious sidechain validators can commit fraud). | +| EVM-compatible sidechains allow dapps to expand their ecosystem. | | + +### Use Sidechains + +Multiple projects provide implementations of sidechains that you can integrate into your dapps: + +- [Polygon PoS](https://polygon.technology/solutions/polygon-pos) +- [Skale](https://skale.network/) +- [Gnosis Chain (formerly xDai)](https://www.gnosischain.com/) +- [Loom Network](https://loomx.io/) +- [Metis Andromeda](https://www.metis.io/) + +## Further reading + +- [Scaling Ethereum dapps through Sidechains](https://medium.com/loom-network/dappchains-scaling-ethereum-dapps-through-sidechains-f99e51fff447) _Feb 8, 2018 - Georgios Konstantopoulos_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Scaling > State Channels + +State channels allow participants to securely transact offchain while keeping interaction with Ethereum Mainnet at a minimum. Channel peers can conduct an arbitrary number of offchain transactions while only submitting two onchain transactions to open and close the channel. This allows for extremely high transaction throughput and results in lower costs for users. + +## Prerequisites + +You should have read and understood our pages on [Ethereum scaling](/developers/docs/scaling/) and [layer 2](/layer-2/). + +## What are channels? + +Public blockchains, such as Ethereum, face scalability challenges due to their distributed architecture: onchain transactions must be executed by all nodes. Nodes have to be able to handle the volume of transactions in a block using modest hardware, imposing a limit on the transaction throughput to keep the network decentralized. Blockchain channels solve this problem by allowing users to interact offchain while still relying on the security of the main chain for final settlement. + +Channels are simple peer-to-peer protocols that allow two parties to make many transactions between themselves and then only post the final results to the blockchain. The channel uses cryptography to demonstrate that the summary data they generate is truly the result of a valid set of intermediate transactions. A ["multisig"](/developers/docs/smart-contracts/#multisig) smart contract ensures the transactions are signed by the correct parties. + +With channels, state changes are executed and validated by interested parties, minimizing computation on Ethereum's execution layer. This decreases congestion on Ethereum and also increases transaction processing speeds for users. + +Each channel is managed by a [multisig smart contract](/developers/docs/smart-contracts/#multisig) running on Ethereum. To open a channel, participants deploy the channel contract onchain and deposit funds into it. Both parties collectively sign a state update to initialize the channel's state, after which they can transact quickly and freely offchain. + +To close the channel, participants submit the last agreed-upon state of the channel onchain. Afterward, the smart contract distributes the locked funds according to each participant's balance in the channel's final state. + +Peer-to-peer channels are particularly useful for situations where some predefined participants wish to transact with high frequency without incurring visible overhead. Blockchain channels fall under two categories: **payment channels** and **state channels**. + +## Payment channels + +A payment channel is best described as a "two-way ledger" collectively maintained by two users. The ledger's initial balance is the sum of deposits locked into the onchain contract during the channel opening phase. Payment channel transfers can be performed instantaneously and without the involvement of the actual blockchain itself, except for an initial one-time onchain creation and an eventual closing of the channel. + +Updates to the ledger's balance (i.e., the payment channel's state) require the approval of all parties in the channel. A channel update, signed by all channel participants, is considered finalized, much like a transaction on Ethereum. + +Payment channels were among the earliest scaling solutions designed to minimize expensive onchain activity of simple user interactions (e.g. ETH transfers, atomic swaps, micropayments). Channel participants can conduct an unlimited amount of instant, feeless transactions between each other as long as the net sum of their transfers does not exceed the deposited tokens. + +## State channels + +Apart from supporting offchain payments, payment channels have not proven useful for handling general state transition logic. State channels were created to solve this problem and make channels useful for scaling general-purpose computation. + +State channels still have a lot in common with payment channels. For example, users interact by exchanging cryptographically signed messages (transactions), which the other channel participants must also sign. If a proposed state update isn't signed by all participants, it is considered invalid. + +However, in addition to holding the user's balances, the channel also tracks the current state of the contract's storage (i.e., values of contract variables). + +This makes it possible to execute a smart contract offchain between two users. In this scenario, updates to the smart contract's internal state require only the approval of the peers who created the channel. + +While this solves the scalability problem described earlier, it has implications for security. On Ethereum, the validity of state transitions is enforced by the network's consensus protocol. This makes it impossible to propose an invalid update to a smart contract's state or alter smart contract execution. + +State channels don't have the same security guarantees. To some extent, a state channel is a miniature version of Mainnet. With a limited set of participants enforcing rules, the possibility of malicious behavior (e.g., proposing invalid state updates) increases. State channels derive their security from a dispute arbitration system based on [fraud proofs](/glossary/#fraud-proof). + +## How state channels work + +Basically, the activity in a state channel is a session of interactions involving users and a blockchain system. Users mostly communicate with each other offchain and only interact with the underlying blockchain to open the channel, close the channel, or settle potential disputes between participants. + +The following section outlines the basic workflow of a state channel: + +### Opening the channel + +Opening a channel requires participants to commit funds to a smart contract on Mainnet. The deposit also functions as a virtual tab, so participating actors can transact freely without needing to settle payments immediately. Only when the channel is finalized onchain do parties settle each other and withdraw what's left of their tab. + +This deposit also serves as a bond to guarantee honest behavior from each participant. If depositors are found guilty of malicious actions during the dispute resolution phase, the contract slashes their deposit. + +Channel peers must sign an initial state, which they all agree upon. This serves as the state channel's genesis, after which users can start transacting. + +### Using the channel + +After initializing the channel's state, peers interact by signing transactions and sending them to each other for approval. Participants initiate state updates with these transactions and sign state updates from others. Each transaction comprises the following: + +- A **nonce**, which acts as a unique ID for transactions and prevents replay attacks. It also identifies the order in which state updates occurred (which is important for dispute resolution) + +- The channel's old state + +- The channel's new state + +- The transaction which triggers the state transition (e.g., Alice sends 5 ETH to Bob) + +State updates in the channel are not broadcasted onchain as is normally the case when users interact on Mainnet, which aligns with state channels' goal to minimize onchain footprint. As long as participants agree on state updates, they are as final as an Ethereum transaction. Participants only need to depend on Mainnet's consensus if a dispute arises. + +### Closing the channel + +Closing a state channel requires submitting the channel's final, agreed-upon state to the onchain smart contract. Details referenced in the state update include the number of each participant's moves and a list of approved transactions. + +After verifying that the state update is valid (i.e., it is signed by all parties) the smart contract finalizes the channel and distributes the locked funds according to the channel's outcome. Payments made offchain are applied to Ethereum's state and each participant receives their remaining portion of the locked funds. + +The scenario described above represents what happens in the happy case. Sometimes, users may be unable to reach an agreement and finalize the channel (the sad case). Any of the following could be true of the situation: + +- Participants go offline and fail to propose state transitions + +- Participants refuse to co-sign valid state updates + +- Participants try to finalize the channel by proposing an old state update to the onchain contract + +- Participants propose invalid state transitions for others to sign + +Whenever consensus breaks down between participating actors in a channel, the last option is to rely on Mainnet's consensus to enforce the channel's final, valid state. In this case, closing the state channel requires settling disputes onchain. + +### Settling disputes + +Typically, parties in a channel agree on closing the channel beforehand and co-sign the last state transition, which they submit to the smart contract. Once the update is approved onchain, execution of the offchain smart contract ends and participants exit the channel with their money. + +However, one party can submit an onchain request to end the smart contract's execution and finalize the channel—without waiting for their counterpart's approval. If any of the consensus-breaking situations described earlier occur, either party can trigger the onchain contract to close the channel and distribute funds. This provides **trustlessness**, ensuring that honest parties can exit their deposits at any point, regardless of the other party's actions. + +To process the channel exit, the user must submit the application's last valid state update to the onchain contract. If this checks out (i.e., it bears the signature of all parties), then funds are redistributed in their favor. + +There is, however, a delay in executing single-user exit requests. If the request to conclude the channel was unanimously approved, then the onchain exit transaction is executed immediately. + +The delay comes into play in single-user exits due to the possibility of fraudulent actions. For example, a channel participant may try to finalize the channel on Ethereum by submitting an older state update onchain. + +As a countermeasure, state channels allow honest users to challenge invalid state updates by submitting the latest, valid state of the channel onchain. State channels are designed such that newer, agreed-upon state updates trump older state updates. + +Once a peer triggers the onchain dispute-resolution system, the other party is required to respond within a time limit (called the challenge window). This allows users to challenge the exit transaction, especially if the other party is applying a stale update. + +Whatever the case may be, channel users always have strong finality guarantees: if the state transition in their possession was signed by all members and is the most recent update, then it is of equal finality with a regular onchain transaction. They still have to challenge the other party onchain, but the only possible outcome is finalizing the last valid state, which they hold. + +### How do state channels interact with Ethereum? + +Although they exist as offchain protocols, state channels have an onchain component: the smart contract deployed on Ethereum when opening the channel. This contract controls the assets deposited into the channel, verifies state updates, and arbitrates disputes between participants. + +State channels don't publish transaction data or state commitments to Mainnet, unlike [layer 2](/layer-2/) scaling solutions. However, they are more connected to Mainnet than, say, [sidechains](/developers/docs/scaling/sidechains/), making them somewhat safer. + +State channels rely on the main Ethereum protocol for the following: + +#### 1. Liveness + +The onchain contract deployed when opening the channel is responsible for the channel's functionality. If the contract is running on Ethereum, then the channel is always available for usage. Conversely, a sidechain can always fail, even if Mainnet is operational, putting user funds at risk. + +#### 2. Security + +To some extent, state channels rely on Ethereum to provide security and protect users from malicious peers. As discussed in later sections, channels use a fraud proof mechanism that lets users challenge attempts to finalize the channel with an invalid or stale update. + +In this case, the honest party provides the latest valid state of the channel as a fraud proof to the onchain contract for verification. Fraud proofs enable mutually distrustful parties to conduct offchain transactions without risking their funds in the process. + +#### 3. Finality + +State updates collectively signed by channel users are considered as good as onchain transactions. Still, all in-channel activity only achieves true finality when the channel is closed on Ethereum. + +In the optimistic case, both parties can cooperate and sign the final state update and submit onchain to close the channel, after which the funds are distributed according to the channel's final state. In the pessimistic case, where someone tries to cheat by posting an incorrect state update onchain, their transaction isn't finalized until the challenge window elapses. + +## Virtual state channels + +The naive implementation of a state channel would be to deploy a new contract when two users wish to execute an application offchain. This is not only infeasible, but it also negates the cost-effectiveness of state channels (onchain transaction costs can quickly add up). + +To solve this problem, "virtual channels" were created. Unlike regular channels that require onchain transactions to open and terminate, a virtual channel can be opened, executed, and finalized without interacting with the main chain. It is even possible to settle disputes offchain using this method. + +This system relies on the existence of so-called "ledger channels", which have been funded onchain. Virtual channels between two parties can be built on top of an existing ledger channel, with the owner(s) of the ledger channel serving as an intermediary. + +Users in each virtual channel interact via a new contract instance, with the ledger channel able to support multiple contract instances. The ledger channel's state also contains more than one contract storage state, allowing for parallel execution of applications offchain between different users. + +Just like regular channels, users exchange state updates to progress the state machine. Unless a dispute arises, the intermediary only has to be contacted when opening or terminating the channel. + +### Virtual payment channels + +Virtual payment channels work off the same idea as virtual state channels: participants connected to the same network can pass messages without needing to open a new channel onchain. In virtual payment channels, value transfers are routed through one or more intermediaries, with guarantees that only the intended recipient can receive transferred funds. + +## Applications of state channels + +### Payments + +Early blockchain channels were simple protocols that allowed two participants to conduct rapid, low-fee transfers offchain without having to pay high transaction fees on Mainnet. Today, payment channels are still useful for applications designed for the exchange and deposits of ether and tokens. + +Channel-based payments have the following advantages: + +1. **Throughput**: The amount of offchain transactions per channel is unconnected to Ethereum's throughput, which is influenced by various factors, especially block size and block time. By executing transactions offchain, blockchain channels can achieve higher throughput. + +2. **Privacy**: Because channels exist offchain, details of interactions between participants are not recorded on Ethereum's public blockchain. Channel users only have to interact onchain when funding and closing channels or settling disputes. Thus, channels are useful for individuals who desire more private transactions. + +3. **Latency**: Offchain transactions conducted between channel participants can be settled instantly, if both parties cooperate, reducing delays. In contrast, sending a transaction on Mainnet requires waiting for nodes to process the transaction, produce a new block with the transaction, and reach consensus. Users may also need to wait for more block confirmations before considering a transaction finalized. + +4. **Cost**: State channels are particularly useful in situations where a set of participants will exchange many state updates over a long period. The only costs incurred are the opening and closing of the state channel smart contract; every state change between opening and closing the channel will be cheaper than the last as the settlement cost is distributed accordingly. + +Implementing state channels on layer 2 solutions, such as [rollups](/developers/docs/scaling/#rollups), could make them even more attractive for payments. While channels offer cheap payments, the costs of setting up the onchain contract on Mainnet during the opening phase can be get expensive—especially when gas fees spike. Ethereum-based rollups offer [lower transaction fees](https://l2fees.info/) and can reduce overhead for channel participants by bringing down setup fees. + +### Microtransactions + +Microtransactions are low-value payments (e.g., lower than a fraction of a dollar) that businesses cannot process without incurring losses. These entities must pay payment service providers, which they cannot do if the margin on customer payments is too low to make a profit. + +Payment channels solve this problem by reducing the overhead associated with microtransactions. For example, an Internet Service Provider (ISP) can open a payment channel with a customer, allowing them to stream small payments each time they use the service. + +Beyond the cost of opening and closing the channel, participants don't incur further costs on microtransactions (no gas fees). This is a win-win situation since customers have more flexibility in how much they pay for services and businesses don't lose out on profitable microtransactions. + +### Decentralized applications + +Like payment channels, state channels can make conditional payments according to the state machine's final states. State channels can also support arbitrary state transition logic, making them useful for executing generic apps offchain. + +State channels are often limited to simple turn-based applications, as this makes it easier to manage funds committed to the onchain contract. Also, with a limited number of parties updating the offchain application's state at intervals, punishing dishonest behavior is relatively straightforward. + +The efficiency of a state channel application also depends on its design. For example, a developer might deploy the app channel contract onchain once and allow other players to re-use the app without having to go onchain. In this case, the initial app channel serves as a ledger channel supporting multiple virtual channels, each running a new instance of the app's smart contract offchain. + +A potential use-case for state channel applications is simple two-player games, where funds are distributed based on the game's outcome. The benefit here is that players don't have to trust each other (trustlessness) and the onchain contract, not players, controls the allocation of funds and settlement of disputes (decentralization). + +Other possible use-cases for state channel apps include ENS name ownership, NFT ledgers, and many more. + +### Atomic transfers + +Early payment channels were restricted to transfers between two parties, limiting their usability. However, the introduction of virtual channels allowed individuals to route transfers through intermediaries (i.e., multiple p2p channels) without having to open a new channel onchain. + +Commonly described as "multi-hop transfers", routed payments are atomic (i.e., either all parts of the transaction succeed or it fails altogether). Atomic transfers use [Hashed Timelock Contracts (HTLCs)](https://en.bitcoin.it/wiki/Hash_Time_Locked_Contracts) to ensure the payment is released only if certain conditions are met, thereby reducing counterparty risk. + +## Drawbacks of using state channels + +### Liveness assumptions + +To ensure efficiency, state channels place time limits on the ability of channel participants to respond to disputes. This rule assumes that peers will always be online to monitor channel activity and contest challenges when necessary. + +In reality, users can go offline for reasons out of their control (e.g., poor internet connection, mechanical failure, etc.). If an honest user goes offline, a malicious peer can exploit the situation by presenting old intermediate states to the adjudicator contract and stealing the committed funds. + +Some channels use "watchtowers"—entities responsible for watching onchain dispute events on behalf of others and taking necessary actions, like alerting concerned parties. However, this can add to the costs of using a state channel. + +### Data unavailability + +As explained earlier, challenging an invalid dispute requires presenting the latest, valid state of the state channel. This is another rule based on an assumption—that users have access to the channel's latest state. + +Although expecting channel users to store copies of offchain application state is reasonable, this data may be lost due to error or mechanical failure. If the user doesn't have the data backed up, they can only hope that the other party doesn't finalize an invalid exit request using old state transitions in their possession. + +Ethereum users don't have to deal with this problem since the network enforces rules on data availability. Transaction data is stored and propagated by all nodes and available for users to download if and when necessary. + +### Liquidity issues + +To establish a blockchain channel, participants need to lock funds in an onchain smart contract for the channel's lifecycle. This reduces the liquidity of channel users and also limits channels to those who can afford to keep funds locked on Mainnet. + +However, ledger channels—operated by an offchain service provider (OSP)—can reduce liquidity issues for users. Two peers connected to a ledger channel can create a virtual channel, which they can open and finalize completely offchain, anytime they want. + +Offchain service providers could also open channels with multiple peers, making them useful for routing payments. Of course, users must pay fees to OSPs for their services, which may be undesirable for some. + +### Griefing attacks + +Griefing attacks are a common feature of fraud proof-based systems. A griefing attack does not directly benefit the attacker but causes grief (i.e., harm) to the victim, hence the name. + +Fraud proving is susceptible to griefing attacks because the honest party must respond to every dispute, even invalid ones, or risk losing their funds. A malicious participant can decide to repeatedly post stale state transitions onchain, forcing the honest party to respond with the valid state. The cost of those onchain transactions can quickly add up, causing honest parties to lose out in the process. + +### Predefined participant sets + +By design, the number of participants that comprise a state channel remains fixed throughout its lifetime. This is because updating the participant set would complicate the channel's operation, especially when funding the channel, or settling disputes. Adding or removing participants would also require additional onchain activity, which increases overhead for users. + +While this makes state channels easier to reason about, it limits the usefulness of channel designs to application developers. This partly explains why state channels have been dropped in favor of other scaling solutions, such as rollups. + +### Parallel transaction processing + +Participants in the state channel send state updates in turns, which is why they work best for "turn-based applications" (e.g., a two-player chess game). This eliminates the need to handle simultaneous state updates and reduces the work the onchain contract must do to punish stale update posters. However, a side-effect of this design is that transactions are dependent on each other, increasing latency and diminishing the overall user experience. + +Some state channels solve this problem by using a "full-duplex" design that separates the offchain state into two unidirectional "simplex" states, allowing for concurrent state updates. Such designs improve offchain throughput and decrease transaction delays. + +## Use state channels + +Multiple projects provide implementations of state channels that you can integrate into your dapps: + +- [Connext](https://connext.network/) +- [Kchannels](https://www.kchannels.io/) +- [Perun](https://perun.network/) +- [Raiden](https://raiden.network/) +- [Statechannels.org](https://statechannels.org/) + +## Further reading + +**State channels** + +- [Making Sense of Ethereum’s Layer 2 Scaling Solutions: State Channels, Plasma, and Truebit](https://medium.com/l4-media/making-sense-of-ethereums-layer-2-scaling-solutions-state-channels-plasma-and-truebit-22cb40dcc2f4) _– Josh Stark, Feb 12 2018_ +- [State Channels - an explanation](https://www.jeffcoleman.ca/state-channels/) _Nov 6, 2015 - Jeff Coleman_ +- [Basics of State Channels](https://education.district0x.io/general-topics/understanding-ethereum/basics-state-channels/) _District0x_ +- [Blockchain State Channels: A State of the Art](https://ieeexplore.ieee.org/document/9627997) + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Scaling > Validium + +Validium is a [scaling solution](/developers/docs/scaling/) that enforces integrity of transactions using validity proofs like [ZK-rollups](/developers/docs/scaling/zk-rollups/), but doesn’t store transaction data on the Ethereum Mainnet. While offchain data availability introduces trade-offs, it can lead to massive improvements in scalability (validiums can process [~9,000 transactions, or more, per second](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263)). + +## Prerequisites + +You should have read and understood our page on [Ethereum scaling](/developers/docs/scaling/) and [layer 2](/layer-2). + +## What is validium? + +Validiums are scaling solutions that use offchain data availability and computation designed to improve throughput by processing transactions off the Ethereum Mainnet. Like zero-knowledge rollups (ZK-rollups), validiums publish [zero-knowledge proofs](/glossary/#zk-proof) to verify offchain transactions on Ethereum. This prevents invalid state transitions and enhances the security guarantees of a validium chain. + +These "validity proofs" can come in the form of ZK-SNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) or ZK-STARKs (Zero-Knowledge Scalable Transparent ARgument of Knowledge). More on [zero-knowledge proofs](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/). + +Funds belonging to validium users are controlled by a smart contract on Ethereum. Validiums offer near-instant withdrawals, much like ZK-rollups do; once the validity proof for a withdrawal request has been verified on Mainnet, users can withdraw funds by providing [Merkle proofs](/developers/tutorials/merkle-proofs-for-offline-data-integrity/). The Merkle proof validates the inclusion of the user’s withdrawal transaction in a verified transaction batch, allowing the onchain contract to process the withdrawal. + +However, validium users can have their funds frozen and withdrawals restricted. This can happen if data availability managers on the validium chain withhold offchain state data from users. Without access to transaction data, users cannot compute the Merkle proof required to prove ownership of funds and execute withdrawals. + +This is the major difference between validiums and ZK-rollups—their positions on the data availability spectrum. Both solutions approach data storage differently, which has implications for security and trustlessness. + +## How do validiums interact with Ethereum? + +Validiums are scaling protocols built on top of the existing Ethereum chain. Although it executes transactions offchain, a validium chain is administered by a collection of smart contracts deployed on Mainnet including: + +1. **Verifier contract**: The verifier contract verifies the validity of proofs submitted by the validium operator when making state updates. This includes validity proofs attesting to the correctness of offchain transactions and data availability proofs verifying the existence of offchain transaction data. + +2. **Main contract**: The main contract stores state commitments (Merkle roots) submitted by block producers and updates the validium's state once a validity proof is verified onchain. This contract also processes deposits to and withdrawals from the validium chain. + +Validiums also rely on the main Ethereum chain for the following: + +### Settlement + +Transactions executed on a validium cannot be fully confirmed until the parent chain verifies their validity. All business conducted on a validium must eventually be settled on Mainnet. The Ethereum blockchain also provides "settlement guarantees" for validium users, meaning offchain transactions cannot be reversed or altered once committed to onchain. + +### Security + +Ethereum, acting as a settlement layer, also guarantees the validity of state transitions on validium. Offchain transactions executed on the validium chain are verified via a smart contract on the base Ethereum layer. + +If the onchain verifier contract deems the proof invalid, the transactions are rejected. This means operators must satisfy validity conditions enforced by the Ethereum protocol before updating the validium's state. + +## How does validium work? + +### Transactions + +Users submit transactions to the operator, a node responsible for executing transactions on the validium chain. Some validiums may use a sole operator to execute the chain or rely on a [proof-of-stake (PoS)](/developers/docs/consensus-mechanisms/pos/) mechanism for rotating operators. + +The operator aggregates transactions into a batch and sends it to a proving circuit for proving. The proving circuit accepts the transaction batch (and other relevant data) as inputs and outputs a validity proof verifying that the operations were performed correctly. + +### State commitments + +The state of the validium is hashed as a Merkle tree with the root stored in the main contract on Ethereum. The Merkle root, also known as the state root, acts as a cryptographic commitment to the current state of accounts and balances on the validium. + +To perform a state update, the operator must compute a new state root (after executing transactions) and submit it to the onchain contract. If the validity proof checks out, the proposed state is accepted and the validium switches to the new state root. + +### Deposits and withdrawals + +Users move funds from Ethereum to a validium by depositing ETH (or any ERC-compatible token) in the onchain contract. The contract relays the deposit event to the validium offchain, where the user's address is credited with an amount equal to their deposit. The operator also includes this deposit transaction in a new batch. + +To move funds back to Mainnet, a validium user initiates a withdrawal transaction and submits it to the operator who validates the withdrawal request and includes it in a batch. The user's assets on the validium chain are also destroyed before they can exit the system. Once the validity proof associated with the batch is verified, the user can call the main contract to withdraw the remainder of their initial deposit. + +As an anti-censorship mechanism, the validium protocol allows users to withdraw directly from the validium contract without going through the operator. In this case, users need to provide a Merkle proof to the verifier contract showing an account's inclusion in the state root. If the proof is accepted, the user can call the main contract's withdrawal function to exit their funds from the validium. + +### Batch submission + +After executing a batch of transactions, the operator submits the associated validity proof to the verifier contract and proposes a new state root to the main contract. If the proof is valid, the main contract updates the validium's state and finalizes the results of transactions in the batch. + +Unlike a ZK-rollup, block producers on a validium are not required to publish transaction data for transaction batches (only block headers). This makes validium a purely offchain scaling protocol, as opposed to "hybrid" scaling protocols (i.e., [layer 2](/layer-2/)) that publish state data on the main Ethereum chain using blob data, `calldata`, or a combination of both. + +### Data availability + +As mentioned, validiums utilize an offchain data availability model, where operators store all transaction data off Ethereum Mainnet. Validium's low onchain data footprint improves scalability (throughput isn't limited by Ethereum's data processing capacity) and reduces user fees (the cost of publishing data onchain is lower). + +Offchain data availability, however, presents a problem: data necessary for creating or verifying Merkle proofs may be unavailable. This means users may be unable to withdraw funds from the onchain contract if operators should act maliciously. + +Various validium solutions attempt to solve this problem by decentralizing the storage of state data. This involves forcing block producers to send the underlying data to "data availability managers" responsible for storing offchain data and making it available to users on request. + +Data availability managers in validium attest to the availability of data for offchain transactions by signing every validium batch. These signatures constitute a form of "availability proof" which the onchain verifier contract checks before approving state updates. + +Validiums differ in their approach to data availability management. Some rely on trusted parties to store state data, while others use randomly assigned validators for the task. + +#### Data availability committee (DAC) + +To guarantee the availability of offchain data, some validium solutions appoint a group of trusted entities, collectively known as a data availability committee (DAC), to store copies of the state and provide proof of data availability. DACs are easier to implement and require less coordination since membership is low. + +However, users must trust the DAC to make the data available when needed (e.g., for generating Merkle proofs). There's the possibility of members of data availability committees [getting compromised by a malicious actor](https://notes.ethereum.org/DD7GyItYQ02d0ax_X-UbWg?view) who can then withhold offchain data. + +[More on data availability committees in validiums](https://medium.com/starkware/data-availability-e5564c416424). + +#### Bonded data availability + +Other validiums require participants charged with storing offline data to stake (i.e., lock up) tokens in a smart contract before assuming their roles. This stake serves as a “bond” to guarantee honest behavior among data availability managers and reduces trust assumptions. If these participants fail to prove data availability, the bond is slashed. + +In a bonded data availability scheme, anyone can be assigned to hold offchain data once they provide the required stake. This expands the pool of eligible data availability managers, reducing the centralization that affects data availability committees (DACs). More importantly, this approach relies on cryptoeconomic incentives to prevent malicious activity, which is considerably more secure than appointing trusted parties to secure offline data in the validium. + +[More on bonded data availability in validiums](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf). + +## Volitions and validium + +Validiums offer many benefits but come with trade-offs (most notably, data availability). But, as with many scaling solutions, validiums are suited to specific use-cases—which is why volitions were created. + +Volitions combine a ZK-rollup and validium chain and allow users to switch between the two scaling solutions. With volitions, users can take advantage of validium's offchain data availability for certain transactions, while retaining the freedom to switch to an onchain data availability solution (ZK-rollup) if needed. This essentially gives users the freedom to choose trade-offs as dictated by their unique circumstances. + +A decentralized exchange (DEX) may prefer using a validium’s scalable and private infrastructure for high-value trades. It can also use a ZK-rollup for users who want a ZK-rollup's higher security guarantees and trustlessness. + +## Validiums and EVM compatibility + +Like ZK-rollups, validiums are mostly suited to simple applications, such as token swaps and payments. Supporting general computation and smart contract execution among validiums is difficult to implement, given the considerable overhead of proving [EVM](/developers/docs/evm/) instructions in a zero-knowledge proof circuit. + +Some validium projects attempt to sidestep this problem by compiling EVM-compatible languages (e.g., Solidity, Vyper) into creating custom bytecode optimized for efficient proving. A drawback of this approach is that new zero-knowledge proof-friendly VMs may not support important EVM opcodes, and developers have to write directly in the high-level language for an optimal experience. This creates even more problems: it forces developers to build dapps with an entirely new development stack and breaks compatibility with current Ethereum infrastructure. + +Some teams, however, are attempting to optimize existing EVM opcodes for ZK-proving circuits. This will result in the development of a zero-knowledge Ethereum Virtual Machine (zkEVM), an EVM-compatible VM that produces proofs to verify the correctness of program execution. With a zkEVM, validium chains can execute smart contracts offchain and submit validity proofs to verify an offchain computation (without having to re-execute it) on Ethereum. + +[More on zkEVMs](https://www.alchemy.com/overviews/zkevm). + +## How do validiums scale Ethereum? + +### 1. Offchain data storage + +Layer 2 scaling projects, such as optimistic rollups and ZK-rollups, trade the infinite scalability of pure offchain scaling protocols (e.g., [Plasma](/developers/docs/scaling/plasma/)) for security by publishing some transaction data on L1. But this means the scalability properties of rollups is limited by data bandwidth on Ethereum Mainnet ([data sharding](/roadmap/danksharding/) proposes to improve Ethereum's data storage capacity for this reason). + +Validiums achieve scalability by keeping all transaction data offchain and only post state commitments (and validity proofs) when relaying state updates to the main Ethereum chain. The existence of validity proofs, however, gives validiums higher security guarantees than other pure offchain scaling solutions, including Plasma and [sidechains](/developers/docs/scaling/sidechains/). By reducing the amount of data Ethereum has to process before validating offchain transactions, validium designs greatly extend throughput on Mainnet. + +### 2. Recursive proofs + +A recursive proof is a validity proof that verifies the validity of other proofs. These "proof of proofs" are generated by recursively aggregating multiple proofs until one final proof verifying all previous proofs is created. Recursive proofs scale blockchain processing speeds by increasing the number of transactions that can be verified per validity proof. + +Typically, each validity proof the validium operator submits to Ethereum for verification validates the integrity of a single block. Whereas a single recursive proof can be used to confirm the validity of several validium blocks at the same time—this is possible since the proving circuit can recursively aggregate several block proofs into one final proof. If the onchain verifier contract accepts the recursive proof, all the underlying blocks are finalized immediately. + +## Pros and cons of validium + +| Pros | Cons | +| ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| Validity proofs enforce integrity of offchain transactions and prevent operators from finalizing invalid state updates. | Producing validity proofs requires special hardware, which poses a centralization risk. | +| Increases capital efficiency for users (no delays in withdrawing funds back to Ethereum) | Limited support for general computation/smart contracts; specialized languages required for development. | +| Not vulnerable to certain economic attacks faced by fraud-proof based systems in high-value applications. | High computational power required to generate ZK proofs; not cost-effective for low throughput applications. | +| Reduces gas fees for users by not posting calldata to Ethereum Mainnet. | Slower subjective finality time (10-30 min to generate a ZK proof) but faster to full finality because there is no dispute time delay. | +| Suitable for specific use-cases, like trading or blockchain gaming that prioritize transaction privacy and scalability. | Users can be prevented from withdrawing funds since generating Merkle proofs of ownership requires offchain data to be available at all times. | +| Offchain data availability provides higher levels of throughput and increases scalability. | Security model relies on trust assumptions and cryptoeconomic incentives, unlike ZK-rollups, which purely rely on cryptographic security mechanisms. | + +### Use Validium/Volitions + +Multiple projects provide implementations of Validium and volitions that you can integrate into your dapps: + +**StarkWare StarkEx** - _StarkEx is an Ethereum Layer 2 (L2) scalability solution that is based on validity proofs. It can operate in either ZK-Rollup or Validium data-availability modes._ + +- [Documentation](https://docs.starkware.co/starkex-v4/starkex-deep-dive/data-availability-modes#validium) +- [Website](https://starkware.co/starkex/) + +**Matter Labs zkPorter**- _zkPorter is a Layer 2 scaling protocol tackling data availability with a hybrid approach that combines the ideas of zkRollup and sharding. It can support arbitrarily many shards, each with its own data availability policy._ + +- [Blog](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) +- [Documentation](https://docs.zksync.io/zksync-protocol/rollup/data-availability) +- [Website](https://zksync.io/) + +## Further reading + +- [Validium And The Layer 2 Two-By-Two — Issue No. 99](https://www.buildblockchain.tech/newsletter/issues/no-99-validium-and-the-layer-2-two-by-two) +- [ZK-rollups vs Validium](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263) +- [Volition and the Emerging Data Availability spectrum](https://medium.com/starkware/volition-and-the-emerging-data-availability-spectrum-87e8bfa09bb) +- [Rollups, Validiums, and Volitions: Learn About the Hottest Ethereum Scaling Solutions](https://www.defipulse.com/blog/rollups-validiums-and-volitions-learn-about-the-hottest-ethereum-scaling-solutions) +- [The Practical Guide to Ethereum Rollups](https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) + +--- + +## Developers > Docs > Scaling > Zk Rollups + +Zero-knowledge rollups (ZK-rollups) are layer 2 [scaling solutions](/developers/docs/scaling/) that increase throughput on Ethereum Mainnet by moving computation and state-storage offchain. ZK-rollups can process thousands of transactions in a batch and then only post some minimal summary data to Mainnet. This summary data defines the changes that should be made to the Ethereum state and some cryptographic proof that those changes are correct. + +## Prerequisites + +You should have read and understood our page on [Ethereum scaling](/developers/docs/scaling/) and [layer 2](/layer-2). + +## What are zero-knowledge rollups? + +**Zero-knowledge rollups (ZK-rollups)** bundle (or 'roll up') transactions into batches that are executed offchain. Offchain computation reduces the amount of data that has to be posted to the blockchain. ZK-rollup operators submit a summary of the changes required to represent all the transactions in a batch rather than sending each transaction individually. They also produce [validity proofs](/glossary/#validity-proof) to prove the correctness of their changes. + +The ZK-rollup's state is maintained by a smart contract deployed on the Ethereum network. To update this state, ZK-rollup nodes must submit a validity proof for verification. As mentioned, the validity proof is a cryptographic assurance that the state-change proposed by the rollup is really the result of executing the given batch of transactions. This means that ZK-rollups only need to provide validity proofs to finalize transactions on Ethereum instead of posting all transaction data onchain like [optimistic rollups](/developers/docs/scaling/optimistic-rollups/). + +There are no delays when moving funds from a ZK-rollup to Ethereum because exit transactions are executed once the ZK-rollup contract verifies the validity proof. Conversely, withdrawing funds from optimistic rollups is subject to a delay to allow anyone to challenge the exit transaction with a [fraud proof](/glossary/#fraud-proof). + +ZK-rollups write transactions to Ethereum as `calldata`. `calldata` is where data that is included in external calls to smart contract functions gets stored. Information in `calldata` is published on the blockchain, allowing anyone to reconstruct the rollup’s state independently. ZK-rollups use compression techniques to reduce transaction data—for example, accounts are represented by an index rather than an address, which saves 28 bytes of data. Onchain data publication is a significant cost for rollups, so data compression can reduce fees for users. + +## How do ZK-rollups interact with Ethereum? + +A ZK-rollup chain is an offchain protocol that operates on top of the Ethereum blockchain and is managed by onchain Ethereum smart contracts. ZK-rollups execute transactions outside of Mainnet, but periodically commit offchain transaction batches to an onchain rollup contract. This transaction record is immutable, much like the Ethereum blockchain, and forms the ZK-rollup chain. + +The ZK-rollup's core architecture is made up of the following components: + +1. **Onchain contracts**: As mentioned, the ZK-rollup protocol is controlled by smart contracts running on Ethereum. This includes the main contract which stores rollup blocks, tracks deposits, and monitors state updates. Another onchain contract (the verifier contract) verifies zero-knowledge proofs submitted by block producers. Thus, Ethereum serves as the base layer or "layer 1" for the ZK-rollup. + +2. **Offchain virtual machine (VM)**: While the ZK-rollup protocol lives on Ethereum, transaction execution and state storage happen on a separate virtual machine independent of the [EVM](/developers/docs/evm/). This offchain VM is the execution environment for transactions on the ZK-rollup and serves as the secondary layer or "layer 2" for the ZK-rollup protocol. Validity proofs verified on Ethereum Mainnet guarantee the correctness of state transitions in the offchain VM. + +ZK-rollups are "hybrid scaling solutions"—offchain protocols that operate independently but derive security from Ethereum. Specifically, the Ethereum network enforces the validity of state updates on the ZK-rollup and guarantees the availability of data behind every update to the rollup's state. As a result, ZK-rollups are considerably safer than pure offchain scaling solutions, such as [sidechains](/developers/docs/scaling/sidechains/), which are responsible for their security properties, or [validiums](/developers/docs/scaling/validium/), which also verify transactions on Ethereum with validity proofs, but store transaction data elsewhere. + +ZK-rollups rely on the main Ethereum protocol for the following: + +### Data availability + +ZK-rollups publish state data for every transaction processed offchain to Ethereum. With this data, it is possible for individuals or businesses to reproduce the rollup’s state and validate the chain themselves. Ethereum makes this data available to all participants of the network as `calldata`. + +ZK-rollups don’t need to publish much transaction data onchain because validity proofs already verify the authenticity of state transitions. Nevertheless, storing data onchain is still important because it allows permissionless, independent verification of the L2 chain's state which in turn allows anyone to submit batches of transactions, preventing malicious operators from censoring or freezing the chain. + +Onchain is required for users to interact with the rollup. Without access to state data users cannot query their account balance or initiate transactions (e.g., withdrawals) that rely on state information. + +### Transaction finality + +Ethereum acts as a settlement layer for ZK-rollups: L2 transactions are finalized only if the L1 contract accepts the validity proof. This eliminates the risk of malicious operators corrupting the chain (e.g., stealing rollup funds) since every transaction must be approved on Mainnet. Also, Ethereum guarantees that user operations cannot be reversed once finalized on L1. + +### Censorship resistance + +Most ZK-rollups use a "supernode" (the operator) to execute transactions, produce batches, and submit blocks to L1. While this ensures efficiency, it increases the risk of censorship: malicious ZK-rollup operators can censor users by refusing to include their transactions in batches. + +As a security measure, ZK-rollups allow users to submit transactions directly to the rollup contract on Mainnet if they think they are being censored by the operator. This allows users to force an exit from the ZK-rollup to Ethereum without having to rely on the operator’s permission. + +## How do ZK-rollups work? + +### Transactions + +Users in the ZK-rollup sign transactions and submit to L2 operators for processing and inclusion in the next batch. In some cases, the operator is a centralized entity, called a sequencer, who executes transactions, aggregates them into batches, and submits to L1. The sequencer in this system is the only entity allowed to produce L2 blocks and add rollup transactions to the ZK-rollup contract. + +Other ZK-rollups may rotate the operator role by using a [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) validator set. Prospective operators deposit funds in the rollup contract, with the size of each stake influencing the staker’s chances of getting selected to produce the next rollup batch. The operator’s stake can be slashed if they act maliciously, which incentivizes them to post valid blocks. + +#### How ZK-rollups publish transaction data on Ethereum + +As explained, transaction data is published on Ethereum as `calldata`. `calldata` is a data area in a smart contract used to pass arguments to a function and behaves similarly to [memory](/developers/docs/smart-contracts/anatomy/#memory). While `calldata` isn’t stored as part of Ethereum’s state, it persists onchain as part of the Ethereum chain's [history logs](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs). `calldata` does not affect Ethereum's state, making it a cheap way to store data onchain. + +The `calldata` keyword often identifies the smart contract method being called by a transaction and holds inputs to the method in the form of an arbitrary sequence of bytes. ZK-rollups use `calldata` to publish compressed transaction data onchain; the rollup operator simply adds a new batch by calling the required function in the rollup contract and passes the compressed data as function arguments. This helps reduce costs for users since a large part of rollup fees go toward storing transaction data onchain. + +### State commitments + +The ZK-rollup’s state, which includes L2 accounts and balances, is represented as a [Merkle tree](/whitepaper/#merkle-trees). A cryptographic hash of the Merkle tree’s root (Merkle root) is stored in the onchain contract, allowing the rollup protocol to track changes in the state of the ZK-rollup. + +The rollup transitions to a new state after the execution of a new set of transactions. The operator who initiated the state transition is required to compute a new state root and submit to the onchain contract. If the validity proof associated with the batch is authenticated by the verifier contract, the new Merkle root becomes the ZK-rollup’s canonical state root. + +Besides computing state roots, the ZK-rollup operator also creates a batch root—the root of a Merkle tree comprising all transactions in a batch. When a new batch is submitted, the rollup contract stores the batch root, allowing users to prove a transaction (e.g., a withdrawal request) was included in the batch. Users will have to provide transaction details, the batch root, and a [Merkle proof](/developers/tutorials/merkle-proofs-for-offline-data-integrity/) showing the inclusion path. + +### Validity proofs + +The new state root that the ZK-rollup operator submits to the L1 contract is the result of updates to the rollup’s state. Say Alice sends 10 tokens to Bob, the operator simply decreases Alice’s balance by 10 and increments Bob’s balance by 10. The operator then hashes the updated account data, rebuilds the rollup's Merkle tree, and submits the new Merkle root to the onchain contract. + +But the rollup contract won’t automatically accept the proposed state commitment until the operator proves the new Merkle root resulted from correct updates to the rollup’s state. The ZK-rollup operator does this by producing a validity proof, a succinct cryptographic commitment verifying the correctness of batched transactions. + +Validity proofs allow parties to prove the correctness of a statement without revealing the statement itself—hence, they are also called zero-knowledge proofs. ZK-rollups use validity proofs to confirm the correctness of offchain state transitions without having to re-execute transactions on Ethereum. These proofs can come in the form of a [ZK-SNARK](https://arxiv.org/abs/2202.06877) (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) or [ZK-STARK](https://eprint.iacr.org/2018/046) (Zero-Knowledge Scalable Transparent Argument of Knowledge). + +Both SNARKs and STARKs help attest to the integrity of offchain computation in ZK-rollups, although each proof type has distinctive features. + +**ZK-SNARKs** + +For the ZK-SNARK protocol to work, creating a Common Reference String (CRS) is necessary: the CRS provides public parameters for proving and verifying validity proofs. The security of the proving system depends on the CRS setup; if information used to create public parameters fall into the possession of malicious actors they may be able to generate false validity proofs. + +Some ZK-rollups attempt to solve this problem by using a [multi-party computation ceremony (MPC)](https://zkproof.org/2021/06/30/setup-ceremonies/amp/), involving trusted individuals, to generate public parameters for the ZK-SNARK circuit. Each party contributes some randomness (called "toxic waste") to the construct the CRS, which they must destroy immediately. + +Trusted setups are used because they increase the security of the CRS setup. As long as one honest participant destroys their input, the security of the ZK-SNARK system is guaranteed. Still, this approach requires trusting those involved to delete their sampled randomness and not undermine the system's security guarantees. + +Trust assumptions aside, ZK-SNARKs are popular for their small proof sizes and constant-time verification. As proof verification on L1 constitutes the larger cost of operating a ZK-rollup, L2s use ZK-SNARKs to generate proofs that can be verified quickly and cheaply on Mainnet. + +**ZK-STARKs** + +Like ZK-SNARKs, ZK-STARKs prove the validity of offchain computation without revealing the inputs. However, ZK-STARKs are considered an improvement on ZK-SNARKs because of their scalability and transparency. + +ZK-STARKs are 'transparent', as they can work without the trusted setup of a Common Reference String (CRS). Instead, ZK-STARKs rely on publicly verifiable randomness to set up parameters for generating and verifying proofs. + +ZK-STARKs also provide more scalability because the time needed to prove and verify validity proofs increases _quasilinearly_ in relation to the complexity of the underlying computation. With ZK-SNARKs, proving and verification times scale _linearly_ in relation to the size of the underlying computation. This means ZK-STARKs require less time than ZK-SNARKs for proving and verifying when large datasets are involved, making them useful for high-volume applications. + +ZK-STARKs are also secure against quantum computers, while the Elliptic Curve Cryptography (ECC) used in ZK-SNARKs is widely believed to be susceptible to quantum computing attacks. The downside to ZK-STARKs is that they produce larger proof sizes, which are more expensive to verify on Ethereum. + +#### How do validity proofs work in ZK-rollups? + +##### Proof generation + +Before accepting transactions, the operator will perform the usual checks. This includes confirming that: + +- The sender and receiver accounts are part of the state tree. +- The sender has enough funds to process the transaction. +- The transaction is correct and matches the sender’s public key on the rollup. +- The sender’s nonce is correct, etc. + +Once the ZK-rollup node has enough transactions, it aggregates them into a batch and compiles inputs for the proving circuit to compile into a succinct ZK-proof. This includes: + +- A Merkle tree root comprising all the transactions in the batch. +- Merkle proofs for transactions to prove inclusion in the batch. +- Merkle proofs for each sender-receiver pair in transactions to prove those accounts are part of the rollup's state tree. +- A set of intermediate state roots, derived from updating the state root after applying state updates for each transaction (i.e., decreasing sender accounts and increasing receiver accounts). + +The proving circuit computes the validity proof by "looping" over each transaction and performing the same checks the operator completed before processing the transaction. First, it verifies the sender's account is part of the existing state root using the provided Merkle proof. Then it reduces the sender's balance, increases their nonce, hashes the updated account data and combines it with the Merkle proof to generate a new Merkle root. + +This Merkle root reflects the sole change in the ZK-rollup's state: a change in the sender's balance and nonce. This is possible because the Merkle proof used to prove the account's existence is used to derive the new state root. + +The proving circuit performs the same process on the receiver's account. It checks if the receiver's account exists under the intermediate state root (using the Merkle proof), increases their balance, re-hashes the account data and combines it with the Merkle proof to generate a new state root. + +The process repeats for every transaction; each "loop" creates a new state root from updating the sender's account and a subsequent new root from updating the receiver's account. As explained, every update to the state root represents one part of the rollup's state tree changing. + +The ZK-proving circuit iterates over the entire transaction batch, verifying the sequence of updates that result in a final state root after the last transaction is executed. The last Merkle root computed becomes the newest canonical state root of the ZK-rollup. + +##### Proof verification + +After the proving circuit verifies the correctness of state updates, the L2 operator submits the computed validity proof to the verifier contract on L1. The contract's verification circuit verifies the proof's validity and also checks public inputs that form part of the proof: + +- **Pre-state root**: The ZK-rollup’s old state root (i.e., before the batched transactions were executed), reflecting the L2 chain's last known valid state. + +- **Post-state root**: The ZK-rollup’s new state root (i.e., after the execution of batched transactions), reflecting the L2 chain's newest state. The post-state root is the final root derived after applying state updates in the proving circuit. + +- **Batch root**: The Merkle root of the batch, derived by _merklizing_ transactions in the batch and hashing the tree's root. + +- **Transaction inputs**: Data associated with the transactions executed as part of the submitted batch. + +If the proof satisfies the circuit (i.e., it is valid), it means that there exists a sequence of valid transactions that transition the rollup from the previous state (cryptographically fingerprinted by the pre-state root) to a new state (cryptographically fingerprinted by the post-state root). If the pre-state root matches the root stored in the rollup contract, and the proof is valid, the rollup contract takes the post-state root from the proof and updates its state tree to reflect the rollup's changed state. + +### Entries and exits + +Users enter the ZK-rollup by depositing tokens in the rollup's contract deployed on the L1 chain. This transaction is queued up since only operators can submit transactions to the rollup contract. + +If the pending deposit queue starts filling up, the ZK-rollup operator will take the deposit transactions and submit them to the rollup contract. Once the user's funds are in the rollup, they can start transacting by sending transactions to the operator for processing. Users can verify balances on the rollup by hashing their account data, sending the hash to the rollup contract, and providing a Merkle proof to verify against the current state root. + +Withdrawing from a ZK-rollup to L1 is straightforward. The user initiates the exit transaction by sending their assets on the rollup to a specified account for burning. If the operator includes the transaction in the next batch, the user can submit a withdrawal request to the onchain contract. This withdrawal request will include the following: + +- Merkle proof proving the inclusion of the user's transaction to the burn account in a transaction batch + +- Transaction data + +- Batch root + +- L1 address to receive deposited funds + +The rollup contract hashes the transaction data, checks if the batch root exists, and uses the Merkle proof to check if the transaction hash is part of the batch root. Afterward, the contract executes the exit transaction and sends funds to the user's chosen address on L1. + +## ZK-rollups and EVM compatibility + +Unlike optimistic rollups, ZK-rollups are not readily compatible with the [Ethereum Virtual Machine (EVM)](/developers/docs/evm/). Proving general-purpose EVM computation in circuits is more difficult and resource-intensive than proving simple computations (like the token transfer described previously). + +However, [advances in zero-knowledge technology](https://hackmd.io/@yezhang/S1_KMMbGt#Why-possible-now) are igniting renewed interest in wrapping EVM computation in zero-knowledge proofs. These efforts are geared towards creating a zero-knowledge EVM (zkEVM) implementation that can efficiently verify the correctness of program execution. A zkEVM recreates existing EVM opcodes for proving/verification in circuits, allowing to execute smart contracts. + +Like the EVM, a zkEVM transitions between states after computation is performed on some inputs. The difference is that the zkEVM also creates zero-knowledge proofs to verify the correctness of every step in the program’s execution. Validity proofs could verify the correctness of operations that touch the VM’s state (memory, stack, storage) and the computation itself (i.e., did the operation call the right opcodes and execute them correctly?). + +The introduction of EVM-compatible ZK-rollups is expected to help developers leverage the scalability and security guarantees of zero-knowledge proofs. More importantly, compatibility with native Ethereum infrastructure means developers can build ZK-friendly dapps using familiar (and battle-tested) tooling and languages. + +## How do ZK-rollup fees work? + +How much users pay for transactions on ZK-rollups is dependent on the gas fee, just like on Ethereum Mainnet. However, gas fees work differently on L2 and are influenced by the following costs: + +1. **State write**: There is a fixed cost for writing to Ethereum’s state (i.e., submitting a transaction on the Ethereum blockchain). ZK-rollups reduce this cost by batching transactions and spreading fixed costs across multiple users. + +2. **Data publication**: ZK-rollups publish state data for every transaction to Ethereum as `calldata`. `calldata` costs are currently governed by [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), which stipulates a cost of 16 gas for non-zero bytes and 4 gas for zero bytes of `calldata`, respectively. The cost paid on each transaction is influenced by how much `calldata` needs to be posted onchain for it. + +3. **L2 operator fees**: This is the amount paid to the rollup operator as compensation for computational costs incurred in processing transactions, much like [transaction "priority fees (tips)"](/developers/docs/gas/#how-are-gas-fees-calculated) on Ethereum Mainnet. + +4. **Proof generation and verification**: ZK-rollup operators must produce validity proofs for transaction batches, which is resource-intensive. Verifying zero-knowledge proofs on Mainnet also costs gas (~ 500,000 gas). + +Apart from batching transactions, ZK-rollups reduce fees for users by compressing transaction data. You can [see a real-time overview](https://l2fees.info/) of how it costs to use Ethereum ZK-rollups. + +## How do ZK-rollups scale Ethereum? + +### Transaction data compression + +ZK-rollups extend the throughput on Ethereum’s base layer by taking computation offchain, but the real boost for scaling comes from compressing transaction data. Ethereum’s [block size](/developers/docs/blocks/#block-size) limits the data each block can hold and, by extension, the number of transactions processed per block. By compressing transaction-related data, ZK-rollups significantly increase the number of transactions processed per block. + +ZK-rollups can compress transaction data better than optimistic rollups since they don't have to post all the data required to validate each transaction. They only have to post the minimal data required to rebuild the latest state of accounts and balances on the rollup. + +### Recursive proofs + +An advantage of zero-knowledge proofs is that proofs can verify other proofs. For example, a single ZK-SNARK can verify other ZK-SNARKs. Such "proof-of-proofs" are called recursive proofs and dramatically increase throughput on ZK-rollups. + +Currently, validity proofs are generated on a block-by-block basis and submitted to the L1 contract for verification. However, verifying single block proofs limits the throughput that ZK-rollups can achieve since only one block can be finalized when the operator submits a proof. + +Recursive proofs, however, make it possible to finalize several blocks with one validity proof. This is because the proving circuit recursively aggregates multiple block proofs until one final proof is created. The L2 operator submits this recursive proof, and if the contract accepts it, all the relevant blocks will be finalized instantly. With recursive proofs, the number of ZK-rollup transactions that can be finalized on Ethereum at intervals increases. + +### Pros and cons of ZK-rollups + +| Pros | Cons | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Validity proofs ensure correctness of offchain transactions and prevent operators from executing invalid state transitions. | The cost associated with computing and verifying validity proofs is substantial and can increase fees for rollup users. | +| Offers faster transaction finality as state updates are approved once validity proofs are verified on L1. | Building EVM-compatible ZK-rollups is difficult due to complexity of zero-knowledge technology. | +| Relies on trustless cryptographic mechanisms for security, not the honesty of incentivized actors as with [optimistic rollups](/developers/docs/scaling/optimistic-rollups/#optimistic-pros-and-cons). | Producing validity proofs requires specialized hardware, which may encourage centralized control of the chain by a few parties. | +| Stores data needed to recover the offchain state on L1, which guarantees security, censorship-resistance, and decentralization. | Centralized operators (sequencers) can influence the ordering of transactions. | +| Users benefit from greater capital efficiency and can withdraw funds from L2 without delays. | Hardware requirements may reduce the number of participants that can force the chain to make progress, increasing the risk of malicious operators freezing the rollup's state and censoring users. | +| Doesn't depend on liveness assumptions and users don't have to validate the chain to protect their funds. | Some proving systems (e.g., ZK-SNARK) require a trusted setup which, if mishandled, could potentially compromise a ZK-rollup's security model. | +| Better data compression can help reduce the costs of publishing `calldata` on Ethereum and minimize rollup fees for users. | | + +### A visual explanation of ZK-rollups + +Watch Finematics explain ZK-rollups: + + + + +## Who is working on a zkEVM? + +Projects working on zkEVMs include: + +- **[zkEVM](https://github.com/privacy-scaling-explorations/zkevm-specs)** - _zkEVM is a project funded by the Ethereum Foundation to develop an EVM-compatible ZK-rollup and a mechanism for generating validity proofs for Ethereum blocks._ + +- **[Polygon zkEVM](https://polygon.technology/solutions/polygon-zkevm)** - _is a decentralized ZK Rollup on the Ethereum mainnet working on a zero-knowledge Ethereum Virtual Machine (zkEVM) that executes Ethereum transactions in a transparent way, including smart contracts with zero-knowledge-proof validations._ + +- **[Scroll](https://scroll.io/blog/zkEVM)** - _Scroll is a tech-driven company working on building a native zkEVM Layer 2 Solution for Ethereum._ + +- **[Taiko](https://taiko.xyz)** - _Taiko is a decentralized, Ethereum-equivalent ZK-rollup (a [Type 1 ZK-EVM](https://vitalik.eth.limo/general/2022/08/04/zkevm.html))._ + +- **[ZKsync](https://docs.zksync.io/)** - _ZKsync Era is an EVM-compatible ZK Rollup built by Matter Labs, powered by its own zkEVM._ + +- **[Starknet](https://starkware.co/starknet/)** - _StarkNet is an EVM-compatible layer 2 scaling solution built by StarkWare._ + +- **[Morph](https://www.morphl2.io/)** - _Morph is a hybrid rollup scaling solution that utilizes zk-proof to address the Layer 2 state challenge issue._ + +## Further reading on ZK-rollups reading + +- [What Are Zero-Knowledge Rollups?](https://coinmarketcap.com/alexandria/glossary/zero-knowledge-rollups) +- [What are zero-knowledge rollups?](https://alchemy.com/blog/zero-knowledge-rollups) +- [The Practical Guide To Ethereum Rollups](https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) +- [STARKs vs SNARKs](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/) +- [What is a zkEVM?](https://www.alchemy.com/overviews/zkevm) +- [ZK-EVM types: Ethereum-equivalent, EVM-equivalent, Type 1, Type 4, and other cryptic buzzwords](https://taiko.mirror.xyz/j6KgY8zbGTlTnHRFGW6ZLVPuT0IV0_KmgowgStpA0K4) +- [Intro to zkEVM](https://hackmd.io/@yezhang/S1_KMMbGt) +- [What are ZK-EVM L2s?](https://linea.mirror.xyz/qD18IaQ4BROn_Y40EBMTUTdJHYghUtdECscSWyMvm8M) +- [Awesome-zkEVM resources](https://github.com/LuozhuZhang/awesome-zkevm) +- [ZK-SNARKS under the hood](https://vitalik.eth.limo/general/2017/02/01/zk_snarks.html) +- [How are SNARKs possible?](https://vitalik.eth.limo/general/2021/01/26/snarks.html) + +--- + +## Developers > Docs > Smart Contracts > Anatomy + +A smart contract is a program that runs at an address on Ethereum. They're made up of data and functions that can execute upon receiving a transaction. Here's an overview of what makes up a smart contract. + +## Prerequisites + +Make sure you've read about [smart contracts](/developers/docs/smart-contracts/) first. This document assumes you're already familiar with programming languages such as JavaScript or Python. + +## Data + +Any contract data must be assigned to a location: either to `storage` or `memory`. It's costly to modify storage in a smart contract so you need to consider where your data should live. + +### Storage + +Persistent data is referred to as storage and is represented by state variables. These values get stored permanently on the blockchain. You need to declare the type so that the contract can keep track of how much storage on the blockchain it needs when it compiles. + +```solidity +// Solidity example +contract SimpleStorage +``` + +```python +# Vyper example +storedData: int128 +``` + +If you've already programmed object-oriented languages, you'll likely be familiar with most types. However `address` should be new to you if you're new to Ethereum development. + +An `address` type can hold an Ethereum address which equates to 20 bytes or 160 bits. It returns in hexadecimal notation with a leading 0x. + +Other types include: + +- boolean +- integer +- fixed point numbers +- fixed-size byte arrays +- dynamically-sized byte arrays +- Rational and integer literals +- String literals +- Hexadecimal literals +- Enums + +For more explanation, take a look at the docs: + +- [See Vyper types](https://vyper.readthedocs.io/en/v0.1.0-beta.6/types.html#value-types) +- [See Solidity types](https://solidity.readthedocs.io/en/latest/types.html#value-types) + +### Memory + +Values that are only stored for the lifetime of a contract function's execution are called memory variables. Since these are not stored permanently on the blockchain, they are much cheaper to use. + +Learn more about how the EVM stores data (Storage, Memory, and the Stack) in the [Solidity docs](https://solidity.readthedocs.io/en/latest/introduction-to-smart-contracts.html?highlight=memory#storage-memory-and-the-stack). + +### Environment variables + +In addition to the variables you define on your contract, there are some special global variables. They are primarily used to provide information about the blockchain or current transaction. + +Examples: + +| **Prop** | **State variable** | **Description** | +| ----------------- | ------------------ | ------------------------------------ | +| `block.timestamp` | uint256 | Current block epoch timestamp | +| `msg.sender` | address | Sender of the message (current call) | + +## Functions + +In the most simplistic terms, functions can get information or set information in response to incoming transactions. + +There are two types of function calls: + +- `internal` – these don't create an EVM call + - Internal functions and state variables can only be accessed internally (i.e. from within the current contract or contracts deriving from it) +- `external` – these do create an EVM call + - External functions are part of the contract interface, which means they can be called from other contracts and via transactions. An external function `f` cannot be called internally (i.e. `f()` does not work, but `this.f()` works). + +They can also be `public` or `private` + +- `public` functions can be called internally from within the contract or externally via messages +- `private` functions are only visible for the contract they are defined in and not in derived contracts + +Both functions and state variables can be made public or private + +Here's a function for updating a state variable on a contract: + +```solidity +// Solidity example +function update_name(string value) public +``` + +- The parameter `value` of type `string` is passed into the function: `update_name` +- It's declared `public`, meaning anyone can access it +- It's not declared `view`, so it can modify the contract state + +### View functions + +These functions promise not to modify the state of the contract's data. Common examples are "getter" functions – you might use this to receive a user's balance for example. + +```solidity +// Solidity example +function balanceOf(address _owner) public view returns (uint256 _balance) +``` + +```python +dappName: public(string) + +@view +@public +def readName() -> string: + return dappName +``` + +What is considered modifying state: + +1. Writing to state variables. +2. [Emitting events](https://solidity.readthedocs.io/en/v0.7.0/contracts.html#events). +3. [Creating other contracts](https://solidity.readthedocs.io/en/v0.7.0/control-structures.html#creating-contracts). +4. Using `selfdestruct`. +5. Sending ether via calls. +6. Calling any function not marked `view` or `pure`. +7. Using low-level calls. +8. Using inline assembly that contains certain opcodes. + +### Constructor functions + +`constructor` functions are only executed once when the contract is first deployed. Like `constructor` in many class-based programming languages, these functions often initialize state variables to their specified values. + +```solidity +// Solidity example +// Initializes the contract's data, setting the `owner` +// to the address of the contract creator. +constructor() public +``` + +```python +# Vyper example + +@external +def __init__(_beneficiary: address, _bidding_time: uint256): + self.beneficiary = _beneficiary + self.auctionStart = block.timestamp + self.auctionEnd = self.auctionStart + _bidding_time +``` + +### Built-in functions + +In addition to the variables and functions you define on your contract, there are some special built-in functions. The most obvious example is: + +- `address.send()` – Solidity +- `send(address)` – Vyper + +These allow contracts to send ETH to other accounts. + +## Writing functions + +Your function needs: + +- parameter variable and type (if it accepts parameters) +- declaration of internal/external +- declaration of pure/view/payable +- returns type (if it returns a value) + +```solidity +pragma solidity >=0.4.0 uint) public balances; + + // Events allow for logging of activity on the blockchain. + // Ethereum clients can listen for events in order to react to contract state changes. + // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events + event Transfer(address from, address to, uint amount); + + // Initializes the contract's data, setting the `owner` + // to the address of the contract creator. + constructor() public + + // Creates an amount of new tokens and sends them to an address. + function mint(address receiver, uint amount) public + + // Creates a random Pizza from string (name) + function createRandomPizza(string memory _name) public + + // Generates random DNA from string (name) and address of the owner (creator) + function generateRandomDna(string memory _str, address _owner) + public + // Functions marked as `pure` promise not to read from or modify the state + // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions + pure + returns (uint256) + + + // Returns array of Pizzas found by owner + function getPizzasByOwner(address _owner) + public + // Functions marked as `view` promise not to modify state + // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions + view + returns (uint256[] memory) + +} +``` + +## Further reading + +Check out Solidity and Vyper's documentation for a more complete overview of smart contracts: + +- [Solidity](https://solidity.readthedocs.io/) +- [Vyper](https://vyper.readthedocs.io/) + +## Related topics + +- [Smart contracts](/developers/docs/smart-contracts/) +- [Ethereum Virtual Machine](/developers/docs/evm/) + +## Related tutorials + +- [Downsizing contracts to fight the contract size limit](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) _– Some practical tips for reducing the size of your smart contract._ +- [Logging data from smart contracts with events](/developers/tutorials/logging-events-smart-contracts/) _– An introduction to smart contract events and how you can use them to log data._ +- [Interact with other contracts from Solidity](/developers/tutorials/interact-with-other-contracts-from-solidity/) _– How to deploy a smart contract from an existing contract and interact with it._ + +--- + +## Developers > Docs > Smart Contracts > Compiling + +You need to compile your contract so that your web app and the Ethereum virtual machine (EVM) can understand it. + +## Prerequisites + +You might find it helpful to have read our intro to [smart contracts](/developers/docs/smart-contracts/) and the [Ethereum virtual machine](/developers/docs/evm/) before reading about compilation. + +## The EVM + +For the [EVM](/developers/docs/evm/) to be able to run your contract it needs to be in **bytecode**. Compilation turns this: + +```solidity +pragma solidity 0.4.24; + +contract Greeter + +} +``` + +**into this** + +``` +PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xCFAE3217 EQ PUSH2 0x46 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x52 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x5B PUSH2 0xD6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x9B JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x80 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0xC8 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x48656C6C6F000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 SLT 0xec 0xe 0xf5 0xf8 SLT 0xc7 0x2d STATICCALL ADDRESS SHR 0xdb COINBASE 0xb1 BALANCE 0xe8 0xf8 DUP14 0xda 0xad DUP13 LOG1 0x4c 0xb4 0x26 0xc2 DELEGATECALL PUSH7 0x8994D3E002900 +``` + +These are called **opcodes**. EVM opcodes are the low-level instructions that the Ethereum Virtual Machine (EVM) can execute. Each opcode represents a specific operation, such as arithmetic operations, logical operations, data manipulation, control flow, etc. + +[More on opcodes](/developers/docs/evm/opcodes/) + +## Web applications + +The compiler will also produce the **Application Binary Interface (ABI)** which you need in order for your application to understand the contract and call the contract's functions. + +The ABI is a JSON file that describes the deployed contract and its smart contract functions. This helps bridge the gap between web2 and web3 + +A [JavaScript client library](/developers/docs/apis/javascript/) will read the **ABI** in order for you to call on your smart contract in your web app's interface. + +Below is the ABI for the ERC-20 token contract. An ERC-20 is a token you can trade on Ethereum. + +```json +[ + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + , + + ], + "name": "approve", + "outputs": [ + + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + , + , + + ], + "name": "transferFrom", + "outputs": [ + + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + + ], + "name": "balanceOf", + "outputs": [ + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + , + + ], + "name": "transfer", + "outputs": [ + + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + , + + ], + "name": "allowance", + "outputs": [ + + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + , + , + , + + ], + "name": "Approval", + "type": "event" + }, + , + , + + ], + "name": "Transfer", + "type": "event" + } +] +``` + +## Further reading + +- [ABI spec](https://solidity.readthedocs.io/en/v0.7.0/abi-spec.html) _– Solidity_ + +## Related topics + +- [JavaScript client libraries](/developers/docs/apis/javascript/) +- [Ethereum virtual machine](/developers/docs/evm/) + +--- + +## Developers > Docs > Smart Contracts > Composability + +## A brief introduction + +Smart contracts are public on Ethereum and can be thought of as open APIs. You don't need to write your own smart contract to become a dapp developer, you just need to know how to interact with them. For example, you can use the existing smart contracts of [Uniswap](https://uniswap.exchange/swap), a decentralized exchange, to handle all the token swap logic in your app – you don't need to start from scratch. Check out some of their [v2](https://github.com/Uniswap/uniswap-v2-core/tree/master/contracts) and [v3](https://github.com/Uniswap/uniswap-v3-core/tree/main/contracts) contracts. + +## What is composability? + +Composability is combining distinct components to create new systems or outputs. In software development, composability means developers can reuse existing software components to build new applications. A good way to understand composability is to think of composable elements as Lego blocks. Each Lego can be combined with another, allowing you to build complex structures by combining different Legos. + +In Ethereum, every smart contract is a Lego of sorts—you can use smart contracts from other projects as building blocks for your project. This means you don't have to spend time reinventing the wheel or building from scratch. + +## How does composability work? + +Ethereum smart contracts are like public APIs, so anyone can interact with the contract or integrate them into dapps for added functionality. Smart contract composability generally works off three principles: modularity, autonomy, and discoverability: + +**1. Modularity**: This is the ability of individual components to perform a specific task. In Ethereum, every smart contract has a specific use case (as shown in the Uniswap example). + +**2. Autonomy**: Composable components must be able to operate independently. Each smart contract in Ethereum is self-executing and can function without relying on other parts of the system. + +**3. Discoverability**: Developers cannot call external contracts or integrate software libraries into applications if the former are not publicly available. By design, smart contracts are open-source; anyone can call a smart contract or fork a codebase. + +## Benefits of composability + +### Shorter development cycle + +Composability reduces the work that developers have to do when creating [dapps](/dapps/#what-are-dapps). [As Naval Ravikant puts it:](https://twitter.com/naval/status/1444366754650656770) "Open source means every problem has to be solved once." + +If there is a smart contract that solves one problem, other developers can reuse it, so they don’t have to solve the same problem. This way, developers can take existing software libraries and add extra functionality to create new dapps. + +### Greater innovation + +Composability encourages innovation and experimentation because developers are free to reuse, modify, duplicate, or integrate open-source code to create desired results. As a result, development teams spend less time on basic functionality and can allocate more time experimenting with new features. + +### Better user experience + +Interoperability between components of the Ethereum ecosystem improves the user experience. Users can access greater functionality when dapps integrate external smart contracts than in a fragmented ecosystem where applications cannot communicate. + +We'll use an example from arbitrage trading to illustrate the benefits of interoperability: + +If a token is trading higher on `exchange A` than `exchange B`, you can take advantage of the price difference to make profit. However, you can only do that if you have enough capital to fund the transaction (i.e., buying the token from `exchange B` and selling it on `exchange A`). + +In a scenario where you don't have enough funds to cover the trade, a flash loan might be ideal. [Flash loans](/defi/#flash-loans) are highly technical, but the basic idea is that you can borrow assets (without collateral) and return same within _one_ transaction. + +Going back to our initial example, an arbitrage trader can take out a large flash loan, buy tokens from `exchange B`, sell them on `exchange A`, pay back the capital + interest, and keep the profit, within the same transaction. This complex logic requires combining calls to multiple contracts, which wouldn't be possible if smart contracts lacked interoperability. + +## Examples of composability in Ethereum + +### Token swaps + +If you create a dapp that requires transactions to be paid in ETH, you can allow users to pay in other ERC-20 tokens by integrating token swap logic. The code will automatically convert the user’s token to ETH before the contract executes the called function. + +### Governance + +Building bespoke governance systems for a [DAO](/dao/) can be expensive and time-consuming. Instead, you could use an open-source governance toolkit, such as [Aragon Client](https://client.aragon.org/), to bootstrap your DAO to quickly create a governance framework. + +### Identity management + +Instead of building a custom authentication system or relying on centralized providers, you can integrate decentralized identity (DID) tools to manage authentication for users. An example is [SpruceID](https://www.spruceid.com/), an open-source toolkit which offers a "Sign in with Ethereum" functionality that lets users authenticate identities with an Ethereum wallet. + +## Related tutorials + +- [Kickstart your dapp frontend development with create-eth-app](/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/) _– An overview of how to use create-eth-app to create apps with popular smart contracts out the box._ + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +- [Composability is Innovation](https://future.a16z.com/how-composability-unlocks-crypto-and-everything-else/) +- [Why Composability Matters For Web3](https://hackernoon.com/why-composability-matters-for-web3) +- [What is Composability?](https://blog.aragon.org/what-is-composability/#:~:text=Aragon,connect%20to%20every%20other%20piece.) + +--- + +## Developers > Docs > Smart Contracts > Deploying + +You need to deploy your smart contract for it to be available to users of an Ethereum network. + +To deploy a smart contract, you merely send an Ethereum transaction containing the compiled code of the smart contract without specifying any recipient. + +## Prerequisites + +You should understand [Ethereum networks](/developers/docs/networks/), [transactions](/developers/docs/transactions/) and the [anatomy of smart contracts](/developers/docs/smart-contracts/anatomy/) before deploying smart contracts. + +Deploying a contract also costs ether (ETH) since they are stored on the blockchain, so you should be familiar with [gas and fees](/developers/docs/gas/) on Ethereum. + +Finally, you'll need to compile your contract before deploying it, so make sure you've read about [compiling smart contracts](/developers/docs/smart-contracts/compiling/). + +## How to deploy a smart contract + +### What you'll need + +- Your contract's bytecode – this is generated through [compilation](/developers/docs/smart-contracts/compiling/) +- ETH for gas – you'll set your gas limit like other transactions so be aware that contract deployment needs a lot more gas than a simple ETH transfer +- a deployment script or plugin +- access to an [Ethereum node](/developers/docs/nodes-and-clients/), either by running your own, connecting to a public node, or via an API key using a [node service](/developers/docs/nodes-and-clients/nodes-as-a-service/) + +### Steps to deploy a smart contract + +The specific steps involved will depend on the development framework in question. For example, you can check out [Hardhat's documentation on deploying your contracts](https://hardhat.org/guides/deploying.html) or [Foundry's documentation on deploying and verifying a smart contract](https://book.getfoundry.sh/forge/deploying). Once deployed, your contract will have an Ethereum address like other [accounts](/developers/docs/accounts/) and can be verified using [source code verification tools](/developers/docs/smart-contracts/verifying/#source-code-verification-tools). + +## Related tools + +**Remix - _Remix IDE allows developing, deploying and administering smart contracts for Ethereum like blockchains_** + +- [Remix](https://remix.ethereum.org) + +**Tenderly - _Web3 development platform that provides debugging, observability, and infrastructure building blocks for developing, testing, monitoring, and operating smart contracts_** + +- [tenderly.co](https://tenderly.co/) +- [Docs](https://docs.tenderly.co/) +- [GitHub](https://github.com/Tenderly) +- [Discord](https://discord.gg/eCWjuvt) + +**Hardhat - _A development environment to compile, deploy, test, and debug your Ethereum software_** + +- [hardhat.org](https://hardhat.org/getting-started/) +- [Docs on deploying your contracts](https://hardhat.org/guides/deploying.html) +- [GitHub](https://github.com/nomiclabs/hardhat) +- [Discord](https://discord.com/invite/TETZs2KK4k) + +**thirdweb - _Easily deploy any contract to any EVM compatible chain, using a single command_** + +- [Documentation](https://portal.thirdweb.com/deploy/) + +**Crossmint - _Enterprise-grade web3 development platform to deploy smart contracts, enable credit-card and cross chain payments, and use APIs to create, distribute, sell, store, and edit NFTs._** + +- [crossmint.com](https://www.crossmint.com) +- [Documentation](https://docs.crossmint.com) +- [Discord](https://discord.com/invite/crossmint) +- [Blog](https://blog.crossmint.com) + +## Related tutorials + +- [Deploying your first smart contract](/developers/tutorials/deploying-your-first-smart-contract/) _– An introduction to deploying your first smart contract on an Ethereum test network._ +- [Hello World | smart contract tutorial](/developers/tutorials/hello-world-smart-contract/) _– An easy-to-follow tutorial to create & deploy a basic smart contract on Ethereum._ +- [Interact with other contracts from Solidity](/developers/tutorials/interact-with-other-contracts-from-solidity/) _– How to deploy a smart contract from an existing contract and interact with it._ +- [How to downsize your contract size](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) _- How to reduce your contract's size to keep it under the limit and save on gas_ + +## Further reading + +- [https://docs.openzeppelin.com/learn/deploying-and-interacting](https://docs.openzeppelin.com/learn/deploying-and-interacting) - _OpenZeppelin_ +- [Deploying your contracts with Hardhat](https://hardhat.org/guides/deploying.html) - _Nomic Labs_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Development frameworks](/developers/docs/frameworks/) +- [Run an Ethereum node](/developers/docs/nodes-and-clients/run-a-node/) +- [Nodes-as-a-service](/developers/docs/nodes-and-clients/nodes-as-a-service) + +--- + +## Developers > Docs > Smart Contracts > Formal Verification + +[Smart contracts](/developers/docs/smart-contracts/) are making it possible to create decentralized, trustless, and robust applications that introduce new use-cases and unlock value for users. Because smart contracts handle large amounts of value, security is a critical consideration for developers. + +Formal verification is one of the recommended techniques for improving [smart contract security](/developers/docs/smart-contracts/security/). Formal verification, which uses [formal methods](https://www.brookings.edu/techstream/formal-methods-as-a-path-toward-better-cybersecurity/) for specifying, designing, and verifying programs, has been used for years to ensure correctness of critical hardware and software systems. + +When implemented in smart contracts, formal verification can prove that a contract's business logic meets a predefined specification. Compared to other methods for assessing the correctness of contract code, such as testing, formal verification gives stronger guarantees that a smart contract is functionally correct. + +## What is formal verification? + +Formal verification refers to the process of evaluating the correctness of a system with respect to a formal specification. In simpler terms, formal verification allows us to check if the behavior of a system satisfies some requirements (i.e., it does what we want). + +Expected behaviors of the system (a smart contract in this case) are described using formal modeling, while specification languages enable the creation of formal properties. Formal verification techniques can then verify that the implementation of a contract complies with its specification and derive mathematical proof of the former's correctness. When a contract satisfies its specification, it is described as “functionally correct”, “correct by design”, or “correct by construction”. + +### What is a formal model? + +In computer science, a [formal model](https://en.wikipedia.org/wiki/Model_of_computation) is a mathematical description of a computational process. Programs are abstracted into mathematical functions (equations), with the model describing how outputs to functions are computed given an input. + +Formal models provide a level of abstraction over which analysis of a program's behavior can be evaluated. The existence of formal models allows for the creation of a _formal specification_, which describes desired properties of the model in question. + +Different techniques are used for modeling smart contracts for formal verification. For example, some models are used to reason about the high-level behavior of a smart contract. These modeling techniques apply a black-box view to smart contracts, viewing them as systems that accept inputs and execute computation based on those inputs. + +High-level models focus on the relationship between smart contracts and external agents, such as externally owned accounts (EOAs), contract accounts, and the blockchain environment. Such models are useful for defining properties that specify how a contract should behave in response to certain user interactions. + +Conversely, other formal models focus on the low-level behavior of a smart contract. While high-level models can help with reasoning about a contract's functionality, they may fail to capture details about the internal workings of the implementation. Low-level models apply a white-box view to program analysis and rely on lower-level representations of smart contract applications, such as program traces and [control flow graphs](https://en.wikipedia.org/wiki/Control-flow_graph), to reason about properties relevant to a contract's execution. + +Low-level models are considered ideal since they represent the actual execution of a smart contract in Ethereum's execution environment (i.e., the [EVM](/developers/docs/evm/)). Low-level modeling techniques are especially useful in establishing critical safety properties in smart contracts and detecting potential vulnerabilities. + +### What is a formal specification? + +A specification is simply a technical requirement that a particular system must satisfy. In programming, specifications represent general ideas about a program's execution (i.e., what the program should do). + +In the context of smart contracts, formal specifications refer to _properties_—formal descriptions of the requirements that a contract must satisfy. Such properties are described as "invariants" and represent logical assertions about a contract's execution that must remain true under every possible circumstance, without any exceptions. + +Thus, we can think of a formal specification as a collection of statements written in a formal language that describe the intended execution of a smart contract. Specifications cover a contract's properties and define how the contract should behave in different circumstances. The purpose of formal verification is to determine if a smart contract possesses these properties (invariants) and that these properties are not violated during execution. + +Formal specifications are critical in developing secure implementations of smart contracts. Contracts that fail to implement invariants or have their properties violated during execution are prone to vulnerabilities that can harm functionality or cause malicious exploits. + +## Types of formal specifications for smart contracts + +Formal specifications enable mathematical reasoning about the correctness of program execution. As with formal models, formal specifications can capture either high-level properties or the low-level behavior of a contract implementation. + +Formal specifications are derived using elements of [program logic](https://en.wikipedia.org/wiki/Logic_programming), which allow for formal reasoning about the properties of a program. A program logic has formal rules that express (in mathematical language) the expected behavior of a program. Various program logics are used in creating formal specifications, including [reachability logic](https://en.wikipedia.org/wiki/Reachability_problem), [temporal logic](https://en.wikipedia.org/wiki/Temporal_logic), and [Hoare logic](https://en.wikipedia.org/wiki/Hoare_logic). + +Formal specifications for smart contracts can be classified broadly as either **high-level** or **low-level** specifications. Regardless of what category a specification belongs to, it must adequately and unambiguously describe the property of the system under analysis. + +### High-level specifications + +As the name suggests, a high-level specification (also called a "model-oriented specification") describes the high-level behavior of a program. High-level specifications model a smart contract as a [finite state machine](https://en.wikipedia.org/wiki/Finite-state_machine) (FSM), which can transition between states by performing operations, with temporal logic used to define formal properties for the FSM model. + +[Temporal logics](https://en.wikipedia.org/wiki/Temporal_logic) are "rules for reasoning about propositions qualified in terms of time (e.g., "I am _always_ hungry" or "I will _eventually_ be hungry")." When applied to formal verification, temporal logics are used to state assertions about the correct behavior of systems modeled as state-machines. Specifically, a temporal logic describes the future states a smart contract can be in and how it transitions between states. + +High-level specifications generally capture two critical temporal properties for smart contracts: **safety** and **liveness**. Safety properties represent the idea that “nothing bad ever happens” and usually express invariance. A safety property may define general software requirements, such as freedom from [deadlock](https://www.techtarget.com/whatis/definition/deadlock), or express domain-specific properties for contracts (e.g., invariants on access control for functions, admissible values of state variables, or conditions for token transfers). + +Take for example this safety requirement which covers conditions for using the `transfer()` or `transferFrom()` in ERC-20 token contracts: _“A sender’s balance is never lower than requested amount of tokens to be sent.”_. This natural-language description of a contract invariant can be translated into a formal (mathematical) specification, which can then be rigorously checked for validity. + +Liveness properties assert that “something eventually good happens” and concern a contract’s ability to progress through different states. An example of a liveness property is “liquidity”, which refers to a contract's ability to transfer its balances to users on request. If this property is violated, users would be unable to withdraw assets stored in the contract, like what happened with the [Parity wallet incident](https://www.cnbc.com/2017/11/08/accidental-bug-may-have-frozen-280-worth-of-ether-on-parity-wallet.html). + +### Low-level specifications + +High-level specifications take as a starting point a finite-state model of a contract and define desired properties of this model. In contrast, low-level specifications (also called "property-oriented specifications") often model programs (smart contracts) as systems comprising a collection of mathematical functions and describe the correct behavior of such systems. + +In simpler terms, low-level specifications analyze _program traces_ and attempt to define properties of a smart contract over these traces. Traces refer to sequences of function executions that alter the state of a smart contract; hence, low-level specifications help specify requirements for a contract's internal execution. + +Low-level formal specifications can be given as either Hoare-style properties or invariants on execution paths. + +### Hoare-style properties + +[Hoare Logic](https://en.wikipedia.org/wiki/Hoare_logic) provides a set of formal rules for reasoning about the correctness of programs, including smart contracts. A Hoare-style property is represented by a Hoare triple `c`, where `c` is a program and `P` and `Q` are predicates on the state of the `c` (i.e., the program), formally described as _preconditions_ and _postconditions_, respectively. + +A precondition is a predicate describing the conditions required for the correct execution of a function; users calling into the contract must satisfy this requirement. A postcondition is a predicate describing the condition that a function establishes if correctly executed; users can expect this condition to be true after calling into the function. An _invariant_ in Hoare logic is a predicate that is preserved by execution of a function (i.e., it doesn't change). + +Hoare-style specifications can guarantee either _partial correctness_ or _total correctness_. The implementation of a contract function is "partially correct" if the precondition holds true before the function is executed, and if execution terminates, the postcondition is also true. Proof of total correctness is obtained if a precondition is true before the function executes, the execution is guaranteed to terminate and when it does, the postcondition holds true. + +Obtaining proof of total correctness is difficult since some executions may delay before terminating, or never terminate at all. That said, the question of whether execution terminates is arguably a moot point since Ethereum's gas mechanism prevents infinite program loops (execution terminates either successfully or ends due to 'out-of-gas' error). + +Smart contract specifications created using Hoare logic will have preconditions, postconditions, and invariants defined for the execution of functions and loops in a contract. Preconditions often include the possibility of erroneous inputs to a function, with postconditions describing the expected response to such inputs (e.g., throwing a specific exception). In this manner Hoare-style properties are effective for assuring correctness of contract implementations. + +Many formal verification frameworks use Hoare-style specifications for proving semantic correctness of functions. It is also possible to add Hoare-style properties (as assertions) directly to contract code by using the `require` and `assert` statements in Solidity. + +`require` statements express a precondition or invariant and are often used to validate user inputs, while `assert` captures a postcondition necessary for safety. For instance, proper access control for functions (an example of a safety property) can be achieved using `require` as a precondition check on the identity of the calling account. Similarly, an invariant on permissible values of state variables in a contract (e.g., total number of tokens in circulation) can be protected from violation by using `assert` to confirm the contract's state after function execution. + +### Trace-level properties + +Trace-based specifications describe operations that transition a contract between different states and the relationships between these operations. As explained earlier, traces are sequences of operations that alter the state of a contract in a particular way. + +This approach relies on model of smart contracts as state-transition systems with some predefined states (described by state variables) along with a set of predefined transitions (described by contract functions). Furthermore, a [control flow graph](https://www.geeksforgeeks.org/software-engineering-control-flow-graph-cfg/) (CFG), which is a graphical representation of a program's execution flow, is often used for describing operational semantics of a contract. Here, each trace represented as a path on the control flow graph. + +Primarily, trace-level specifications are used to reason about patterns of internal execution in smart contracts. By creating trace-level specifications, we assert the admissible execution paths (i.e., state transitions) for a smart contract. Using techniques, such as symbolic execution, we can formally verify that execution never follows a path not defined in the formal model. + +Let's use an example of a [DAO](/dao/) contract that has some publicly accessible functions to describe trace-level properties. Here, we assume the DAO contract allows users to perform the following operations: + +- Deposit funds + +- Vote on a proposal after depositing funds + +- Claim a refund if they don't vote on a proposal + +Example trace-level properties could be _"users that do not deposit funds cannot vote on a proposal"_ or _"users that do not vote on a proposal should always be able to claim a refund"_. Both properties assert preferred sequences of execution (voting cannot happen _before_ depositing funds and claiming a refunds cannot happen _after_ voting on a proposal). + +## Techniques for formal verification of smart contracts + +### Model checking + +Model checking is a formal verification technique in which an algorithm checks a formal model of a smart contract against its specification. In model checking smart contracts are often represented as state-transition systems, while properties on permissible contract states are defined using temporal logic. + +Model checking requires creating an abstract mathematical representation of a system (i.e., a contract) and expressing properties of this system using formulas rooted in [propositional logic](https://www.baeldung.com/cs/propositional-logic). This simplifies the task of the model-checking algorithm, namely to prove that a mathematical model satisfies a given logical formula. + +Model checking in formal verification is primarily used to evaluate temporal properties that describe the behavior of a contract over time. Temporal properties for smart contracts include _safety_ and _liveness_, which we explained earlier. + +For example, a security property related to access control (e.g., _Only the owner of the contract can call `selfdestruct`_) can be written in formal logic. Thereafter, the model-checking algorithm can verify if the contract satisfies this formal specification. + +Model checking uses state space exploration, which involves constructing all possible states of a smart contract and attempting to find reachable states that result in property violations. However, this can lead to an infinite number of states (known as the "state explosion problem"), hence model checkers rely on abstraction techniques to make efficient analysis of smart contracts possible. + +### Theorem proving + +Theorem proving is a method of mathematically reasoning about the correctness of programs, including smart contracts. It involves transforming the model of a contract’s system and its specifications into mathematical formulas (logic statements). + +The objective of theorem proving is to verify logical equivalence between these statements. “Logical equivalence” (also called “logical bi-implication”) is a type of relationship between two statements such that the first statement is true _if and only if_ the second statement is true. + +The required relationship (logical equivalence) between statements about a contract’s model and its property is formulated as a provable statement (called a theorem). Using a formal system of inference, the automated theorem prover can verify the theorem’s validity. In other words, a theorem prover can conclusively prove a smart contract’s model precisely matches its specifications. + +While model checking models contracts as transition systems with finite states, theorem proving can handle analysis of infinite-state systems. However, this means an automated theorem prover cannot always know if a logic problem is "decidable" or not. + +As a result, human assistance is often required to guide the theorem prover in deriving correctness proofs. The use of human effort in theorem proving makes it more expensive to use than model checking, which is fully automated. + +### Symbolic execution + +Symbolic execution is a method of analyzing a smart contract by executing functions using _symbolic values_ (e.g., `x > 5`) instead of _concrete values_ (e.g., `x == 5`). As a formal verification technique, symbolic execution is used to formally reason about trace-level properties in a contract's code. + +Symbolic execution represents an execution trace as a mathematical formula over symbolic input values, otherwise called a _path predicate_. An [SMT solver](https://en.wikipedia.org/wiki/Satisfiability_modulo_theories) is used to check if a path predicate is "satisfiable" (i.e., there exists a value that can satisfy the formula). If a vulnerable path is satisfiable, the SMT solver will generate a concrete value that triggers steers execution toward that path. + +Suppose a smart contract's function takes as input a `uint` value (`x`) and reverts when `x` is greater than `5` and also lower than `10`. Finding a value for `x` that triggers the error using a normal testing procedure would require running through dozens of test cases (or more) without the assurance of actually finding an error-triggering input. + +Conversely, a symbolic execution tool would execute the function with the symbolic value: `X > 5 ∧ X 5 ∧ X 5 ∧ X =x); + require(z>=y); + + return z; +``` + +An execution trace that results in an integer overflow would need to satisfy the formula: `z = x + y AND (z >= x) AND (z=>y) AND (z < x OR z < y)` Such a formula is unlikely to be solved, hence it serves a mathematical proof that the function `safe_add` never overflows. + +### Why use formal verification for smart contracts? + +#### Need for reliability + +Formal verification is used to assess the correctness of safety-critical systems whose failure can have devastating consequences, such as death, injury, or financial ruin. Smart contracts are high-value applications controlling enormous amounts of value, and simple errors in design can lead to [irrecoverable losses for users](https://www.freecodecamp.org/news/a-hacker-stole-31m-of-ether-how-it-happened-and-what-it-means-for-ethereum-9e5dc29e33ce/amp/). Formally verifying a contract before deployment, however, can increase guarantees that it will perform as expected once running on the blockchain. + +Reliability is a highly desired quality in any smart contract, especially because code deployed in the Ethereum Virtual Machine (EVM) is typically immutable. With post-launch upgrades not readily accessible, the need to guarantee reliability of contracts makes formal verification necessary. Formal verification is able to detect tricky issues, such as integer underflows and overflow, re-entrancy, and poor gas optimizations, which may slip past auditors and testers. + +#### Prove functional correctness + +Program testing is the most common method of proving that a smart contract satisfies some requirements. This involves executing a contract with a sample of the data it is expected to handle and analyzing its behavior. If the contract returns the expected results for the sample data, then developers have objective proof of its correctness. + +However, this approach cannot prove correct execution for input values that are not part of the sample. Therefore, testing a contract may help detect bugs (i.e., if some code paths fail to return desired results during execution), but **it cannot conclusively prove the absence of bugs**. + +Conversely, formal verification can formally prove that a smart contract satisfies requirements for an infinite range of executions _without_ running the contract at all. This requires creating a formal specification that precisely describes correct contract behaviors and developing a formal (mathematical) model of the contract's system. Then we can follow a formal proof procedure to check for consistency between the contract's model and its specification. + +With formal verification, the question of verifying if a contract's business logic satisfies requirements is a mathematical proposition that can be proved or disproved. By formally proving a proposition, we can verify an infinite number of test cases with a finite number of steps. In this manner formal verification has better prospects of proving a contract is functionally correct with respect to a specification. + +#### Ideal verification targets + +A verification target describes the system to be formally verified. Formal verification is best used in "embedded systems" (small, simple pieces of software that form part of a larger system). They are also ideal for specialized domains that have few rules, as this makes it easier to modify tools for verifying domain-specific properties. + +Smart contracts—at least, to some extent—fulfill both requirements. For example, the small size of Ethereum contracts makes them amenable to formal verification. Similarly, the EVM follows simple rules, which makes specifying and verifying semantic properties for programs running in the EVM easier. + +### Faster development cycle + +Formal verification techniques, such as model checking and symbolic execution, are generally more efficient than regular analysis of smart contract code (performed during testing or auditing). This is because formal verification relies on symbolic values to test assertions ("what if a user tries to withdraw _n_ ether?") unlike testing which uses concrete values ("what if a user tries to withdraw 5 ether?"). + +Symbolic input variables can cover multiple classes of concrete values, so formal verification approaches promise more code coverage in a shorter time frame. When used effectively, formal verification can accelerate the development cycle for developers. + +Formal verification also improves the process of building decentralized applications (dapps) by reducing costly design errors. Upgrading contracts (where possible) to fix vulnerabilities requires extensive rewriting of codebases and more effort spent on development. Formal verification can detect many errors in contract implementations that may slip past testers and auditors and provides ample opportunity to fix those issues before deploying a contract. + +## Drawbacks of formal verification + +### Cost of manual labor + +Formal verification, especially semi-automated verification in which a human guides the prover to derive correctness proofs, requires considerable manual labor. Moreover, creating formal specification is a complex activity that demands a high level of skill. + +These factors (effort and skill) makes formal verification more demanding and expensive compared to the usual methods of assessing correctness in contracts, such as testing and audits. Nevertheless, paying the cost for a full verification audit is practical, given the cost of errors in smart contract implementations. + +### False negatives + +Formal verification can only check if the execution of the smart contract matches the formal specification. As such, it is important to make sure the specification properly describes the expected behaviors of a smart contract. + +If specifications are poorly written, violations of properties—which point to vulnerable executions—cannot be detected by the formal verification audit. In this case, a developer might erroneously assume that the contract is bug-free. + +### Performance issues + +Formal verification runs into a number of performance issues. For instance, state and path explosion problems encountered during model checking and symbolic checking, respectively, can affect verification procedures. Also, formal verification tools often use SMT solvers and other constraint solvers in their underlying layer, and these solvers rely on computationally intensive procedures. + +Also, it is not always possible for program verifiers to determine if a property (described as a logical formula) can be satisfied or not (the "[decidability problem](https://en.wikipedia.org/wiki/Decision_problem)") because a program might never terminate. As such, it may be impossible to prove some properties for a contract even if it's well-specified. + +## Formal verification tools for Ethereum smart contracts + +### Specification languages for creating formal specifications + +**Act**: _*Act allows specification of storage updates, pre/post conditions and contract invariants. Its tool suite also has proof backends able to prove many properties via Coq, SMT solvers, or hevm.*_ + +- [GitHub](https://github.com/ethereum/act) +- [Documentation](https://ethereum.github.io/act/) + +**Scribble** - _*Scribble transforms code annotations in the Scribble specification language into concrete assertions that check the specification.*_ + +- [Documentation](https://docs.scribble.codes/) + +**Dafny** - _*Dafny is a verification-ready programming language that relies on high-level annotations to reason about and prove correctness of code.*_ + +- [GitHub](https://github.com/dafny-lang/dafny) + +### Program verifiers for checking correctness + +**Certora Prover** - _Certora Prover is an automatic formal verification tool for checking code correctness in smart contracts. Specifications are written in CVL (Certora Verification Language), with property violations detected using a combination of static analysis and constraint-solving._ + +- [Website](https://www.certora.com/) +- [Documentation](https://docs.certora.com/en/latest/index.html) + +**Solidity SMTChecker** - _*Solidity’s SMTChecker is a built-in model checker based on SMT (Satisfiability Modulo Theories) and Horn solving. It confirms if a contract’s source code matches specifications during compilation and statically checks for violations of safety properties.*_ + +- [GitHub](https://github.com/ethereum/solidity) + +**solc-verify** - _*solc-verify is an extended version of the Solidity compiler that can perform automated formal verification on Solidity code using annotations and modular program verification.*_ + +- [GitHub](https://github.com/SRI-CSL/solidity) + +**KEVM** - _*KEVM is a formal semantics of the Ethereum Virtual Machine (EVM) written in the K framework. KEVM is executable and can prove certain property-related assertions using reachability logic.*_ + +- [GitHub](https://github.com/runtimeverification/evm-semantics) +- [Documentation](https://jellopaper.org/) + +### Logical frameworks for theorem proving + +**Isabelle** - _Isabelle/HOL is a proof assistant that allows mathematical formulas to be expressed in a formal language and provides tools for proving those formulas. The main application is the formalization of mathematical proofs and in particular formal verification, which includes proving the correctness of computer hardware or software and proving properties of computer languages and protocols._ + +- [GitHub](https://github.com/isabelle-prover) +- [Documentation](https://isabelle.in.tum.de/documentation.html) + +**Coq** - _Coq is an interactive theorem prover that lets you define programs using theorems and interactively generate machine-checked proofs of correctness._ + +- [GitHub](https://github.com/coq/coq) +- [Documentation](https://coq.github.io/doc/v8.13/refman/index.html) + +### Symbolic execution-based tools for detecting vulnerable patterns in smart contracts + +**Manticore** - _*A tool for analyzing EVM bytecode analysis tool based on symbolic execution*._ + +- [GitHub](https://github.com/trailofbits/manticore) +- [Documentation](https://github.com/trailofbits/manticore/wiki) + +**hevm** - _*hevm is a symbolic execution engine and equivalence checker for EVM bytecode.*_ + +- [GitHub](https://github.com/dapphub/dapptools/tree/master/src/hevm) + +**Mythril** - _A symbolic execution tool for detecting vulnerabilities in Ethereum smart contracts_ + +- [GitHub](https://github.com/ConsenSys/mythril-classic) +- [Documentation](https://mythril-classic.readthedocs.io/en/develop/) + +## Further reading + +- [How Formal Verification of Smart Contracts Works](https://runtimeverification.com/blog/how-formal-verification-of-smart-contracts-works/) +- [How Formal Verification Can Ensure Flawless Smart Contracts](https://media.consensys.net/how-formal-verification-can-ensure-flawless-smart-contracts-cbda8ad99bd1) +- [An Overview of Formal Verification Projects in the Ethereum Ecosystem](https://github.com/leonardoalt/ethereum_formal_verification_overview) +- [End-to-End Formal Verification of Ethereum 2.0 Deposit Smart Contract](https://runtimeverification.com/blog/end-to-end-formal-verification-of-ethereum-2-0-deposit-smart-contract/) +- [Formally Verifying The World's Most Popular Smart Contract](https://www.zellic.io/blog/formal-verification-weth) +- [SMTChecker and Formal Verification](https://docs.soliditylang.org/en/v0.8.15/smtchecker.html) + +--- + +## Developers > Docs > Smart Contracts + +## What is a smart contract? + +A "smart contract" is simply a program that runs on the Ethereum blockchain. It's a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain. + +Smart contracts are a type of [Ethereum account](/developers/docs/accounts/). This means they have a balance and can be the target of transactions. However they're not controlled by a user, instead they are deployed to the network and run as programmed. User accounts can then interact with a smart contract by submitting transactions that execute a function defined on the smart contract. Smart contracts can define rules, like a regular contract, and automatically enforce them via the code. Smart contracts cannot be deleted by default, and interactions with them are irreversible. + +## Prerequisites + +If you're just getting started or looking for a less technical introduction, we recommend our [introduction to smart contracts](/smart-contracts/). + +Make sure you've read up on [accounts](/developers/docs/accounts/), [transactions](/developers/docs/transactions/) and the [Ethereum virtual machine](/developers/docs/evm/) before jumping into the world of smart contracts. + +## A digital vending machine + +Perhaps the best metaphor for a smart contract is a vending machine, as described by [Nick Szabo](https://unenumerated.blogspot.com/). With the right inputs, a certain output is guaranteed. + +To get a snack from a vending machine: + +``` +money + snack selection = snack dispensed +``` + +This logic is programmed into the vending machine. + +A smart contract, like a vending machine, has logic programmed into it. Here's a simple example of how this vending machine would look if it were a smart contract written in Solidity: + +```solidity +pragma solidity 0.8.7; + +contract VendingMachine + + // Allow the owner to increase the smart contract's cupcake balance + function refill(uint amount) public + + // Allow anyone to purchase cupcakes + function purchase(uint amount) public payable +} +``` + +Like how a vending machine removes the need for a vendor employee, smart contracts can replace intermediaries in many industries. + +## Permissionless + +Anyone can write a smart contract and deploy it to the network. You just need to learn how to code in a [smart contract language](/developers/docs/smart-contracts/languages/), and have enough ETH to deploy your contract. Deploying a smart contract is technically a transaction, so you need to pay [gas](/developers/docs/gas/) in the same way you need to pay gas for a simple ETH transfer. However, gas costs for contract deployment are far higher. + +Ethereum has developer-friendly languages for writing smart contracts: + +- Solidity +- Vyper + +[More on languages](/developers/docs/smart-contracts/languages/) + +However, they must be compiled before they can be deployed so that Ethereum's virtual machine can interpret and store the contract. [More on compilation](/developers/docs/smart-contracts/compiling/) + +## Composability + +Smart contracts are public on Ethereum and can be thought of as open APIs. This means you can call other smart contracts in your own smart contract to greatly extend what's possible. Contracts can even deploy other contracts. + +Learn more about [smart contract composability](/developers/docs/smart-contracts/composability/). + +## Limitations + +Smart contracts alone cannot get information about "real-world" events because they can't retrieve data from offchain sources. This means they can't respond to events in the real world. This is by design. Relying on external information could jeopardise consensus, which is important for security and decentralization. + +However, it is important for blockchain applications to be able to use offchain data. The solution is [oracles](/developers/docs/oracles/) which are tools that ingest offchain data and make it available to smart contracts. + +Another limitation of smart contracts is the maximum contract size. A smart contract can be a maximum of 24KB or it will run out of gas. This can be circumnavigated by using [The Diamond Pattern](https://eips.ethereum.org/EIPS/eip-2535). + +## Multisig contracts + +Multisig (multiple-signature) contracts are smart contract accounts that require multiple valid signatures to execute a transaction. This is very useful for avoiding single points of failure for contracts holding substantial amounts of ether or other tokens. Multisigs also divide responsibility for contract execution and key management between multiple parties and prevent the loss of a single private key leading to irreversible loss of funds. For these reasons, multisig contracts can be used for simple DAO governance. Multisigs require N signatures out of M possible acceptable signatures (where N ≤ M, and M > 1) in order to execute. `N = 3, M = 5` and `N = 4, M = 7` are commonly used. A 4/7 multisig requires four out of seven possible valid signatures. This means the funds are still retrievable even if three signatures are lost. In this case, it also means that the majority of key-holders must agree and sign in order for the contract to execute. + +## Smart contract resources + +**OpenZeppelin Contracts -** **_Library for secure smart contract development._** + +- [openzeppelin.com/contracts/](https://openzeppelin.com/contracts/) +- [GitHub](https://github.com/OpenZeppelin/openzeppelin-contracts) +- [Community Forum](https://forum.openzeppelin.com/c/general/16) + +## Further reading + +- [Coinbase: What is a smart contract?](https://www.coinbase.com/learn/crypto-basics/what-is-a-smart-contract) +- [Chainlink: What is a smart contract?](https://chain.link/education/smart-contracts) +- [Video: Simply Explained - Smart Contracts](https://youtu.be/ZE2HxTmxfrI) +- [Cyfrin Updraft: Web3 learning and auditing platform](https://updraft.cyfrin.io) + +--- + +## Developers > Docs > Smart Contracts > Languages + +A great aspect about Ethereum is that smart contracts can be programmed using relatively developer-friendly languages. If you're experienced with Python or any [curly-bracket language](https://wikipedia.org/wiki/List_of_programming_languages_by_type#Curly-bracket_languages), you can find a language with familiar syntax. + +The two most active and maintained languages are: + +- Solidity +- Vyper + +Remix IDE provides a comprehensive development environment for creating and testing contracts in both Solidity and Vyper. [Try the in-browser Remix IDE](https://remix.ethereum.org) to start coding. + +More experienced developers also might want to use Yul, an intermediate language for the [Ethereum Virtual Machine](/developers/docs/evm/), or Yul+, an extension to Yul. + +If you're curious and like to help test new languages that are still under heavy development you can experiment with Fe, an emerging smart contract language which is currently still in its infancy. + +## Prerequisites + +Previous knowledge of programming languages, especially of JavaScript or Python, can help you make sense of differences in smart contract languages. We also recommend you understand smart contracts as a concept before digging too deep into the language comparisons. [Intro to smart contracts](/developers/docs/smart-contracts/). + +## Solidity + +- Object-oriented, high-level language for implementing smart contracts. +- Curly-bracket language that has been most profoundly influenced by C++. +- Statically typed (the type of a variable is known at compile time). +- Supports: + - Inheritance (you can extend other contracts). + - Libraries (you can create reusable code that you can call from different contracts – like static functions in a static class in other object oriented programming languages). + - Complex user-defined types. + +### Important links + +- [Documentation](https://docs.soliditylang.org/en/latest/) +- [Solidity Language Portal](https://soliditylang.org/) +- [Solidity by Example](https://docs.soliditylang.org/en/latest/solidity-by-example.html) +- [GitHub](https://github.com/ethereum/solidity/) +- [Solidity Gitter Chatroom](https://gitter.im/ethereum/solidity) bridged to [Solidity Matrix Chatroom](https://matrix.to/#/#ethereum_solidity:gitter.im) +- [Cheat Sheet](https://reference.auditless.com/cheatsheet) +- [Solidity Blog](https://blog.soliditylang.org/) +- [Solidity Twitter](https://twitter.com/solidity_lang) + +### Example contract + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >= 0.7.0; + +contract Coin + + // Sends an amount of newly created coins to an address + // Can only be called by the contract creator + function mint(address receiver, uint amount) public + +If you're new to Ethereum and haven't done any coding with smart contract languages yet, we recommend getting started with Solidity or Vyper. Only look into Yul or Yul+ once you're familiar with smart contract security best practices and the specifics of working with the EVM. + +**Yul** + +- Intermediate language for Ethereum. +- Supports the [EVM](/developers/docs/evm) and [Ewasm](https://github.com/ewasm), an Ethereum flavored WebAssembly, and is designed to be a usable common denominator of both platforms. +- Good target for high-level optimisation stages that can benefit both EVM and Ewasm platforms equally. + +**Yul+** + +- A low-level, highly efficient extension to Yul. +- Initially designed for an [optimistic rollup](/developers/docs/scaling/optimistic-rollups/) contract. +- Yul+ can be looked at as an experimental upgrade proposal to Yul, adding new features to it. + +### Important links + +- [Yul Documentation](https://docs.soliditylang.org/en/latest/yul.html) +- [Yul+ Documentation](https://github.com/fuellabs/yulp) +- [Yul+ Playground](https://yulp.fuel.sh/) +- [Yul+ Introduction Post](https://medium.com/@fuellabs/introducing-yul-a-new-low-level-language-for-ethereum-aa64ce89512f) + +### Example contract + +The following simple example implements a power function. It can be compiled using `solc --strict-assembly --bin input.yul`. The example should +be stored in the input.yul file. + +``` + + case 1 + default + + } + } + let res := power(calldataload(0), calldataload(32)) + mstore(0, res) + return(0, 32) +} +``` + +If you are already well experienced with smart contracts, a full ERC20 implementation in Yul can be found [here](https://solidity.readthedocs.io/en/latest/yul.html#complete-erc20-example). + +## Fe + +- Statically typed language for the Ethereum Virtual Machine (EVM). +- Inspired by Python and Rust. +- Aims to be easy to learn -- even for developers who are new to the Ethereum ecosystem. +- Fe development is still in its early stages, the language had its alpha release in January 2021. + +### Important links + +- [GitHub](https://github.com/ethereum/fe) +- [Fe Announcement](https://snakecharmers.ethereum.org/fe-a-new-language-for-the-ethereum-ecosystem/) +- [Fe 2021 Roadmap](https://notes.ethereum.org/LVhaTF30SJOpkbG1iVw1jg) +- [Fe Discord Chat](https://discord.com/invite/ywpkAXFjZH) +- [Fe Twitter](https://twitter.com/official_fe) + +### Example contract + +The following is a simple contract implemented in Fe. + +``` +type BookMsg = bytes[100] + +contract GuestBook: + pub guest_book: map + + event Signed: + book_msg: BookMsg + + pub def sign(book_msg: BookMsg): + self.guest_book[msg.sender] = book_msg + + emit Signed(book_msg=book_msg) + + pub def get_msg(addr: address) -> BookMsg: + return self.guest_book[addr].to_mem() + +``` + +## How to choose + +As with any other programming language, it's mostly about choosing the right tool for the right job as well as personal preferences. + +Here are a few things to consider if you haven't tried any of the languages yet: + +### What is great about Solidity? + +- If you are a beginner, there are many tutorials and learning tools out there. See more about that in the [Learn by Coding](/developers/learning-tools/) section. +- Good developer tooling available. +- Solidity has a big developer community, which means you'll most likely find answers to your questions quite quickly. + +### What is great about Vyper? + +- Great way to get started for Python devs that want to write smart contracts. +- Vyper has a smaller number of features which makes it great for quick prototyping of ideas. +- Vyper aims to be easy to audit and maximally human-readable. + +### What is great about Yul and Yul+? + +- Simplistic and functional low-level language. +- Allows to get much closer to raw EVM, which can help to optimize the gas usage of your contracts. + +## Language comparisons + +For comparisons of basic syntax, the contract lifecycle, interfaces, operators, data structures, functions, control flow, and more check out this [cheatsheet by Auditless](https://reference.auditless.com/cheatsheet/) + +## Further reading + +- [Solidity Contracts Library by OpenZeppelin](https://docs.openzeppelin.com/contracts) +- [Solidity by Example](https://solidity-by-example.org) + +--- + +## Developers > Docs > Smart Contracts > Libraries + +You don't need to write every smart contract in your project from scratch. There are many open source smart contract libraries available that provide reusable building blocks for your project that can save you from having to reinvent the wheel. + +## Prerequisites + +Before jumping into smart contract libraries, it's a good idea to have a nice understanding of the structure of a smart contract. Head over to [smart contract anatomy](/developers/docs/smart-contracts/anatomy/) if you haven't done so yet. + +## What's in a library + +You can usually find two kinds of building blocks in smart contract libraries: reusable behaviors you can add to your contracts, and implementations of various standards. + +### Behaviors + +When writing smart contracts, there is a good chance you'll find yourself writing similar patterns over and over, like assigning an _admin_ address to carry out protected operations in a contract, or adding an emergency _pause_ button in the event of an unexpected issue. + +Smart contract libraries usually provide reusable implementations of these behaviors as [libraries](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#libraries) or via [inheritance](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#inheritance) in Solidity. + +As an example, following is a simplified version of the [`Ownable` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/access/Ownable.sol) from the [OpenZeppelin Contracts library](https://github.com/OpenZeppelin/openzeppelin-contracts), which designates an address as the owner of a contract, and provides a modifier for restricting access to a method only to that owner. + +```solidity +contract Ownable + + modifier onlyOwner() +} +``` + +To use a building block like this in your contract, you would need to first import it, and then extend from it in your own contracts. This will allow you to use the modifier provided by the base `Ownable` contract to secure your own functions. + +```solidity +import ".../Ownable.sol"; // Path to the imported library + +contract MyContract is Ownable +} +``` + +Another popular example is [SafeMath](https://docs.openzeppelin.com/contracts/3.x/utilities#math) or [DsMath](https://dappsys.readthedocs.io/en/latest/ds_math.html). These are libraries (as opposed to base contracts) that provide arithmetic functions with overflow checks, which are not provided by the language. It's a good practice to use either of these libraries instead of native arithmetic operations to guard your contract against overflows, which can have disastrous consequences! + +### Standards + +To facilitate [composability and interoperability](/developers/docs/smart-contracts/composability/), the Ethereum community has defined several standards in the form of **ERCs**. You can read more about them in the [standards](/developers/docs/standards/) section. + +When including an ERC as part of your contracts, it's a good idea to look for standard implementations rather than trying to roll out your own. Many smart contract libraries include implementations for the most popular ERCs. For example, the ubiquitous [ERC20 fungible token standard](/developers/tutorials/understand-the-erc-20-token-smart-contract/) can be found in [HQ20](https://github.com/HQ20/contracts/blob/master/contracts/token/README.md), [DappSys](https://github.com/dapphub/ds-token/) and [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc20). Additionally, some ERCs also provide canonical implementations as part of the ERC itself. + +It's worth mentioning that some ERCs are not standalone, but are additions to other ERCs. For example, [ERC2612](https://eips.ethereum.org/EIPS/eip-2612) adds an extension to ERC20 for improving its usability. + +## How to add a library + +Always refer to the documentation of the library you are including for specific instructions on how to include it in your project. Several Solidity contract libraries are packaged using `npm`, so you can just `npm install` them. Most tools for [compiling](/developers/docs/smart-contracts/compiling/) contracts will look into your `node_modules` for smart contract libraries, so you can do the following: + +```solidity +// This will load the @openzeppelin/contracts library from your node_modules +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract MyNFT is ERC721 +} +``` + +Regardless of the method you use, when including a library, always keep an eye on the [language](/developers/docs/smart-contracts/languages/) version. For instance, you cannot use a library for Solidity 0.6 if you are writing your contracts in Solidity 0.5. + +## When to use + +Using a smart contract library for your project has several benefits. First and foremost, it saves you time by providing you with ready-to-use building blocks you can include in your system, rather than having to code them yourself. + +Security is also a major plus. Open source smart contract libraries are also often heavily scrutinized. Given many projects depend on them, there is a strong incentive by the community to keep them under constant review. It's much more common to find errors in application code than in reusable contract libraries. Some libraries also undergo [external audits](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/audits) for additional security. + +However, using smart contract libraries carry the risk of including code you are not familiar with into your project. It's tempting to import a contract and include it directly into your project, but without a good understanding of what that contract does, you may be inadvertently introducing an issue in your system due to an unexpected behavior. Always make sure to read the documentation of the code you are importing, and then review the code itself before making it a part of your project! + +Last, when deciding on whether to include a library, consider its overall usage. A widely-adopted one has the benefits of having a larger community and more eyes looking into it for issues. Security should be your primary focus when building with smart contracts! + +## Related tools + +**OpenZeppelin Contracts -** **_Most popular library for secure smart contract development._** + +- [Documentation](https://docs.openzeppelin.com/contracts/) +- [GitHub](https://github.com/OpenZeppelin/openzeppelin-contracts) +- [Community Forum](https://forum.openzeppelin.com/c/general/16) + +**DappSys -** **_Safe, simple, flexible building-blocks for smart-contracts._** + +- [Documentation](https://dappsys.readthedocs.io/) +- [GitHub](https://github.com/dapphub/dappsys) + +**HQ20 -** **_A Solidity project with contracts, libraries and examples to help you build fully-featured distributed applications for the real world._** + +- [GitHub](https://github.com/HQ20/contracts) + +**thirdweb Solidity SDK -** **_Provides the tools needed to build custom smart contracts efficiently_** + +- [Documentation](https://portal.thirdweb.com/contracts/build/overview) +- [GitHub](https://github.com/thirdweb-dev/contracts) + +## Related tutorials + +- [Security considerations for Ethereum developers](/developers/docs/smart-contracts/security/) _– A tutorial on security considerations when building smart contracts, including library usage._ +- [Understand the ERC-20 token smart contract](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _-Tutorial on the ERC20 standard, provided by multiple libraries._ + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Smart Contracts > Security + +Smart contracts are extremely flexible, and capable of controlling large amounts of value and data, while running immutable logic based on code deployed on the blockchain. This has created a vibrant ecosystem of trustless and decentralized applications that provide many advantages over legacy systems. They also represent opportunities for attackers looking to profit by exploiting vulnerabilities in smart contracts. + +Public blockchains, like Ethereum, further complicate the issue of securing smart contracts. Deployed contract code _usually_ cannot be changed to patch security flaws, while assets stolen from smart contracts are extremely difficult to track and mostly irrecoverable due to immutability. + +Although figures vary, it is estimated that the total amount of value stolen or lost due to security defects in smart contracts is easily over $1 billion. This includes high-profile incidents, such as the [DAO hack](https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/) (3.6M ETH stolen, worth over $1B in today’s prices), [Parity multi-sig wallet hack](https://www.coindesk.com/markets/2017/07/19/30-million-ether-reported-stolen-due-to-parity-wallet-breach) ($30M lost to hackers), and the [Parity frozen wallet issue](https://www.theguardian.com/technology/2017/nov/08/cryptocurrency-300m-dollars-stolen-bug-ether) (over $300M in ETH locked forever). + +The aforementioned issues make it imperative for developers to invest effort in building secure, robust, and resilient smart contracts. Smart contract security is serious business, and one that every developer will do well to learn. This guide will cover security considerations for Ethereum developers and explore resources for improving smart contract security. + +## Prerequisites + +Make sure you’re familiar with the [fundamentals of smart contract development](/developers/docs/smart-contracts/) before tackling security. + +## Guidelines for building secure Ethereum smart contracts + +### 1. Design proper access controls + +In smart contracts, functions marked `public` or `external` can be called by any externally owned accounts (EOAs) or contract accounts. Specifying public visibility for functions is necessary if you want others to interact with your contract. Functions marked `private` however can only be called by functions within the smart contract, and not external accounts. Giving every network participant access to contract functions can cause problems, especially if it means anyone can perform sensitive operations (e.g., minting new tokens). + +To prevent unauthorized use of smart contract functions, it is necessary to implement secure access controls. Access control mechanisms restrict the ability to use certain functions in a smart contract to approved entities, such as accounts responsible for managing the contract. The **Ownable pattern** and **role-based control** are two patterns useful for implementing access control in smart contracts: + +#### Ownable pattern + +In the Ownable pattern, an address is set as the “owner” of the contract during the contract-creation process. Protected functions are assigned an `OnlyOwner` modifier, which ensures the contract authenticates the identity of the calling address before executing the function. Calls to protected functions from other addresses aside from the contract owner always revert, preventing unwanted access. + +#### Role-based access control + +Registering a single address as `Owner` in a smart contract introduces the risk of centralization and represents a single point-of-failure. If the owner’s account keys are compromised, attackers can attack the owned contract. This is why using a role-based access control pattern with multiple administrative accounts may be a better option. + +In role-based access control, access to sensitive functions is distributed between a set of trusted participants. For instance, one account may be responsible for minting tokens, while another account performs upgrades or pauses the contract. Decentralizing access control this way eliminates single points of failure and reduces trust assumptions for users. + +##### Using multi-signature wallets + +Another approach for implementing secure access control is using a [multi-signature account](/developers/docs/smart-contracts/#multisig) to manage a contract. Unlike a regular EOA, multi-signature accounts are owned by multiple entities and require signatures from a minimum number of accounts—say 3-of-5—to execute transactions. + +Using a multisig for access control introduces an extra layer of security since actions on the target contract require consent from multiple parties. This is particularly useful if using the Ownable pattern is necessary, as it makes it more difficult for an attacker or rogue insider to manipulate sensitive contract functions for malicious purposes. + +### 2. Use require(), assert(), and revert() statements to guard contract operations + +As mentioned, anyone can call public functions in your smart contract once it is deployed on the blockchain. Since you cannot know in advance how external accounts will interact with a contract, it is ideal to implement internal safeguards against problematic operations before deploying. You can enforce correct behavior in smart contracts by using the `require()`, `assert()`, and `revert()` statements to trigger exceptions and revert state changes if execution fails to satisfy certain requirements. + +**`require()`**: `require` are defined at the start of functions and ensures predefined conditions are met before the called function is executed. A `require` statement can be used to validate user inputs, check state variables, or authenticate the identity of the calling account before progressing with a function. + +**`assert()`**: `assert()` is used to detect internal errors and check for violations of “invariants” in your code. An invariant is a logical assertion about a contract’s state that should hold true for all function executions. An example invariant is the maximum total supply or balance of a token contract. Using `assert()` ensures that your contract never reaches a vulnerable state, and if it does, all changes to state variables are rolled back. + +**`revert()`**: `revert()` can be used in an if-else statement that triggers an exception if the required condition is not satisfied. The sample contract below uses `revert()` to guard the execution of functions: + +``` +pragma solidity ^0.8.4; + +contract VendingMachine + function withdraw() public +} +``` + +### 3. Test smart contracts and verify code correctness + +The immutability of code running in the [Ethereum Virtual Machine](/developers/docs/evm/) means smart contracts demand a higher level of quality assessment during the development phase. Testing your contract extensively and observing it for any unexpected results will improve security a great deal and protect your users in the long run. + +The usual method is to write small unit tests using mock data that the contract is expected to receive from users. [Unit testing](/developers/docs/smart-contracts/testing/#unit-testing) is good for testing the functionality of certain functions and ensuring a smart contract works as expected. + +Unfortunately, unit testing is minimally effective for improving smart contract security when used in isolation. A unit test might prove a function executes properly for mock data, but unit tests are only as effective as the tests that are written. This makes it difficult to detect missed edge cases and vulnerabilities that could break the safety of your smart contract. + +A better approach is to combine unit testing with property-based testing performed using [static and dynamic analysis](/developers/docs/smart-contracts/testing/#static-dynamic-analysis). Static analysis relies on low-level representations, such as [control flow graphs](https://en.wikipedia.org/wiki/Control-flow_graph) and [abstract syntax trees](https://deepsource.io/glossary/ast/) to analyze reachable program states and execution paths. Meanwhile, dynamic analysis techniques, such as [smart contract fuzzing](https://www.cyfrin.io/blog/smart-contract-fuzzing-and-invariants-testing-foundry), execute contract code with random input values to detect operations that violate security properties. + +[Formal verification](/developers/docs/smart-contracts/formal-verification) is another technique for verifying security properties in smart contracts. Unlike regular testing, formal verification can conclusively prove the absence of errors in a smart contract. This is achieved by creating a formal specification that captures desired security properties and proving that a formal model of the contracts adheres to this specification. + +### 4. Ask for an independent review of your code + +After testing your contract, it is good to ask others to check the source code for any security issues. Testing will not uncover every flaw in a smart contract, but getting an independent review increases the possibility of spotting vulnerabilities. + +#### Audits + +Commissioning a smart contract audit is one way of conducting an independent code review. Auditors play an important role in ensuring that smart contracts are secure and free from quality defects and design errors. + +That said, you should avoid treating audits as a silver bullet. Smart contract audits won't catch every bug and are mostly designed to provide an additional round of reviews, which can help detect issues missed by developers during initial development and testing. You should also follow best practices for working with auditors, such as documenting code properly and adding inline comments, to maximize the benefit of a smart contract audit. + +- [Smart contract auditing tips & tricks](https://twitter.com/tinchoabbate/status/1400170232904400897) - _@tinchoabbate_ +- [Make the most out of your audit](https://inference.ag/blog/2023-08-14-tips/) - _Inference_ + +#### Bug bounties + +Setting up a bug bounty program is another approach for implementing external code reviews. A bug bounty is a financial reward given to individuals (usually whitehat hackers) that discover vulnerabilities in an application. + +When used properly, bug bounties give members of the hacker community incentive to inspect your code for critical flaws. A real-life example is the “infinite money bug” that would have let an attacker create an unlimited amount of ether on [Optimism](https://www.optimism.io/), a [Layer 2](/layer-2/) protocol running on Ethereum. Fortunately, a whitehat hacker [discovered the flaw](https://www.saurik.com/optimism.html) and notified the team, [earning a large payout in the process](https://cryptoslate.com/critical-bug-in-ethereum-l2-optimism-2m-bounty-paid/). + +A useful strategy is to set the payout of a bug bounty program in proportion to the amount of funds at stake. Described as the “[scaling bug bounty](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7)”, this approach provides financial incentives for individuals to responsibly disclose vulnerabilities instead of exploiting them. + +### 5. Follow best practices during smart contract development + +The existence of audits and bug bounties doesn’t excuse your responsibility to write high-quality code. Good smart contract security starts with following proper design and development processes: + +- Store all code in a version control system, such as git + +- Make all code modifications via pull requests + +- Ensure pull requests have at least one independent reviewer—if you are working solo on a project, consider finding other developers and trade code reviews + +- Use a [development environment](/developers/docs/frameworks/) for testing, compiling, deploying smart contracts + +- Run your code through basic code analysis tools, such as, [Cyfrin Aderyn](https://github.com/Cyfrin/aderyn), Mythril and Slither. Ideally, you should do this before each pull request is merged and compare differences in output + +- Ensure your code compiles without errors, and the Solidity compiler emits no warnings + +- Properly document your code (using [NatSpec](https://solidity.readthedocs.io/en/develop/natspec-format.html)) and describe details about the contract architecture in easy-to-understand language. This will make it easier for others to audit and review your code. + +### 6. Implement robust disaster recovery plans + +Designing secure access controls, implementing function modifiers, and other suggestions can improve smart contract security, but they cannot rule out the possibility of malicious exploits. Building secure smart contracts requires “preparing for failure” and having a fallback plan for responding effectively to attacks. A proper disaster recovery plan will incorporate some or all of the following components: + +#### Contract upgrades + +While Ethereum smart contracts are immutable by default, it is possible to achieve some degree of mutability by using upgrade patterns. Upgrading contracts is necessary in cases where a critical flaw renders your old contract unusable and deploying new logic is the most feasible option. + +Contract upgrade mechanisms work differently, but the “proxy pattern” is one of the more popular approaches for upgrading smart contracts. [Proxy patterns](https://www.cyfrin.io/blog/upgradeable-proxy-smart-contract-pattern) split an application’s state and logic between _two_ contracts. The first contract (called a ‘proxy contract’) stores state variables (e.g., user balances), while the second contract (called a ‘logic contract’) holds the code for executing contract functions. + +Accounts interact with the proxy contract, which dispatches all function calls to the logic contract using the [`delegatecall()`](https://docs.soliditylang.org/en/v0.8.16/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries) low-level call. Unlike a regular message call, `delegatecall()` ensures the code running at the logic contract’s address is executed in the context of the calling contract. This means the logic contract will always write to the proxy’s storage (instead of its own storage) and the original values of `msg.sender` and `msg.value` are preserved. + +Delegating calls to the logic contract requires storing its address in the proxy contract's storage. Hence, upgrading the contract's logic is only a matter of deploying another logic contract and storing the new address in the proxy contract. As subsequent calls to the proxy contract are automatically routed to the new logic contract, you would have “upgraded” the contract without actually modifying the code. + +[More on upgrading contracts](/developers/docs/smart-contracts/upgrading/). + +#### Emergency stops + +As mentioned, extensive auditing and testing cannot possibly discover all bugs in a smart contract. If a vulnerability appears in your code after deployment, patching it is impossible since you cannot change the code running at the contract address. Also, upgrade mechanisms (e.g., proxy patterns) may take time to implement (they often require approval from different parties), which only gives attackers more time to cause more damage. + +The nuclear option is to implement an “emergency stop” function that blocks calls to vulnerable functions in a contract. Emergency stops typically comprise the following components: + +1. A global Boolean variable indicating if the smart contract is in a stopped state or not. This variable is set to `false` when setting up the contract, but will revert to `true` once the contract is stopped. + +2. Functions that reference the Boolean variable in their execution. Such functions are accessible when the smart contract is not stopped, and become inaccessible when the emergency stop feature is triggered. + +3. An entity that has access to the emergency stop function, which sets the Boolean variable to `true`. To prevent malicious actions, calls to this function can be restricted to a trusted address (e.g., the contract owner). + +Once the contract activates the emergency stop, certain functions will not be callable. This is achieved by wrapping select functions in a modifier that references the global variable. Below is [an example](https://github.com/fravoll/solidity-patterns/blob/master/EmergencyStop/EmergencyStop.sol) describing an implementation of this pattern in contracts: + +```solidity +// This code has not been professionally audited and makes no promises about safety or correctness. Use at your own risk. + +contract EmergencyStop + + modifier onlyWhenStopped + + modifier onlyAuthorized + + function stopContract() public onlyAuthorized + + function resumeContract() public onlyAuthorized + + function deposit() public payable stoppedInEmergency + + function emergencyWithdraw() public onlyWhenStopped +} +``` + +This example shows the basic features of emergency stops: + +- `isStopped` is a Boolean that evaluates to `false` at the beginning and `true` when the contract enters emergency mode. + +- The function modifiers `onlyWhenStopped` and `stoppedInEmergency` check the `isStopped` variable. `stoppedInEmergency` is used to control functions that should be inaccessible when the contract is vulnerable (e.g., `deposit()`). Calls to these functions will simply revert. + +`onlyWhenStopped` is used for functions that should be callable during an emergency (e.g., `emergencyWithdraw()`). Such functions can help resolve the situation, hence their exclusion from the “restricted functions” list. + +Using an emergency stop functionality provides an effective stopgap for dealing with serious vulnerabilities in your smart contract. However, it increases the need for users to trust developers not to activate it for self-serving reasons. To this end, decentralizing control of the emergency stop either by subjecting it to an onchain voting mechanism, timelock, or approval from a multisig wallet are possible solutions. + +#### Event monitoring + +[Events](https://docs.soliditylang.org/en/v0.8.15/contracts.html#events) allow you to track calls to smart contract functions and monitor changes to state variables. It is ideal to program your smart contract to emit an event whenever some party takes a safety-critical action (e.g., withdrawing funds). + +Logging events and monitoring them offchain provides insights on contract operations and aids faster discovery of malicious actions. This means your team can respond faster to hacks and take action to mitigate impact on users, such as pausing functions or performing an upgrade. + +You can also opt for an off-the-shelf monitoring tool that automatically forwards alerts whenever someone interacts with your contracts. These tools will allow you to create custom alerts based on different triggers, such as transaction volume, frequency of function calls, or the specific functions involved. For example, you could program an alert that comes in when the amount withdrawn in a single transaction crosses a particular threshold. + +### 7. Design secure governance systems + +You may want to decentralize your application by turning over control of core smart contracts to community members. In this case, the smart contract system will include a governance module—a mechanism that allows community members to approve administrative actions via an onchain governance system. For example, a proposal to upgrade a proxy contract to a new implementation may be voted upon by token-holders. + +Decentralized governance can be beneficial, especially because it aligns the interests of developers and end-users. Nevertheless, smart contract governance mechanisms may introduce new risks if implemented incorrectly. A plausible scenario is if an attacker acquires enormous voting power (measured in number of tokens held) by taking out a [flash loan](/defi/#flash-loans) and pushes through a malicious proposal. + +One way of preventing problems related to onchain governance is to [use a timelock](https://blog.openzeppelin.com/protect-your-users-with-smart-contract-timelocks/). A timelock prevents a smart contract from executing certain actions until a specific amount of time passes. Other strategies include assigning a “voting weight” to each token based on how long it has been locked up for, or measuring the voting power of an address at a historical period (for example, 2-3 blocks in the past) instead of the current block. Both methods reduce the possibility of quickly amassing voting power to swing onchain votes. + +More on [designing secure governance systems](https://blog.openzeppelin.com/smart-contract-security-guidelines-4-strategies-for-safer-governance-systems/), [different voting mechanisms in DAOs](https://hackernoon.com/governance-is-the-holy-grail-for-daos), and [the common DAO attack vectors leveraging DeFi](https://dacian.me/dao-governance-defi-attacks) in the shared links. + +### 8. Reduce complexity in code to a minimum + +Traditional software developers are familiar with the KISS (“keep it simple, stupid”) principle, which advises against introducing unnecessary complexity into software design. This follows the long-held thinking that “complex systems fail in complex ways” and are more susceptible to costly errors. + +Keeping things simple is of particular importance when writing smart contracts, given that smart contracts are potentially controlling large amounts of value. A tip for achieving simplicity when writing smart contracts is to reuse existing libraries, such as [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/4.x/), where possible. Because these libraries have been extensively audited and tested by developers, using them reduces the chances of introducing bugs by writing new functionality from scratch. + +Another common advice is to write small functions and keep contracts modular by splitting business logic across multiple contracts. Not only does writing simpler code reduce the attack surface in a smart contract, it also makes it easier to reason about the correctness of the overall system and detect possible design errors early. + +### 9. Defend against common smart contract vulnerabilities + +#### Reentrancy + +The EVM doesn’t permit concurrency, meaning two contracts involved in a message call cannot run simultaneously. An external call pauses the calling contract's execution and memory until the call returns, at which point execution proceeds normally. This process can be formally described as transferring [control flow](https://www.computerhope.com/jargon/c/contflow.htm) to another contract. + +Although mostly harmless, transferring control flow to untrusted contracts can cause problems, such as reentrancy. A reentrancy attack occurs when a malicious contract calls back into a vulnerable contract before the original function invocation is complete. This type of attack is best explained with an example. + +Consider a simple smart contract (‘Victim’) that allows anyone to deposit and withdraw ether: + +```solidity +// This contract is vulnerable. Do not use in production + +contract Victim + + function withdraw() external +} +``` + +This contract exposes a `withdraw()` function to allow users to withdraw ETH previously deposited in the contract. When processing a withdrawal, the contract performs the following operations: + +1. Checks the user’s ETH balance +2. Sends funds to the calling address +3. Resets their balance to 0, preventing additional withdrawals from the user + +The `withdraw()` function in `Victim` contract follows a “checks-interactions-effects” pattern. It _checks_ if conditions necessary for execution are satisfied (i.e., the user has a positive ETH balance) and performs the _interaction_ by sending ETH to the caller’s address, before applying the _effects_ of the transaction (i.e., reducing the user’s balance). + +If `withdraw()` is called from an externally owned account (EOA), the function executes as expected: `msg.sender.call.value()` sends ETH to the caller. However, if `msg.sender` is a smart contract account calls `withdraw()`, sending funds using `msg.sender.call.value()` will also trigger code stored at that address to run. + +Imagine this is the code deployed at the contract address: + +```solidity + contract Attacker + + function() external payable + } +} +``` + +This contract is designed to do three things: + +1. Accept a deposit from another account (likely the attacker’s EOA) +2. Deposit 1 ETH into the Victim contract +3. Withdraw the 1 ETH stored in the smart contract + +There’s nothing wrong here, except that `Attacker` has another function that calls `withdraw()` in `Victim` again if the gas left over from the incoming `msg.sender.call.value` is more than 40,000. This gives `Attacker` the ability to reenter `Victim` and withdraw more funds _before_ the first invocation of `withdraw` completes. The cycle looks like this: + +```solidity +- Attacker's EOA calls `Attacker.beginAttack()` with 1 ETH +- `Attacker.beginAttack()` deposits 1 ETH into `Victim` +- `Attacker` calls `withdraw() in `Victim` +- `Victim` checks `Attacker`’s balance (1 ETH) +- `Victim` sends 1 ETH to `Attacker` (which triggers the default function) +- `Attacker` calls `Victim.withdraw()` again (note that `Victim` hasn’t reduced `Attacker`’s balance from the first withdrawal) +- `Victim` checks `Attacker`’s balance (which is still 1 ETH because it hasn’t applied the effects of the first call) +- `Victim` sends 1 ETH to `Attacker` (which triggers the default function and allows `Attacker` to reenter the `withdraw` function) +- The process repeats until `Attacker` runs out of gas, at which point `msg.sender.call.value` returns without triggering additional withdrawals +- `Victim` finally applies the results of the first transaction (and subsequent ones) to its state, so `Attacker`’s balance is set to 0 +``` + +The summary is that because the caller’s balance isn't set to 0 until the function execution completes, subsequent invocations will succeed and allow the caller to withdraw their balance multiple times. This kind of attack can be used to drain a smart contract of its funds, like what happened in the [2016 DAO hack](https://www.coindesk.com/learn/understanding-the-dao-attack). Reentrancy attacks are still a critical issue for smart contracts today as [public listings of reentrancy exploits](https://github.com/pcaversaccio/reentrancy-attacks) show. + +##### How to prevent reentrancy attacks + +An approach to dealing with reentrancy is following the [checks-effects-interactions pattern](https://docs.soliditylang.org/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern). This pattern orders the execution of functions in a way that code that performs necessary checks before progressing with execution comes first, followed by code that manipulates contract state, with code that interacts with other contracts or EOAs arriving last. + +The checks-effect-interaction pattern is used in a revised version of the `Victim` contract shown below: + +```solidity +contract NoLongerAVictim +} +``` + +This contract performs a _check_ on the user’s balance, applies the _effects_ of the `withdraw()` function (by resetting the user’s balance to 0), and proceeds to perform the _interaction_ (sending ETH to the user’s address). This ensures the contract updates its storage before the external call, eliminating the re-entrancy condition that enabled the first attack. The `Attacker` contract could still call back into `NoLongerAVictim`, but since `balances[msg.sender]` has been set to 0, additional withdrawals will throw an error. + +Another option is to use a mutual exclusion lock (commonly described as a "mutex") that locks a portion of a contract’s state until a function invocation completes. This is implemented using a Boolean variable that is set to `true` before the function executes and reverts to `false` after the invocation is done. As seen in the example below, using a mutex protects a function against recursive calls while the original invocation is still processing, effectively stopping reentrancy. + +```solidity +pragma solidity ^0.7.0; + +contract MutexPattern + // This function is protected by a mutex, so reentrant calls from within `msg.sender.call` cannot call `withdraw` again. + // The `return` statement evaluates to `true` but still evaluates the `locked = false` statement in the modifier + function withdraw(uint _amount) public payable noReentrancy returns(bool) (""); + require(success); + + return true; + } +} +``` + +You can also use a [pull payments](https://docs.openzeppelin.com/contracts/4.x/api/security#PullPayment) system that requires users to withdraw funds from the smart contracts, instead of a "push payments" system that sends funds to accounts. This removes the possibility of inadvertently triggering code at unknown addresses (and can also prevent certain denial-of-service attacks). + +#### Integer underflows and overflows + +An integer overflow occurs when the results of an arithmetic operation falls outside the acceptable range of values, causing it to "roll over" to the lowest representable value. For example, a `uint8` can only store values up to 2^8-1=255. Arithmetic operations that result in values higher than `255` will overflow and reset `uint` to `0`, similar to how the odometer on a car resets to 0 once it reaches the maximum mileage (999999). + +Integer underflows happen for similar reasons: the results of an arithmetic operation falls below the acceptable range. Say you tried decrementing `0` in a `uint8`, the result would simply roll over to the maximum representable value (`255`). + +Both integer overflows and underflows can lead to unexpected changes to a contract’s state variables and result in unplanned execution. Below is an example showing how an attacker can exploit arithmetic overflow in a smart contract to perform an invalid operation: + +``` +pragma solidity ^0.7.6; + +// This contract is designed to act as a time vault. +// User can deposit into this contract but cannot withdraw for at least a week. +// User can also extend the wait time beyond the 1 week waiting period. + +/* +1. Deploy TimeLock +2. Deploy Attack with address of TimeLock +3. Call Attack.attack sending 1 ether. You will immediately be able to + withdraw your ether. + +What happened? +Attack caused the TimeLock.lockTime to overflow and was able to withdraw +before the 1 week waiting period. +*/ + +contract TimeLock + + function increaseLockTime(uint _secondsToIncrease) public + + function withdraw() public (""); + require(sent, "Failed to send Ether"); + } +} + +contract Attack + + fallback() external payable {} + + function attack() public payable (); + /* + if t = current lock time then we need to find x such that + x + t = 2**256 = 0 + so x = -t + 2**256 = type(uint).max + 1 + so x = type(uint).max + 1 - t + */ + timeLock.increaseLockTime( + type(uint).max + 1 - timeLock.lockTime(address(this)) + ); + timeLock.withdraw(); + } +} +``` + +##### How to prevent integer underflows and overflows + +As of version 0.8.0, the Solidity compiler rejects code that results in integer underflows and overflows. However, contracts compiled with a lower compiler version should either perform checks on functions involving arithmetic operations or use a library (e.g., [SafeMath](https://docs.openzeppelin.com/contracts/2.x/api/math)) that checks for underflow/overflow. + +#### Oracle manipulation + +[Oracles](/developers/docs/oracles/) source offchain information and send it onchain for smart contracts to use. With oracles, you can design smart contracts that interoperate with offchain systems, such as capital markets, greatly expanding their application. + +But if the oracle is corrupted and sends incorrect information onchain, smart contracts will execute based on erroneous inputs, which can cause problems. This is the basis of the “oracle problem”, which concerns the task of making sure information from a blockchain oracle is accurate, up-to-date, and timely. + +A related security concern is using an onchain oracle, such as a decentralized exchange, to get the spot price for an asset. Lending platforms in the [decentralized finance (DeFi)](/defi/) industry often do this to determine the value of a user’s collateral to determine how much they can borrow. + +DEX prices are often accurate, largely due to arbitrageurs restoring parity in markets. However, they are open to manipulation, particularly if the onchain oracle calculates asset prices based on historical trading patterns (as is usually the case). + +For instance, an attacker could artificially pump the spot price of an asset by taking out a flash loan right before interacting with your lending contract. Querying the DEX for the asset’s price would return a higher-than-normal value (due to the attacker’s large “buy order” skewing demand for the asset), allowing them to borrow more than they should. Such "flash loan attacks" have been used to exploit reliance on price oracles among DeFi applications, costing protocols millions in lost funds. + +##### How to prevent oracle manipulation + +The minimum requirement to [avoid oracle manipulation](https://www.cyfrin.io/blog/price-oracle-manipultion-attacks-with-examples) is to use a decentralized oracle network that queries information from multiple sources to avoid single points of failure. In most cases, decentralized oracles have built-in cryptoeconomic incentives to encourage oracle nodes to report correct information, making them more secure than centralized oracles. + +If you plan on querying an onchain oracle for asset prices, consider using one that implements a time-weighted average price (TWAP) mechanism. A [TWAP oracle](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles) queries the price of an asset at two different points in time (which you can modify) and calculates the spot price based on the average obtained. Choosing longer time periods protects your protocol against price manipulation since large orders executed recently cannot impact asset prices. + +## Smart contract security resources for developers + +### Tools for analyzing smart contracts and verifying code correctness + +- **[Testing tools and libraries](/developers/docs/smart-contracts/testing/#testing-tools-and-libraries)** - _Collection of industry-standard tools and libraries for performing unit tests, static analysis, and dynamic analysis on smart contracts._ + +- **[Formal verification tools](/developers/docs/smart-contracts/formal-verification/#formal-verification-tools)** - _Tools for verifying functional correctness in smart contracts and checking invariants._ + +- **[Smart contract auditing services](/developers/docs/smart-contracts/testing/#smart-contract-auditing-services)** - _Listing of organizations providing smart contract auditing services for Ethereum development projects._ + +- **[Bug bounty platforms](/developers/docs/smart-contracts/testing/#bug-bounty-platforms)** - _Platforms for coordinating bug bounties and rewarding responsible disclosure of critical vulnerabilities in smart contracts._ + +- **[Fork Checker](https://forkchecker.hashex.org/)** - _A free online tool for checking all available information regarding a forked contract._ + +- **[ABI Encoder](https://abi.hashex.org/)** - _A free online service for encoding your Solidity contract functions and constructor arguments._ + +- **[Aderyn](https://github.com/Cyfrin/aderyn)** - _Solidity Static Analyzer, traversing the Abstract Syntax Trees (AST) to pinpoint suspected vulnerabilities and printing out issues in an easy-to-consume markdown format._ + +### Tools for monitoring smart contracts + +- **[OpenZeppelin Defender Sentinels](https://docs.openzeppelin.com/defender/v1/sentinel)** - _A tool for automatically monitoring and responding to events, functions, and transaction parameters on your smart contracts._ + +- **[Tenderly Real-Time Alerting](https://tenderly.co/alerting/)** - _A tool for getting real-time notifications when unusual or unexpected events happen on your smart contracts or wallets._ + +### Tools for secure administration of smart contracts + +- **[OpenZeppelin Defender Admin](https://docs.openzeppelin.com/defender/v1/admin)** - _Interface for managing smart contract administration, including access controls, upgrades, and pausing._ + +- **[Safe](https://safe.global/)** - _Smart contract wallet running on Ethereum that requires a minimum number of people to approve a transaction before it can occur (M-of-N)._ + +- **[OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/4.x/)** - _Contract libraries for implementing administrative features, including contract ownership, upgrades, access controls, governance, pauseability, and more._ + +### Smart contract auditing services + +- **[ConsenSys Diligence](https://consensys.net/diligence/)** - _Smart contract auditing service helping projects across the blockchain ecosystem ensure their protocols are ready for launch and built to protect users._ + +- **[CertiK](https://www.certik.com/)** - _Blockchain security firm pioneering the use of cutting-edge formal Verification technology on smart contracts and blockchain networks._ + +- **[Trail of Bits](https://www.trailofbits.com/)** - _Cybersecurity company that combines security research with an attacker mentality to reduce risk and fortify code._ + +- **[PeckShield](https://peckshield.com/)** - _Blockchain security company offering products and services for the security, privacy, and usability of the entire blockchain ecosystem._ + +- **[QuantStamp](https://quantstamp.com/)** - _Auditing service facilitating the mainstream adoption of blockchain technology through security and risk assessment services._ + +- **[OpenZeppelin](https://www.openzeppelin.com/security-audits)** - _Smart contract security company providing security audits for distributed systems._ + +- **[Runtime Verification](https://runtimeverification.com/)** - _Security company specializing in formal modeling and verification of smart contracts._ + +- **[Hacken](https://hacken.io)** - _Web3 cybersecurity auditor bringing the 360-degree approach to blockchain security._ + +- **[Nethermind](https://www.nethermind.io/smart-contract-audits)** - _Solidity and Cairo auditing services, ensuring the integrity of smart contracts and the safety of users across Ethereum and Starknet._ + +- **[HashEx](https://hashex.org/)** - _HashEx focuses on blockchain and smart contract auditing to ensure the security of cryptocurrencies, providing services such as smart contract development, penetration testing, blockchain consulting._ + +- **[Code4rena](https://code4rena.com/)** - _Competitive audit platform that incentivizes smart contract security experts to find vulnerabilities and help make web3 more secure._ + +- **[CodeHawks](https://codehawks.com/)** - _Competitive audits platform hosting smart contracts auditing competitions for security researchers._ + +- **[Cyfrin](https://cyfrin.io)** - _Web3 security powerhouse, incubating crypto security through products and smart contract auditing services._ + +- **[ImmuneBytes](https://immunebytes.com/smart-contract-audit/)** - _Web3 security firm offering security audits for blockchain systems through a team of experienced auditors and best-in-class tools._ + +- **[Oxorio](https://oxor.io/)** - _Smart contract audits and blockchain security services with expertise in EVM, Solidity, ZK, Cross-chain tech for crypto firms and DeFi projects._ + +- **[Inference](https://inference.ag/)** - _Security auditing company, specialized in smart contract auditing for EVM-based blockchains. Thanks to its expert auditors they identify potential issues and suggest actionable solutions to fix them before deployment._ + +### Bug bounty platforms + +- **[Immunefi](https://immunefi.com/)** - _Bug bounty platform for smart contracts and DeFi projects, where security researchers review code, disclose vulnerabilities, get paid, and make crypto safer._ + +- **[HackerOne](https://www.hackerone.com/)** - _Vulnerability coordination and bug bounty platform that connects businesses with penetration testers and cybersecurity researchers._ + +- **[HackenProof](https://hackenproof.com/)** - _Expert bug bounty platform for crypto projects (DeFi, Smart Contracts, Wallets, CEX and more), where security professionals provide triage services and researchers get paid for relevant, verified bug reports._ + +- **[Sherlock](https://www.sherlock.xyz/)** - _Underwriter in Web3 for smart contract security, with payouts for auditors managed via smart contracts to secure that relevant bugs are paid fairly._ + +- **[CodeHawks](https://www.codehawks.com/)** - _Competitive bug bounty platform where auditors take part in security contests and challenges, and (soon) in their own private audits._ + +### Publications of known smart contract vulnerabilities and exploits + +- **[ConsenSys: Smart Contract Known Attacks](https://consensys.github.io/smart-contract-best-practices/attacks/)** - _Beginner-friendly explanation of the most significant contract vulnerabilities, with sample code for most cases._ + +- **[SWC Registry](https://swcregistry.io/)** - _Curated list of Common Weakness Enumeration (CWE) items that apply to Ethereum smart contracts._ + +- **[Rekt](https://rekt.news/)** - _Regularly updated publication of high-profile crypto hacks and exploits, along with detailed post-mortem reports._ + +### Challenges for learning smart contract security + +- **[Awesome BlockSec CTF](https://github.com/blockthreat/blocksec-ctfs)** - _Curated list of blockchain security wargames, challenges, and [Capture The Flag](https://www.webopedia.com/definitions/ctf-event/amp/) competitions and solution writeups._ + +- **[Damn Vulnerable DeFi](https://www.damnvulnerabledefi.xyz/)** - _Wargame to learn offensive security of DeFi smart contracts and build skills in bug-hunting and security auditing._ + +- **[Ethernaut](https://ethernaut.openzeppelin.com/)** - _Web3/Solidity-based wargame where each level is a smart contract that needs to be 'hacked'._ + +- **[HackenProof x HackTheBox](https://app.hackthebox.com/tracks/HackenProof-Track)** - _Smart contract hacking challenge, set in a fantasy adventure. Successful completion of the challenge also gives access to a private bug bounty program._ + +### Best practices for securing smart contracts + +- **[ConsenSys: Ethereum Smart Contract Security Best Practices](https://consensys.github.io/smart-contract-best-practices/)** - _Comprehensive list of guidelines for securing Ethereum smart contracts._ + +- **[Nascent: Simple Security Toolkit](https://github.com/nascentxyz/simple-security-toolkit)** - _Collection of practical security-focused guides and checklists for smart contract development._ + +- **[Solidity Patterns](https://fravoll.github.io/solidity-patterns/)** - _Useful compilation of secure patterns and best practices for the smart contract programming language Solidity._ + +- **[Solidity Docs: Security Considerations](https://docs.soliditylang.org/en/v0.8.16/security-considerations.html)** - _Guidelines for writing secure smart contracts with Solidity._ + +- **[Smart Contract Security Verification Standard](https://github.com/securing/SCSVS)** - _Fourteen-part checklist created to standardize the security of smart contracts for developers, architects, security reviewers and vendors._ + +- **[Learn Smart Contract Security and Auditing](https://updraft.cyfrin.io/courses/security)** - _Ultimate smart contract security and auditing course, created for smart contract developers looking to level up their security best practices and become security researchers._ + +### Tutorials on smart contract security + +- [How to write secure smart contracts](/developers/tutorials/secure-development-workflow/) + +- [How to use Slither to find smart contract bugs](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) + +- [How to use Manticore to find smart contract bugs](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) + +- [Smart contract security guidelines](/developers/tutorials/smart-contract-security-guidelines/) + +- [How to safely integrate your token contract with arbitrary tokens](/developers/tutorials/token-integration-checklist/) + +- [Cyfrin Updraft - Smart contracts security and auditing full course](https://updraft.cyfrin.io/courses/security) + +--- + +## Developers > Docs > Smart Contracts > Testing + +Public blockchains like Ethereum are immutable, making it difficult to change a smart contracts code after deployment. [Contract upgrade patterns](/developers/docs/smart-contracts/upgrading/) for performing "virtual upgrades" exist, but these are difficult to implement and require social consensus. Moreover, an upgrade can only fix an error _after_ it is discovered—if an attacker discovers the vulnerability first, your smart contract is at risk of an exploit. + +For these reasons, testing smart contracts before [deploying](/developers/docs/smart-contracts/deploying/) to Mainnet is a minimum requirement for [security](/developers/docs/smart-contracts/security/). There are many techniques for testing contracts and evaluating code correctness; what you choose depends on your needs. Nevertheless, a test suite made up of different tools and approaches is ideal for catching both minor and major security flaws in contract code. + +## Prerequisites + +This page explains how to test smart contracts before deploying on the Ethereum network. It assumes you're familiar with [smart contracts](/developers/docs/smart-contracts/). + +## What is smart contract testing? + +Smart contract testing is the process of verifying that the code of a smart contract works as expected. Testing is useful for checking if a particular smart contract satisfies requirements for reliability, usability, and security. + +Although approaches vary, most testing methods require executing a smart contract with a small sample of the data it is expected to handle. If the contract produces correct results for sample data, it is assumed to be functioning properly. Most testing tools provide resources for writing and executing [test cases](https://en.m.wikipedia.org/wiki/Test_case) to check if a contracts execution matches the expected results. + +### Why is it important to test smart contracts? + +As smart contracts often manage high-value financial assets, minor programming errors can and often lead to [massive losses for users](https://rekt.news/leaderboard/). Rigorous testing can, however, help you discover defects and issues in a smart contract's code early and fix them before launching on Mainnet. + +While it is possible to upgrade a contract if a bug is discovered, upgrades are complex and can [result in errors](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/) if handled improperly. Upgrading a contract further negates the principle of immutability and burdens users with additional trust assumptions. Conversely, a comprehensive plan for testing your contract mitigates smart contract security risks and reduces the need to perform complex logic upgrades after deploying. + +## Methods for testing smart contracts + +Methods for testing Ethereum smart contracts fall under two broad categories: **automated testing** and **manual testing**. Automated testing and manual testing offer unique benefits and tradeoffs, but you can combine both to create a robust plan for analyzing your contracts. + +### Automated testing + +Automated testing uses tools that automatically check a smart contracts code for errors in execution. The benefit of automated testing comes from using [scripts](https://www.techtarget.com/whatis/definition/script?amp=1) to guide the evaluation of contract functionalities. Scripted tests can be scheduled to run repeatedly with minimal human intervention, making automated testing more efficient than manual approaches to testing. + +Automated testing is particularly useful when tests are repetitive and time-consuming; difficult to carry out manually; susceptible to human error; or involve evaluating critical contract functions. But automated testing tools can have drawbacks—they may miss certain bugs and produce many [false positives](https://www.contrastsecurity.com/glossary/false-positive). Hence, pairing automated testing with manual testing for smart contracts is ideal. + +### Manual testing + +Manual testing is human-aided and involves executing each test case in your test suite one after the other when analyzing a smart contracts correctness. This is unlike automated testing where you can simultaneously run multiple isolated tests on a contract and get a report showing all failing and passing tests. + +Manual testing can be carried out by a single individual following a written test plan that covers different test scenarios. You could also have multiple individuals or groups interact with a smart contract over a specified period as part of manual testing. Testers will compare the actual behavior of the contract against the expected behavior, flagging any difference as a bug. + +Effective manual testing requires considerable resources (skill, time, money, and effort), and it is possible—due to human error—to miss certain errors while executing tests. But manual testing can also be beneficial—for example, a human tester (e.g., an auditor) may use intuition to detect edge cases that an automated testing tool would miss. + +## Automated testing for smart contracts + +### Unit testing + +Unit testing evaluates contract functions separately and checks that each component works correctly. Good unit tests should be simple, quick to run and provide a clear idea of what went wrong if tests fail. + +Unit tests are useful for checking that functions return expected values and that contract storage is updated properly after function execution. Moreover, running unit tests after making changes to a contracts codebase ensures adding new logic does not introduce errors. Below are some guidelines for running effective unit tests: + +#### Guidelines for unit testing smart contracts + +##### 1. Understand your contracts business logic and workflow + +Before writing unit tests, it helps to know what functionalities a smart contract offers and how users will access and use those functions. This is particularly useful for running [happy path tests](https://en.m.wikipedia.org/wiki/Happy_path) that determine if functions in a contract return the correct output for valid user inputs. We'll explain this concept using this (abridged) example of [an auction contract](https://docs.soliditylang.org/en/v0.8.17/solidity-by-example.html?highlight=Auction%20contract#simple-open-auction) + +``` +constructor( + uint biddingTime, + address payable beneficiaryAddress + ) + +function bid() external payable + } + return true; + } + +function auctionEnd() external + +While unit testing debugs contract functions in isolation, integration tests evaluate the components of a smart contract as a whole. Integration testing can detect issues arising from cross-contract calls or interactions between different functions in the same smart contract. For example, integration tests can help check if things like [inheritance](https://docs.soliditylang.org/en/v0.8.12/contracts.html#inheritance) and dependency injection work properly. + +Integration testing is useful if your contract adopts a modular architecture or interfaces with other onchain contracts during execution. One way of running integration tests is to [fork the blockchain](/glossary/#fork) at a specific height (using a tool like [Forge](https://book.getfoundry.sh/forge/fork-testing) or [Hardhat](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks) and simulate interactions between your contract and deployed contracts. + +The forked blockchain will behave similarly to Mainnet and have accounts with associated states and balances. But it only acts as a sandboxed local development environment, meaning you won't need real ETH for transactions, for example, nor will your changes affect the real Ethereum protocol. + +### Property-based testing + +Property-based testing is the process of checking that a smart contract satisfies some defined property. Properties assert facts about a contract’s behavior that are expected to remain true in different scenarios—an example of a smart contract property could be "Arithmetic operations in the contract never overflow or underflow." + +**Static analysis** and **dynamic analysis** are two common techniques for executing property-based testing, and both can verify that the code for a program (a smart contract in this case) satisfies some predefined property. Some property-based testing tools come with predefined rules about expected contract properties and check the code against those rules, while others allow you to create custom properties for a smart contract. + +#### Static analysis + +A static analyzer takes as input the source code of a smart contract and outputs results declaring whether a contract satisfies a property or not. Unlike dynamic analysis, static analysis doesn't involve executing a contract to analyze it for correctness. Static analysis instead reasons about all the possible paths that a smart contract could take during execution (i.e., by examining the structure of the source code to determine what it would mean for the contracts operation at runtime). + +[Linting](https://www.perforce.com/blog/qac/what-lint-code-and-why-linting-important) and [static testing](https://www.techtarget.com/whatis/definition/static-analysis-static-code-analysis) are common methods for running static analysis on contracts. Both require analyzing low-level representations of a contracts execution such as [abstract syntax trees](https://en.m.wikipedia.org/wiki/Abstract_syntax_tree) and [control flow graphs](https://www.geeksforgeeks.org/software-engineering-control-flow-graph-cfg/amp/) output by the compiler. + +In most cases, static analysis is useful for detecting safety issues like use of unsafe constructs, syntax errors, or violations of coding standards in a contracts code. However, static analyzers are known to be generally unsound at detecting deeper vulnerabilities, and may produce excessive false positives. + +#### Dynamic analysis + +Dynamic analysis generates symbolic inputs (e.g., in [symbolic execution](https://en.m.wikipedia.org/wiki/Symbolic_execution)) or concrete inputs (e.g., in [fuzzing](https://owasp.org/www-community/Fuzzing)) to a smart contracts functions to see if any execution trace(s) violates specific properties. This form of property-based testing differs from unit tests in that test cases cover multiple scenarios and a program handles the generation of test cases. + +[Fuzzing](https://halborn.com/what-is-fuzz-testing-fuzzing/) is an example of a dynamic analysis technique for verifying arbitrary properties in smart contracts. A fuzzer invokes functions in a target contract with random or malformed variations of a defined input value. If the smart contract enters an error state (e.g., one where an assertion fails), the problem is flagged and inputs that drive execution toward the vulnerable path are produced in a report. + +Fuzzing is useful for evaluating a smart contracts input validation mechanism since improper handling of unexpected inputs might result in unintended execution and produce dangerous effects. This form of property-based testing can be ideal for many reasons: + +1. **Writing test cases to cover many scenarios is difficult.** A property test only requires that you define a behavior and a range of data to test the behavior with—the program automatically generates test cases based on the defined property. + +2. **Your test suite may not sufficiently cover all possible paths within the program.** Even with 100% coverage, it is possible to miss out on edge cases. + +3. **Unit tests prove a contract executes correctly for sample data, but whether the contract executes correctly for inputs outside the sample remains unknown.** Property tests execute a target contract with multiple variations of a given input value to find execution traces that cause assertion failures. Thus, a property test provides more guarantees that a contract executes correctly for a broad class of input data. + +### Guidelines for running property-based testing for smart contracts + +Running property-based testing typically starts with defining a property (e.g., absence of [integer overflows](https://github.com/ConsenSys/mythril/wiki/Integer-Overflow)) or collection of properties that you want to verify in a smart contract. You may also need to define a range of values within which the program can generate data for transaction inputs when writing property tests. + +Once configured properly, the property testing tool will execute your smart contracts functions with randomly generated inputs. If there are any assertion violations, you should get a report with concrete input data that violates the property under evaluation. See some of the guides below to get started with running property-based testing with different tools: + +- **[Static analysis of smart contracts with Slither](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/slither#slither)** +- **[Static analysis of smart contracts with Wake](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** +- **[Property-based testing with Brownie](https://eth-brownie.readthedocs.io/en/stable/tests-hypothesis-property.html)** +- **[Fuzzing contracts with Foundry](https://book.getfoundry.sh/forge/fuzz-testing)** +- **[Fuzzing contracts with Echidna](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna#echidna-tutorial)** +- **[Fuzzing contracts with Wake](https://ackeeblockchain.com/wake/docs/latest/testing-framework/fuzzing/)** +- **[Symbolic execution of smart contracts with Manticore](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore#manticore-tutorial)** +- **[Symbolic execution of smart contracts with Mythril](https://mythril-classic.readthedocs.io/en/master/tutorial.html)** + +## Manual testing for smart contracts + +Manual testing of smart contracts often comes later in the development cycle after running automated tests. This form of testing evaluates the smart contract as one fully integrated product to see if it performs as specified in the technical requirements. + +### Testing contracts on a local blockchain + +While automated testing performed in a local development environment can provide useful debugging information, you'll want to know how your smart contract behaves in a production environment. However, deploying to the main Ethereum chain incurs gas fees—not to mention that you or your users can lose real money if your smart contract still has bugs. + +Testing your contract on a local blockchain (also known as a [development network](/developers/docs/development-networks/)) is a recommended alternative to testing on Mainnet. A local blockchain is a copy of the Ethereum blockchain running locally on your computer which simulates the behavior of Ethereum's execution layer. As such, you can program transactions to interact with a contract without incurring significant overhead. + +Running contracts on a local blockchain could be useful as a form of manual integration testing. [Smart contracts are highly composable](/developers/docs/smart-contracts/composability/), allowing you to integrate with existing protocols—but you'll still need to ensure that such complex onchain interactions produce the correct results. + +[More on development networks.](/developers/docs/development-networks/) + +### Testing contracts on testnets + +A test network or testnet works exactly like Ethereum Mainnet, except that it uses ether (ETH) with no real-world value. Deploying your contract on a [testnet](/developers/docs/networks/#ethereum-testnets) means anyone can interact with it (e.g., via the dapp's frontend) without putting funds at risk. + +This form of manual testing is useful for evaluating the end-to-end flow of your application from a user’s point of view. Here, beta testers can also perform trial runs and report any issues with the contract’s business logic and overall functionality. + +Deploying on a testnet after testing on a local blockchain is ideal since the former is closer to the behavior of the Ethereum Virtual Machine. Therefore, it is common for many Ethereum-native projects to deploy dapps on testnets to evaluate a smart contracts operation under real-world conditions. + +[More on Ethereum testnets.](/developers/docs/development-networks/#public-beacon-testchains) + +## Testing vs. formal verification + +While testing helps confirm that a contract returns the expected results for some data inputs, it cannot conclusively prove the same for inputs not used during tests. Testing a smart contract, therefore, cannot guarantee "functional correctness" (i.e., it cannot show that a program behaves as required for _all_ sets of input values). + +Formal verification is an approach to assessing the correctness of software by checking whether a formal model of the program matches the formal specification. A formal model is an abstract mathematical representation of a program, while a formal specification defines a program's properties (i.e., logical assertions about the program's execution). + +Because properties are written in mathematical terms, it becomes possible to verify that a formal (mathematical) model of the system satisfies a specification using logical rules of inference. Thus, formal verification tools are said to produce ‘mathematical proof’ of a system’s correctness. + +Unlike testing, formal verification can be used to verify a smart contracts execution satisfies a formal specification for _all_ executions (i.e., it has no bugs) without needing to execute it with sample data. Not only does this reduce time spent on running dozens of unit tests, but it is also more effective at catching hidden vulnerabilities. That said, formal verification techniques lie on a spectrum depending on their difficulty of implementation and usefulness. + +[More on formal verification for smart contracts.](/developers/docs/smart-contracts/formal-verification) + +## Testing vs audits and bug bounties + +As mentioned, rigorous testing can rarely guarantee the absence of bugs in a contract; formal verification approaches can provide stronger assurances of correctness but are currently difficult to use and incur considerable costs. + +Still, you can further increase the possibility of catching contract vulnerabilities by getting an independent code review. [Smart contract audits](https://www.immunebytes.com/blog/what-is-a-smart-contract-audit/) and [bug bounties](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7) are two ways of getting others to analyze your contracts. + +Audits are performed by auditors experienced at finding cases of security flaws and poor development practices in smart contracts. An audit will usually include testing (and possibly formal verification) as well as a manual review of the entire codebase. + +Conversely, a bug bounty program usually involves offering a financial reward to an individual (commonly described as [whitehat hackers]()) that discovers a vulnerability in a smart contract and discloses it to developers. Bug bounties are similar to audits since it involves asking others to help find defects in smart contracts. + +The major difference is that bug bounty programs are open to the wider developer/hacker community and attract a broad class of ethical hackers and independent security professionals with unique skills and experience. This may be an advantage over smart contract audits that mainly rely on teams who may possess limited or narrow expertise. + +## Testing tools and libraries + +### Unit testing tools + +- **[solidity-coverage](https://github.com/sc-forks/solidity-coverage)** - _Code coverage tool for smart contracts written in Solidity._ + +- **[Waffle](https://ethereum-waffle.readthedocs.io/en/latest/)** - _Framework for advanced smart contract development and testing (based on ethers.js)_. + +- **[Remix Tests](https://github.com/ethereum/remix-project/tree/master/libs/remix-tests)** - _Tool for testing Solidity smart contracts. Works underneath Remix IDE "Solidity Unit Testing" plugin which is used to write and run test cases for a contract._ + +- **[OpenZeppelin Test Helpers](https://github.com/OpenZeppelin/openzeppelin-test-helpers)** - _Assertion library for Ethereum smart contract testing. Make sure your contracts behave as expected!_ + +- **[Brownie unit testing framework](https://eth-brownie.readthedocs.io/en/v1.0.0_a/tests.html)** - _Brownie utilizes Pytest, a feature-rich test framework that lets you write small tests with minimal code, scales well for large projects, and is highly extendable._ + +- **[Foundry Tests](https://github.com/foundry-rs/foundry/tree/master/crates/forge)** - _Foundry offers Forge, a fast and flexible Ethereum testing framework capable of executing simple unit tests, gas optimization checks, and contract fuzzing._ + +- **[Hardhat Tests](https://hardhat.org/hardhat-runner/docs/guides/test-contracts)** - _Framework for testing smart contracts based on ethers.js, Mocha, and Chai._ + +- **[ApeWorx](https://docs.apeworx.io/ape/stable/userguides/testing.html)** - _Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine._ + +- **[Wake](https://ackeeblockchain.com/wake/docs/latest/testing-framework/overview/)** - _Python-based framework for unit testing and fuzzing with strong debugging capabilities and cross-chain testing support, utilizing pytest and Anvil for best user experience and performance._ + +### Property-based testing tools + +#### Static analysis tools + +- **[Slither](https://github.com/crytic/slither)** - _Python-based Solidity static analysis framework for finding vulnerabilities, enhancing code comprehension, and writing custom analyses for smart contracts._ + +- **[Ethlint](https://ethlint.readthedocs.io/en/latest/)** - _Linter for enforcing style and security best practices for the Solidity smart contract programming language._ + +- **[Cyfrin Aderyn](https://cyfrin.io/tools/aderyn)** - _Rust-based static analyzer specifically designed for Web3 smart contract security and development._ + +- **[Wake](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** - _Python-based static analysis framework with vulnerability and code quality detectors, printers for extracting useful information from code and support for writing custom submodules._ + +#### Dynamic analysis tools + +- **[Echidna](https://github.com/crytic/echidna/)** - _Fast contract fuzzer for detecting vulnerabilities in smart contracts through property-based testing._ + +- **[Diligence Fuzzing](https://consensys.net/diligence/fuzzing/)** - _Automated fuzzing tool useful for detecting property violations in smart contract code._ + +- **[Manticore](https://manticore.readthedocs.io/en/latest/index.html)** - _Dynamic symbolic execution framework for analyzing EVM bytecode._ + +- **[Mythril](https://github.com/ConsenSys/mythril-classic)** - _EVM bytecode assessment tool for detecting contract vulnerabilities using taint analysis, concolic analysis, and control flow checking._ + +- **[Diligence Scribble](https://consensys.net/diligence/scribble/)** - _Scribble is a specification language and runtime verification tool that allows you to annotate smart contracts with properties that allow you to automatically test the contracts with tools such as Diligence Fuzzing or MythX._ + +## Related tutorials + +- [An overview and comparison of different testing products](/developers/tutorials/guide-to-smart-contract-security-tools/) \_ +- [How to use Echidna to test smart contracts](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) +- [How to use Manticore to find smart contract bugs](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) +- [How to use Slither to find smart contract bugs](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) +- [How to mock Solidity contracts for testing](/developers/tutorials/how-to-mock-solidity-contracts-for-testing/) +- [How to run unit tests in Solidity using Foundry](https://www.rareskills.io/post/foundry-testing-solidity) + +## Further reading + +- [An in-depth guide to testing Ethereum smart contracts](https://iamdefinitelyahuman.medium.com/an-in-depth-guide-to-testing-ethereum-smart-contracts-2e41b2770297) +- [How to test ethereum smart contracts](https://betterprogramming.pub/how-to-test-ethereum-smart-contracts-35abc8fa199d) +- [MolochDAO's unit testing guide for developers](https://github.com/MolochVentures/moloch/tree/4e786db8a4aa3158287e0935dcbc7b1e43416e38/test#moloch-testing-guide) +- [How to test smart contracts like a rockstar](https://forum.openzeppelin.com/t/test-smart-contracts-like-a-rockstar/1001) + +--- + +## Developers > Docs > Smart Contracts > Upgrading + +Smart contracts on Ethereum are self-executing programs that run in the Ethereum Virtual Machine (EVM). These programs are immutable by design, which prevents any updates to the business logic once the contract is deployed. + +While immutability is necessary for trustlessness, decentralization, and security of smart contracts, it may be a drawback in certain cases. For instance, immutable code can make it impossible for developers to fix vulnerable contracts. + +However, increased research into improving smart contracts has led to the introduction of several upgrade patterns. These upgrade patterns enable developers to upgrade smart contracts (while preserving immutability) by placing business logic in different contracts. + +## Prerequisites + +You should have a good understanding of [smart contracts](/developers/docs/smart-contracts/), [smart contract anatomy](/developers/docs/smart-contracts/anatomy/), and the [Ethereum Virtual Machine (EVM)](/developers/docs/evm/). This guide also assumes readers have a grasp of programming smart contracts. + +## What is a smart contract upgrade? + +A smart contract upgrade involves changing the business logic of a smart contract while preserving the contract's state. It is important to clarify that upgradeability and mutability are not the same, especially in the context of smart contracts. + +You still cannot change a program deployed to an address on the Ethereum network. But you can change the code that's executed when users interact with a smart contract. + +This can be done via the following methods: + +1. Creating multiple versions of a smart contract and migrating state (i.e., data) from the old contract to a new instance of the contract. + +2. Creating separate contracts to store business logic and state. + +3. Using proxy patterns to delegate function calls from an immutable proxy contract to a modifiable logic contract. + +4. Creating an immutable main contract that interfaces with and relies on flexible satellite contracts to execute specific functions. + +5. Using the diamond pattern to delegate function calls from a proxy contract to logic contracts. + +### Upgrade mechanism #1: Contract migration + +Contract migration is based on versioning—the idea of creating and managing unique states of the same software. Contract migration involves deploying a new instance of an existing smart contract and transferring storage and balances to the new contract. + +The newly deployed contract will have an empty storage, allowing you to recover data from the old contract and write it to the new implementation. Afterward, you will need to update all contracts that interacted with the old contract to reflect the new address. + +The last step in contract migration is to convince users to switch to using the new contract. The new contract version will retain user balances and addresses, which preserves immutability. If it's a token-based contract, you will also need to contact exchanges to discard the old contract and use the new contract. + +Contract migration is a relatively straightforward and safe measure for upgrading smart contracts without breaking user interactions. However, manually migrating user storage and balances to the new contract is time-intensive and can incur high gas costs. + +[More on contract migration.](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) + +### Upgrade mechanism #2: Data separation + +Another method for upgrading smart contracts is to separate business logic and data storage into separate contracts. This means users interact with the logic contract, while data is stored in the storage contract. + +The logic contract contains the code executed when users interact with the application. It also holds the storage contract's address and interacts with it to get and set data. + +Meanwhile, the storage contract holds the state associated with the smart contract, such as user balances and addresses. Note that the storage contract is owned by the logic contract and is configured with the latter's address at deployment. This prevents unauthorized contracts from calling the storage contract or updating its data. + +By default, the storage contract is immutable—but you can replace the logic contract it points to with a new implementation. This will change the code that runs in the EVM, while keeping storage and balances intact. + +Using this upgrade method requires updating the logic contract's address in the storage contract. You must also configure the new logic contract with the storage contract's address for reasons explained earlier. + +The data separation pattern is arguably easier to implement compared to contract migration. However, you'll have to manage multiple contracts and implement complex authorization schemes to protect smart contracts from malicious upgrades. + +### Upgrade mechanism #3: Proxy patterns + +The proxy pattern also uses data separation to keep business logic and data in separate contracts. However, in a proxy pattern, the storage contract (called a proxy) calls the logic contract during code execution. This is a reverse of the data separation method, where the logic contract calls the storage contract. + +This is what happens in a proxy pattern: + +1. Users interact with the proxy contract, which stores data, but doesn't hold the business logic. + +2. The proxy contract stores the address of the logic contract and delegates all function calls to the logic contract (which holds the business logic) using the `delegatecall` function. + +3. After the call is forwarded to the logic contract, the returned data from the logic contract is retrieved and returned to the user. + +Using the proxy patterns requires an understanding of the **delegatecall** function. Basically, `delegatecall` is an opcode that allows a contract to call another contract, while the actual code execution happens in the context of the calling contract. An implication of using `delegatecall` in proxy patterns is that the proxy contract reads and writes to its storage and executes logic stored at the logic contract as if calling an internal function. + +From the [Solidity documentation](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries): + +> _There exists a special variant of a message call, named **delegatecall** which is identical to a message call apart from the fact that the code at the target address is executed in the context (i.e. at the address) of the calling contract and `msg.sender` and `msg.value` do not change their values._ _This means that a contract can dynamically load code from a different address at runtime. Storage, current address and balance still refer to the calling contract, only the code is taken from the called address._ + +The proxy contract knows to invoke `delegatecall` whenever a user calls a function because it has a `fallback` function built into it. In Solidity programming the [fallback function](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function) is executed when a function call does not match functions specified in a contract. + +Making the proxy pattern work requires writing a custom fallback function that specifies how the proxy contract should handle function calls it does not support. In this case the proxy's fallback function is programmed to initiate a delegatecall and reroute the user's request to the current logic contract implementation. + +The proxy contract is immutable by default, but new logic contracts with updated business logic can be created. Performing the upgrade is then a matter of changing the address of the logic contract referenced in the proxy contract. + +By pointing the proxy contract to a new logic contract, the code executed when users call the proxy contract function changes. This allows us to upgrade a contract's logic without asking users to interact with a new contract. + +Proxy patterns are a popular method for upgrading smart contracts because they eliminate the difficulties associated with contract migration. However, proxy patterns are more complicated to use and can introduce critical flaws, such as [function selector clashes](https://medium.com/nomic-foundation-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357), if used improperly. + +[More on proxy patterns](https://blog.openzeppelin.com/proxy-patterns/). + +### Upgrade mechanism #4: Strategy pattern + +This technique is influenced by the [strategy pattern](https://en.wikipedia.org/wiki/Strategy_pattern), which encourages creating software programs that interface with other programs to implement specific features. Applying the strategy pattern to Ethereum development would mean building a smart contract that calls functions from other contracts. + +The main contract in this case contains the core business logic, but interfaces with other smart contracts ("satellite contracts") to execute certain functions. This main contract also stores the address for each satellite contract and can switch between different implementations of the satellite contract. + +You can build a new satellite contract and configure the main contract with the new address. This allows you to change _strategies_ (i.e., implement new logic) for a smart contract. + +Although similar to the proxy pattern discussed earlier, the strategy pattern is different because the main contract, which users interact with, holds the business logic. Using this pattern affords you the opportunity to introduce limited changes to a smart contract without affecting the core infrastructure. + +The main drawback is that this pattern is mostly useful for rolling out minor upgrades. Also, if the main contract is compromised (e.g., via a hack), you cannot use this upgrade method. + +### Upgrade mechanism #5: Diamond pattern + +The diamond pattern can be considered an improvement on the proxy pattern. Diamond patterns differ from proxy patterns because the diamond proxy contract can delegate function calls to more than one logic contract. + +The logic contracts in the diamond pattern are known as _facets_. To make the diamond pattern work, you need to create a mapping in the proxy contract that maps [function selectors](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector) to different facet addresses. + +When a user makes a function call, the proxy contract checks the mapping to find the facet responsible for executing that function. Then it invokes `delegatecall` (using the fallback function) and redirects the call to the appropriate logic contract. + +The diamond upgrade pattern has some advantages over traditional proxy upgrade patterns: + +1. It allows you to upgrade a small part of the contract without changing all of the code. Using the proxy pattern for upgrades requires creating an entirely new logic contract, even for minor upgrades. + +2. All smart contracts (including logic contracts used in proxy patterns) have a 24KB size limit, which can be a limitation—especially for complex contracts requiring more functions. The diamond pattern makes it easy to solve this problem by splitting functions across multiple logic contracts. + +3. Proxy patterns adopt a catch-all approach to access controls. An entity with access to upgrade functions can change the _entire_ contract. But the diamond pattern enables a modular permissions approach, where you can restrict entities to upgrading certain functions within a smart contract. + +[More on the diamond pattern](https://eip2535diamonds.substack.com/p/introduction-to-the-diamond-standard?s=w). + +## Pros and cons of upgrading smart contracts + +| Pros | Cons | +| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A smart contract upgrade can make it easier to fix vulnerabilities discovered in the post-deployment phase. | Upgrading smart contracts negates the idea of code immutability, which has implications for decentralization and security. | +| Developers can use logic upgrades to add new features to decentralized applications. | Users must trust developers not to modify smart contracts arbitrarily. | +| Smart contract upgrades can improve safety for end-users since bugs can be fixed quickly. | Programming upgrade functionality into smart contracts adds another layer of complexity and increases the possibility of critical flaws. | +| Contract upgrades give developers more room to experiment with different features and improve dapps over time. | The opportunity to upgrade smart contracts may encourage developers to launch projects faster without doing due diligence during the development phase. | +| | Insecure access control or centralization in smart contracts can make it easier for malicious actors to perform unauthorized upgrades. | + +## Considerations for upgrading smart contracts + +1. Use secure access control/authorization mechanisms to prevent unauthorized smart contract upgrades, especially if using proxy patterns, strategy patterns, or data separation. An example is restricting access to the upgrade function, such that only the contract's owner can call it. + +2. Upgrading smart contracts is a complex activity and requires a high level of diligence to prevent the introduction of vulnerabilities. + +3. Reduce trust assumptions by decentralizing the process of implementing upgrades. Possible strategies include using a [multi-sig wallet contract](/developers/docs/smart-contracts/#multisig) to control upgrades, or requiring [members of a DAO](/dao/) to vote on approving the upgrade. + +4. Be aware of the costs involved in upgrading contracts. For instance, copying state (e.g., user balances) from an old contract to a new contract during contract migration may require more than one transaction, meaning more gas fees. + +5. Consider implementing **timelocks** to protect users. A timelock refers to a delay enforced on changes to a system. Timelocks can be combined with a multi-sig governance system to control upgrades: if a proposed action reaches the required approval threshold, it doesn't execute until the predefined delay period elapses. + +Timelocks give users some time to exit the system if they disagree with a proposed change (e.g., logic upgrade or new fee schemes). Without timelocks, users need to trust developers not to implement arbitrary changes in a smart contract without prior notice. The drawback here is that timelocks restrict the ability to quickly patch vulnerabilities. + +## Resources + +**OpenZeppelin Upgrades Plugins - _A suite of tools for deploying and securing upgradeable smart contracts._** + +- [GitHub](https://github.com/OpenZeppelin/openzeppelin-upgrades) +- [Documentation](https://docs.openzeppelin.com/upgrades) + +## Tutorials + +- [Upgrading your Smart Contracts | YouTube Tutorial](https://www.youtube.com/watch?v=bdXJmWajZRY) by Patrick Collins +- [Ethereum Smart Contract Migration Tutorial](https://medium.com/coinmonks/ethereum-smart-contract-migration-13f6f12539bd) by Austin Griffith +- [Using the UUPS proxy pattern to upgrade smart contracts](https://blog.logrocket.com/author/praneshas/) by Pranesh A.S +- [Web3 Tutorial: Write upgradeable smart contract (proxy) using OpenZeppelin](https://dev.to/yakult/tutorial-write-upgradeable-smart-contract-proxy-contract-with-openzeppelin-1916) by fangjun.eth + +## Further reading + +- [The State of Smart Contract Upgrades](https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/) by Santiago Palladino +- [Multiple ways to upgrade a Solidity smart contract](https://cryptomarketpool.com/multiple-ways-to-upgrade-a-solidity-smart-contract/) - Crypto Market Pool blog +- [Learn: Upgrading Smart Contracts](https://docs.openzeppelin.com/learn/upgrading-smart-contracts) - OpenZeppelin Docs +- [Proxy Patterns For Upgradeability Of Solidity Contracts: Transparent vs UUPS Proxies](https://mirror.xyz/0xB38709B8198d147cc9Ff9C133838a044d78B064B/M7oTptQkBGXxox-tk9VJjL66E1V8BUF0GF79MMK4YG0) by Naveen Sahu +- [How Diamond Upgrades Work](https://dev.to/mudgen/how-diamond-upgrades-work-417j) by Nick Mudge + +--- + +## Developers > Docs > Smart Contracts > Verifying + +[Smart contracts](/developers/docs/smart-contracts/) are designed to be “trustless”, meaning users shouldn’t have to trust third parties (e.g., developers and companies) before interacting with a contract. As a requisite for trustlessness, users and other developers must be able to verify a smart contract’s source code. Source code verification assures users and developers that the published contract code is the same code running at the contract address on the Ethereum blockchain. + +It is important to make the distinction between "source code verification" and "[formal verification](/developers/docs/smart-contracts/formal-verification/)". Source code verification, which will be explained in detail below, refers to verifying that the given source code of a smart contract in a high-level language (e.g. Solidity) compiles to the same bytecode to be executed at the contract address. However, formal verification describes verifying the correctness of a smart contract, meaning the contract behaves as expected. Although context-dependent, contract verification usually refers to source code verification. + +## What is source code verification? + +Before deploying a smart contract in the [Ethereum Virtual Machine (EVM)](/developers/docs/evm/), developers [compile](/developers/docs/smart-contracts/compiling/) the contract’s source code—instructions [written in Solidity](/developers/docs/smart-contracts/languages/) or another high-level programming language—to bytecode. As the EVM cannot interpret high-level instructions, compiling source code to bytecode (i.e., low-level, machine instructions) is necessary for executing contract logic in the EVM. + +Source code verification is comparing a smart contract’s source code and the compiled bytecode used during the contract creation to detect any differences. Verifying smart contracts matters because the advertised contract code may be different from what runs on the blockchain. + +Smart contract verification enables investigating what a contract does through the higher-level language it is written in, without having to read machine code. Functions, values, and usually the variable names and comments remain the same with the original source code that is compiled and deployed. This makes reading code much easier. Source verification also makes provision for code documentation, so that end-users know what a smart contract is designed to do. + +### What is full verification? + +There are some parts of the source code that do not affect the compiled bytecode such as comments or variable names. That means two source codes with different variable names and different comments would both be able to verify the same contract. With that, a malicious actor can add deceiving comments or give misleading variable names inside the source code and get the contract verified with a source code different than the original source code. + +It is possible to avoid this by appending extra data to the bytecode to serve as a _cryptographic guarantee_ for the exactness of the source code, and as a _fingerprint_ of the compilation information. The necessary information is found in the [Solidity's contract metadata](https://docs.soliditylang.org/en/v0.8.15/metadata.html), and the hash of this file is appended to the bytecode of a contract. You can see it in action in the [metadata playground](https://playground.sourcify.dev) + +The metadata file contains information about the compilation of the contract including the source files and their hashes. Meaning, if any of the compilation settings or even a byte in one of the source files change, the metadata file changes. Consequently the hash of the metadata file, which is appended to the bytecode, also changes. That means if a contract's bytecode + the appended metadata hash match with the given source code and compilation settings, we can be sure this is exactly the same source code used in the original compilation, not even a single byte is different. + +This type of verification that leverages the metadata hash is referred to as **"[full verification](https://docs.sourcify.dev/docs/full-vs-partial-match/)"** (also "perfect verification"). If the metadata hashes do not match or are not considered in verification it would be a "partial match", which currently is the more common way to verify contracts. It is possible to [insert malicious code](https://samczsun.com/hiding-in-plain-sight/) that wouldn't be reflected in the verified source code without full verification. Most developers are not aware of the full verification and don't keep the metadata file of their compilation, hence partial verification has been the de facto method to verify contracts so far. + +## Why is source code verification important? + +### Trustlessness + +Trustlessness is arguably the biggest premise for smart contracts and [decentralized applications (dapps)](/developers/docs/dapps/). Smart contracts are “immutable” and cannot be altered; a contract will only execute the business logic defined in the code at the time of deployment. This means developers and enterprises cannot tamper with a contract's code after deploying on Ethereum. + +For a smart contract to be trustless, the contract code should be available for independent verification. While the compiled bytecode for every smart contract is publicly available on the blockchain, low-level language is difficult to understand—for both developers and users. + +Projects reduce trust assumptions by publishing the source code of their contracts. But this leads to another problem: it is difficult to verify that the published source code matches the contract bytecode. In this scenario, the value of trustlessness is lost because users have to trust developers not to change a contract's business logic (i.e., by changing the bytecode) before deploying it on the blockchain. + +Source code verification tools provide guarantees that a smart contract’s source code files matches the assembly code. The result is a trustless ecosystem, where users don’t blindly trust third parties and instead verify code before depositing funds into a contract. + +### User Safety + +With smart contracts, there’s usually a lot of money at stake. This calls for higher security guarantees and verification of a smart contract’s logic before using it. The problem is that unscrupulous developers can deceive users by inserting malicious code in a smart contract. Without verification, malicious smart contracts can have [backdoors](https://www.trustnodes.com/2018/11/10/concerns-rise-over-backdoored-smart-contracts), controversial access control mechanisms, exploitable vulnerabilities, and other things that jeopardize user safety that would go undetected. + +Publishing a smart contract's source code files makes it easier for those interested, such as auditors, to assess the contract for potential attack vectors. With multiple parties independently verifying a smart contract, users have stronger guarantees of its security. + +## How to verify source code for Ethereum smart contracts + +[Deploying a smart contract on Ethereum](/developers/docs/smart-contracts/deploying/) requires sending a transaction with a data payload (compiled bytecode) to a special address. The data payload is generated by compiling the source code, plus the [constructor arguments](https://docs.soliditylang.org/en/v0.8.14/contracts.html#constructor) of the contract instance appended to the data payload in the transaction. Compilation is deterministic, meaning it always produces the same output (i.e., contract bytecode) if the same source files, and compilation settings (e.g. compiler version, optimizer) are used. + +![A diagram showing showing smart contract source code verification](./source-code-verification.png) + +Verifying a smart contract basically involves the following steps: + +1. Input the source files and compilation settings to a compiler. + +2. Compiler outputs the bytecode of the contract + +3. Get the bytecode of the deployed contract at a given address + +4. Compare the deployed bytecode with the recompiled bytecode. If the codes match, the contract gets verified with the given source code and compilation settings. + +5. Additionally, if the metadata hashes at the end of the bytecode match, it will be a full match. + +Note that this is a simplistic description of verification and there are many exceptions that would not work with this such as having [immutable variables](https://docs.sourcify.dev/docs/immutables/). + +## Source code verification tools + +The traditional process of verifying contracts can be complex. This is why we have tools for verifying source code for smart contracts deployed on Ethereum. These tools automate large parts of the source code verification and also curate verified contracts for the benefits of users. + +### Etherscan + +Although mostly known as an [Ethereum blockchain explorer](/developers/docs/data-and-analytics/block-explorers/), Etherscan also offers a [source code verification service](https://etherscan.io/verifyContract) for smart contract developers and users. + +Etherscan allows you to recompile contract bytecode from the original data payload (source code, library address, compiler settings, contract address, etc.) If the recompiled bytecode is associated with the bytecode (and constructor parameters) of the onchain contract, then [the contract is verified](https://info.etherscan.com/types-of-contract-verification/). + +Once verified, your contract’s source code receives a "Verified" label and is published on Etherscan for others to audit. It also gets added to the [Verified Contracts](https://etherscan.io/contractsVerified/) section—a repository of smart contracts with verified source codes. + +Etherscan is the most used tool for verifying contracts. However, Etherscan's contract verification has a drawback: it fails to compare the **metadata hash** of the onchain bytecode and recompiled bytecode. Therefore the matches in Etherscan are partial matches. + +[More on verifying contracts on Etherscan](https://medium.com/etherscan-blog/verifying-contracts-on-etherscan-f995ab772327). + +### Sourcify + +[Sourcify](https://sourcify.dev/#/verifier) is another tool for verifying contracts that is open-sourced and decentralized. It is not a block explorer and only verifies contracts on [different EVM based networks](https://docs.sourcify.dev/docs/chains). It acts as a public infrastructure for other tools to build on top of it, and aims to enable more human-friendly contract interactions using the [ABI](/developers/docs/smart-contracts/compiling/#web-applications) and [NatSpec](https://docs.soliditylang.org/en/v0.8.15/natspec-format.html) comments found in the metadata file. + +Unlike Etherscan, Sourcify supports full matches with the metadata hash. The verified contracts are served in its [public repository](https://docs.sourcify.dev/docs/repository/) on HTTP and [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/#what-is-ipfs), which is a decentralized, [content-addressed](https://web3.storage/docs/concepts/content-addressing/) storage. This allows fetching the metadata file of a contract over IPFS since the appended metadata hash is an IPFS hash. + +Additionally, one can also retrieve the source code files over IPFS, as IPFS hashes of these files are also found in the metadata. A contract can be verified by providing the metadata file and source files over its API or the [UI](https://sourcify.dev/#/verifier), or using the plugins. Sourcify monitoring tool also listens to contract creations on new blocks and tries to verify the contracts if their metadata and source files are published on IPFS. + +[More on verifying contracts on Sourcify](https://blog.soliditylang.org/2020/06/25/sourcify-faq/). + +### Tenderly + +The [Tenderly platform](https://tenderly.co/) enables Web3 developers to build, test, monitor, and operate smart contracts. Combining debugging tools with observability and infrastructure building blocks, Tenderly helps developers accelerate smart contract development. To fully enable Tenderly features, developers need to [perform source code verification](https://docs.tenderly.co/monitoring/contract-verification) using several methods. + +It's possible to verify a contract privately or publicly. If verified privately, the smart contract is visible only to you (and other members in your project). Verifying a contract publicly makes it visible to everyone using the Tenderly platform. + +You can verify your contracts using the [Dashboard](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-a-smart-contract), [Tenderly Hardhat plugin](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-contracts-using-the-tenderly-hardhat-plugin), or [CLI](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-contracts-using-cli). + +When verifying contracts through the Dashboard, you need to import the source file or the metadata file generated by the Solidity compiler, the address/network, and compiler settings. + +Using the Tenderly Hardhat plugin allows for more control over the verification process with less effort, enabling you to choose between automatic (no-code) and manual (code-based) verification. + +## Further reading + +- [Verifying contract source code](https://programtheblockchain.com/posts/2018/01/16/verifying-contract-source-code/) + +--- + +## Developers > Docs > Standards + +## Standards overview + +The Ethereum community has adopted many standards that help keep projects (such as [Ethereum clients](/developers/docs/nodes-and-clients/) and wallets) interoperable across implementations, and ensure smart contracts and dapps remain composable. + +Typically standards are introduced as [Ethereum Improvement Proposals](/eips/) (EIPs), which are discussed by community members through a [standard process](https://eips.ethereum.org/EIPS/eip-1). + +- [Introduction to EIPs](/eips/) +- [List of EIPs](https://eips.ethereum.org/) +- [EIP GitHub repo](https://github.com/ethereum/EIPs) +- [EIP discussion board](https://ethereum-magicians.org/c/eips) +- [Introduction to Ethereum Governance](/governance/) +- [Ethereum Governance Overview](https://web.archive.org/web/20201107234050/https://blog.bmannconsulting.com/ethereum-governance/) _March 31, 2019 - Boris Mann_ +- [Ethereum Protocol Development Governance and Network Upgrade Coordination](https://hudsonjameson.com/2020-03-23-ethereum-protocol-development-governance-and-network-upgrade-coordination/) _March 23, 2020 - Hudson Jameson_ +- [Playlist of all Ethereum Core Dev Meetings](https://www.youtube.com/@EthereumProtocol) _(YouTube Playlist)_ + +## Types of standards + +There are 3 types of EIPs: + +- Standards Track: describes any change that affects most or all Ethereum implementations +- [Meta Track](https://eips.ethereum.org/meta): describes a process surrounding Ethereum or proposes a change to a process +- [Informational Track](https://eips.ethereum.org/informational): describes an Ethereum design issue or provides general guidelines or information to the Ethereum community + +Furthermore, the Standard Track is subdivided into 4 categories: + +- [Core](https://eips.ethereum.org/core): improvements requiring a consensus fork +- [Networking](https://eips.ethereum.org/networking): improvements around devp2p and Light Ethereum Subprotocol, as well as proposed improvements to network protocol specifications of whisper and swarm. +- [Interface](https://eips.ethereum.org/interface): improvements around client API/RPC specifications and standards, and certain language-level standards like method names and contract ABIs. +- [ERC](https://eips.ethereum.org/erc): application-level standards and conventions + +More detailed information on these different types and categories can be found in [EIP-1](https://eips.ethereum.org/EIPS/eip-1#eip-types) + +### Token standards + +- [ERC-20](/developers/docs/standards/tokens/erc-20/) - A standard interface for fungible (interchangeable) tokens, like voting tokens, staking tokens or virtual currencies. + - [ERC-223](/developers/docs/standards/tokens/erc-223/) - A fungible tokens standard that makes tokens behave identical to ether and supports token transfers handling on the recipients side. + - [ERC-1363](https://eips.ethereum.org/EIPS/eip-1363) - Defines a token interface for ERC-20 tokens that supports executing recipient code after transfer or transferFrom, or spender code after approve. +- [ERC-721](/developers/docs/standards/tokens/erc-721/) - A standard interface for non-fungible tokens, like a deed for artwork or a song. + - [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) - A standardized event emitted when creating/transferring one, or many non-fungible tokens using consecutive token identifiers. + - [ERC-4400](https://eips.ethereum.org/EIPS/eip-4400) - Interface extension for EIP-721 consumer role. + - [ERC-4907](https://eips.ethereum.org/EIPS/eip-4907) - Add a time-limited role with restricted permissions to ERC-721 tokens. +- [ERC-777](/developers/docs/standards/tokens/erc-777/) - **(NOT RECOMMENDED)** A token standard improving over ERC-20. +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - A token standard which can contain both fungible and non-fungible assets. +- [ERC-4626](/developers/docs/standards/tokens/erc-4626/) - A tokenized vault standard designed to optimize and unify the technical parameters of yield-bearing vaults. + +Learn more about [token standards](/developers/docs/standards/tokens/). + +## Further reading + +- [Ethereum Improvement Proposals (EIPs)](/eips/) + +_Know of a community resource that helped you? Edit this page and add it!_ + +--- + +## Developers > Docs > Standards > Tokens > Erc 1155 + +## Introduction + +A standard interface for contracts that manage multiple token types. A single deployed contract may include any combination of fungible tokens, non-fungible tokens or other configurations (e.g. semi-fungible tokens). + +**What is meant by Multi-Token Standard?** + +The idea is simple and seeks to create a smart contract interface that can represent and control any number of fungible and non-fungible token types. In this way, the ERC-1155 token can do the same functions as an [ERC-20](/developers/docs/standards/tokens/erc-20/) and [ERC-721](/developers/docs/standards/tokens/erc-721/) token, and even both at the same time. It improves the functionality of both the ERC-20 and ERC-721 standards, making it more efficient and correcting obvious implementation errors. + +The ERC-1155 token is described fully in [EIP-1155](https://eips.ethereum.org/EIPS/eip-1155). + +## Prerequisites + +To better understand this page, we recommend you first read about [token standards](/developers/docs/standards/tokens/), [ERC-20](/developers/docs/standards/tokens/erc-20/), and [ERC-721](/developers/docs/standards/tokens/erc-721/). + +## ERC-1155 Functions and Features: + +- [Batch Transfer](#batch_transfers): Transfer multiple assets in a single call. +- [Batch Balance](#batch_balance): Get the balances of multiple assets in a single call. +- [Batch Approval](#batch_approval): Approve all tokens to an address. +- [Hooks](#receive_hook): Receive tokens hook. +- [NFT Support](#nft_support): If supply is only 1, treat it as NFT. +- [Safe Transfer Rules](#safe_transfer_rule): Set of rules for secure transfer. + +### Batch Transfers + +The batch transfer works very similar to regular ERC-20 transfers. Let's look at the regular ERC-20 `transferFrom` function: + +```solidity +// ERC-20 +function transferFrom(address from, address to, uint256 value) external returns (bool); + +// ERC-1155 +function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data +) external; +``` + +The only difference in ERC-1155 is that we pass the values as an array and we also pass an array of ids. For example given `ids=[3, 6, 13]` and `values=[100, 200, 5]`, the resulting transfers will be + +1. Transfer 100 tokens with id 3 from `_from` to `_to`. +2. Transfer 200 tokens with id 6 from `_from` to `_to`. +3. Transfer 5 tokens with id 13 from `_from` to `_to`. + +In ERC-1155 we only have `transferFrom`, no `transfer`. To use it like a regular `transfer`, just set the from address to the address that's calling the function. + +### Batch Balance + +The respective ERC-20 `balanceOf` call likewise has its partner function with batch support. As a reminder, this is the ERC-20 version: + +```solidity +// ERC-20 +function balanceOf(address owner) external view returns (uint256); + +// ERC-1155 +function balanceOfBatch( + address[] calldata _owners, + uint256[] calldata _ids +) external view returns (uint256[] memory); +``` + +Even simpler for the balance call, we can retrieve multiple balances in a single call. We pass the array of owners, followed by the array of token ids. + +For example given `_ids=[3, 6, 13]` and `_owners=[0xbeef..., 0x1337..., 0x1111...]`, the return value will be + +```solidity +[ + balanceOf(0xbeef...), + balanceOf(0x1337...), + balanceOf(0x1111...) +] +``` + +### Batch Approval + +```solidity +// ERC-1155 +function setApprovalForAll( + address _operator, + bool _approved +) external; + +function isApprovedForAll( + address _owner, + address _operator +) external view returns (bool); +``` + +The approvals are slightly different than ERC-20. Instead of approving specific amounts, you set an operator to approved or not approved via `setApprovalForAll`. + +Reading the current status can be done via `isApprovedForAll`. As you can see, it's an all-or-nothing operation. You cannot define how many tokens to approve or even which token class. + +This is intentionally designed with simplicity in mind. You can only approve everything for one address. + +### Receive Hook + +```solidity +function onERC1155BatchReceived( + address _operator, + address _from, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data +) external returns(bytes4); +``` + +Given the [EIP-165](https://eips.ethereum.org/EIPS/eip-165) support, ERC-1155 supports receive hooks for smart contracts only. The hook function must return a magic predefined bytes4 value which is given as: + +```solidity +bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)")) +``` + +When the receiving contract returns this value, it is assumed the contract accepts the transfer and knows how to handle the ERC-1155 tokens. Great, no more stuck tokens in a contract! + +### NFT Support + +When the supply is just one, the token is essentially a non-fungible token (NFT). And as is standard for ERC-721, you can define a metadata URL. The URL can be read and modified by clients, see [here](https://eips.ethereum.org/EIPS/eip-1155#metadata). + +### Safe Transfer Rule + +We've touched on a few safe transfer rules already in the previous explanations. But let's look at the most important of the rules: + +1. The caller must be approved to spend the tokens for the `_from` address or the caller must equal `_from`. +2. The transfer call must revert if + 1. `_to` address is 0. + 2. length of `_ids` is not the same as length of `_values`. + 3. any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + 4. any other error occurs. + +_Note_: All batch functions including the hook also exist as versions without batch. This is done for gas efficiency, considering transferring just one asset will likely still be the most commonly used way. We've left them out for simplicity in the explanations, including safe transfer rules. The names are identical, just remove the 'Batch'. + +## Further reading + +- [EIP-1155: Multi Token Standard](https://eips.ethereum.org/EIPS/eip-1155) +- [ERC-1155: Openzeppelin Docs](https://docs.openzeppelin.com/contracts/5.x/erc1155) +- [ERC-1155: GitHub Repo](https://github.com/enjin/erc-1155) +- [Alchemy NFT API](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) + +--- + +## Developers > Docs > Standards > Tokens > Erc 20 + +## Introduction + +**What is a Token?** + +Tokens can represent virtually anything in Ethereum: + +- reputation points in an online platform +- skills of a character in a game +- financial assets like a share in a company +- a fiat currency like USD +- an ounce of gold +- and more... + +Such a powerful feature of Ethereum must be handled by a robust standard, right? That's exactly +where the ERC-20 plays its role! This standard allows developers to build token applications that are interoperable with other products and services. The ERC-20 standard is also used to provide additional functionality to [ether](/glossary/#ether). + +**What is ERC-20?** + +The ERC-20 introduces a standard for Fungible Tokens, in other words, they have a property that makes each Token be exactly +the same (in type and value) as another Token. For example, an ERC-20 Token acts just like the ETH, meaning that 1 Token +is and will always be equal to all the other Tokens. + +## Prerequisites + +- [Accounts](/developers/docs/accounts) +- [Smart Contracts](/developers/docs/smart-contracts/) +- [Token standards](/developers/docs/standards/tokens/) + +## Body + +The ERC-20 (Ethereum Request for Comments 20), proposed by Fabian Vogelsteller in November 2015, is a Token Standard that +implements an API for tokens within Smart Contracts. + +Example functionalities ERC-20 provides: + +- transfer tokens from one account to another +- get the current token balance of an account +- get the total supply of the token available on the network +- approve whether an amount of token from an account can be spent by a third-party account + +If a Smart Contract implements the following methods and events it can be called an ERC-20 Token Contract and, once deployed, it +will be responsible to keep track of the created tokens on Ethereum. + +From [EIP-20](https://eips.ethereum.org/EIPS/eip-20): + +### Methods + +```solidity +function name() public view returns (string) +function symbol() public view returns (string) +function decimals() public view returns (uint8) +function totalSupply() public view returns (uint256) +function balanceOf(address _owner) public view returns (uint256 balance) +function transfer(address _to, uint256 _value) public returns (bool success) +function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) +function approve(address _spender, uint256 _value) public returns (bool success) +function allowance(address _owner, address _spender) public view returns (uint256 remaining) +``` + +### Events + +```solidity +event Transfer(address indexed _from, address indexed _to, uint256 _value) +event Approval(address indexed _owner, address indexed _spender, uint256 _value) +``` + +### Examples + +Let's see how a Standard is so important to make things simple for us to inspect any ERC-20 Token Contract on Ethereum. +We just need the Contract Application Binary Interface (ABI) to create an interface to any ERC-20 Token. As you can +see below we will use a simplified ABI, to make it a low friction example. + +#### Web3.py Example + +First, make sure you have installed [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python library: + +``` +pip install web3 +``` + +```python +from web3 import Web3 + + +w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com")) + +dai_token_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI +weth_token_addr = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # Wrapped ether (WETH) + +acc_address = "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11" # Uniswap V2: DAI 2 + +# This is a simplified Contract Application Binary Interface (ABI) of an ERC-20 Token Contract. +# It will expose only the methods: balanceOf(address), decimals(), symbol() and totalSupply() +simplified_abi = [ + ], + 'name': 'balanceOf', + 'outputs': [], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + } +] + +dai_contract = w3.eth.contract(address=w3.to_checksum_address(dai_token_addr), abi=simplified_abi) +symbol = dai_contract.functions.symbol().call() +decimals = dai_contract.functions.decimals().call() +totalSupply = dai_contract.functions.totalSupply().call() / 10**decimals +addr_balance = dai_contract.functions.balanceOf(acc_address).call() / 10**decimals + +# DAI +print("===== %s =====" % symbol) +print("Total Supply:", totalSupply) +print("Addr Balance:", addr_balance) + +weth_contract = w3.eth.contract(address=w3.to_checksum_address(weth_token_addr), abi=simplified_abi) +symbol = weth_contract.functions.symbol().call() +decimals = weth_contract.functions.decimals().call() +totalSupply = weth_contract.functions.totalSupply().call() / 10**decimals +addr_balance = weth_contract.functions.balanceOf(acc_address).call() / 10**decimals + +# WETH +print("===== %s =====" % symbol) +print("Total Supply:", totalSupply) +print("Addr Balance:", addr_balance) +``` + +## Known issues + +### ERC-20 token reception issue + +**As of 06/20/2024 at least $83,656,418 worth of ERC-20 tokens were lost due to this issue. Note that a pure ERC-20 implementation is prone to this problem unless you implement a set of additional restrictions on top of the standard as listed below.** + +When ERC-20 tokens are sent to a smart contract that is not designed to handle ERC-20 tokens, those tokens can be permanently lost. This happens because the receiving contract does not have the functionality to recognize or respond to the incoming tokens, and there’s no mechanism in the ERC-20 standard to notify the receiving contract about the incoming tokens. The main ways this issue takes form is through: + +1. Token transfer mechanism + - ERC-20 tokens are transferred using the transfer or transferFrom functions + - When a user sends tokens to a contract address using these functions, the tokens are transferred regardless of whether the receiving contract is designed to handle them +2. Lack of notification + - The receiving contract does not receive a notification or callback that tokens have been sent to it + - If the receiving contract lacks a mechanism to handle tokens (e.g., a fallback function or a dedicated function to manage token reception), the tokens are effectively stuck in the contract’s address +3. No built-in handling + - The ERC-20 standard does not include a mandatory function for receiving contracts to implement, leading to a situation where many contracts are unable to manage incoming tokens properly + +**Possible Solutions** + +While it is not possible to prevent this issue with ERC-20 completely there are methods that would allow to significantly reduce the possibility of a tokens loss for the end user: + +- The most common problem is when a user sends tokens to the token contract address itself (e.g. USDT deposited to the address of USDT token contract). It is recommended to restrict `transfer(..)` function to revert such transfer attempts. Consider adding `require(_to != address(this));` check within the implementation of the `transfer(..)` function. +- The `transfer(..)` function in general is not designed for depositing tokens to contracts. `approve(..) & transferFrom(..)` pattern is used to deposit ERC-20 tokens to contracts instead. It is possible to restrict the transfer function to disallow depositing tokens to any contracts with it, however it may break compatibility with contracts that assume tokens can be deposited to contracts with the `trasnfer(..)` function (e.g. Uniswap liqudity pools). +- Always assume that ERC-20 tokens can end up in your contract even if your contract is not supposed to ever receive any. There is no way to prevent or reject accidental deposits on the recipients end. It is recommended to implement a function that would allow to extract accidentally deposited ERC-20 tokens. +- Consider using alternative token standards. + +Some alternative standards have come out of this issue such as [ERC-223](/developers/docs/standards/tokens/erc-223) + +## Further reading + +- [EIP-20: ERC-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20) +- [OpenZeppelin - Tokens](https://docs.openzeppelin.com/contracts/3.x/tokens#ERC20) +- [OpenZeppelin - ERC-20 Implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) +- [Alchemy - Guide to Solidity ERC20 Tokens](https://www.alchemy.com/overviews/erc20-solidity) + + +## Other fungible token standards + +- [ERC-223](/developers/docs/standards/tokens/erc-223) +- [ERC-777](/developers/docs/standards/tokens/erc-777) +- [ERC-4626 - Tokenized vaults](/developers/docs/standards/tokens/erc-4626) + +--- + +## Developers > Docs > Standards > Tokens > Erc 223 + +## Introduction + +### What is ERC-223? + +ERC-223 is a standard for fungible tokens, similar to the ERC-20 standard. The key difference is that ERC-223 defines not only the token API but also the logic for transferring tokens from sender to recipient. It introduces a communication model that allows token transfers to be handled on the recipient's side. + +### Differences from ERC-20 + +ERC-223 addresses some limitations of ERC-20 and introduces a new method of interaction between the token contract and a contract that may receive the tokens. There are few things that are possible with ERC-223 but not with ERC-20: + +- Token transfer handling on the recipient's side: Recipients can detect that an ERC-223 token is being deposited. +- Rejection of improperly sent tokens: If a user sends ERC-223 tokens to a contract not supposed to receive tokens, the contract can reject the transaction, preventing token loss. +- Metadata in transfers: ERC-223 tokens can include metadata, allowing arbitrary information to be attached to token transactions. + +## Prerequisites + +- [Accounts](/developers/docs/accounts) +- [Smart Contracts](/developers/docs/smart-contracts/) +- [Token standards](/developers/docs/standards/tokens/) +- [ERC-20](/developers/docs/standards/tokens/erc-20/) + +## Body + +ERC-223 is a token standard that implements an API for tokens within smart contracts. It also declares an API for contracts that are supposed to receive ERC-223 tokens. Contracts that do not support the ERC-223 Receiver API cannot receive ERC-223 tokens, preventing user error. + +If a smart contract implements the following methods and events it can be called an ERC-223 compatible token contract. Once deployed, it +will be responsible to keep track of the created tokens on Ethereum. + +The contract is not obligated to have only these functions and a developer can add any other feature from different token standards to this contract. For example, `approve` and `transferFrom` functions are not part of ERC-223 standard but these functions could be implemented should it be necessary. + +From [EIP-223](https://eips.ethereum.org/EIPS/eip-223): + +### Methods + +ERC-223 token must implement the following methods: + +```solidity +function name() public view returns (string) +function symbol() public view returns (string) +function decimals() public view returns (uint8) +function totalSupply() public view returns (uint256) +function balanceOf(address _owner) public view returns (uint256 balance) +function transfer(address _to, uint256 _value) public returns (bool success) +function transfer(address _to, uint256 _value, bytes calldata _data) public returns (bool success) +``` + +A contract that is supposed to receive ERC-223 tokens must implement the following method: + +```solidity +function tokenReceived(address _from, uint _value, bytes calldata _data) +``` + +If ERC-223 tokens are sent to a contract that doesn't implement the `tokenReceived(..)` function then the transfer must fail and the tokens must not be moved from the sender's balance. + +### Events + +```solidity +event Transfer(address indexed _from, address indexed _to, uint256 _value, bytes calldata _data) +``` + +### Examples + +The API of ERC-223 token is similar to that of ERC-20, so from UI development point of view there is no difference. The only exception here is that ERC-223 tokens may not have `approve` + `transferFrom` functions as these are optional for this standard. + +#### Solidity examples + +The following example illustrates how a basic ERC-223 token contract operates: + +```solidity +pragma solidity ^0.8.19; +abstract contract IERC223Recipient +contract VeryBasicERC223Token + function symbol() public view returns (string memory) + function decimals() public view returns (uint8) + function totalSupply() public view returns (uint256) + function balanceOf(address _owner) public view returns (uint256) + function isContract(address account) internal view returns (bool) + return size > 0; + } + function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success) + emit Transfer(msg.sender, _to, _value, _data); + return true; + } + function transfer(address _to, uint _value) public returns (bool success) + emit Transfer(msg.sender, _to, _value, _empty); + return true; + } +} +``` + +Now we want another contract to accept deposits of `tokenA` assuming that tokenA is an ERC-223 token. The contract must accept only tokenA and reject any other tokens. When the contract receives tokenA it must emit a `Deposit()` event and increase the value of the internal `deposits` variable. + +Here is the code: + +```solidity +contract RecipientContract is IERC223Recipient +} +``` + +## Frequently asked questions + +### What will happen if we send some tokenB to the contract? + +The transaction will fail, and the transfer of tokens will not happen. The tokens will be returned to the sender's address. + +### How can we make a deposit to this contract? + +Call the `transfer(address,uint256)` or `transfer(address,uint256,bytes)` function of the ERC-223 token, specifying the address of the `RecipientContract`. + +### What will happen if we transfer an ERC-20 token to this contract? + +If an ERC-20 token is sent to the `RecipientContract`, the tokens will be transferred, but the transfer will not be recognized (no `Deposit()` event will be fired, and the deposits value will not change). Unwanted ERC-20 deposits cannot be filtered or prevented. + +### What if we want to execute some function after the token deposit is completed? + +There are multiple ways of doing so. In this example we will follow the method which makes ERC-223 transfers identical to ether transfers: + +```solidity +contract RecipientContract is IERC223Recipient + function foo() public + + function bar(uint256 _someNumber) public + +} +``` + +When the `RecipientContract` will receive a ERC-223 token the contract will execute a function encoded as `_data` parameter of the token transaction, identical to how ether transactions encode function calls as transaction `data`. Read [the data field](https://ethereum.org/en/developers/docs/transactions/#the-data-field) for more information. + +In the above example an ERC-223 token must be transferred to the address of the `RecipientContract` with the `transfer(address,uin256,bytes calldata _data)` function. If the data parameter will be `0xc2985578` (the signature of a `foo()` function) then the function foo() will be invoked after the token deposit is received and the event Foo() will be fired. + +Parameters can be encoded in the `data` of the token transfer as well, for example we can call the bar() function with 12345 value for `_someNumber`. In this case the `data` must be `0x0423a13200000000000000000000000000000000000000000000000000000000000004d2` where `0x0423a132` is the signature of the `bar(uint256)` function and `00000000000000000000000000000000000000000000000000000000000004d2` is 12345 as uint256. + +## Limitations + +While ERC-223 addresses several issues found in the ERC-20 standard, it is not without its own limitations: + +- Adoption and Compatibility: ERC-223 is not yet widely adopted, which may limit its compatibility with existing tools and platforms. +- Backward Compatibility: ERC-223 is not backward compatible with ERC-20, meaning that existing ERC-20 contracts and tools will not work with ERC-223 tokens without modifications. +- Gas Costs: The additional checks and functionalities in ERC-223 transfers may result in higher gas costs compared to ERC-20 transactions. + +## Further reading + +- [EIP-223: ERC-223 Token Standard](https://eips.ethereum.org/EIPS/eip-223) +- [Initial ERC-223 proposal](https://github.com/ethereum/eips/issues/223) + +--- + +## Developers > Docs > Standards > Tokens > Erc 4626 + +## Introduction + +ERC-4626 is a standard to optimize and unify the technical parameters of yield-bearing vaults. It provides a standard API for tokenized yield-bearing vaults that represent shares of a single underlying ERC-20 token. ERC-4626 also outlines an optional extension for tokenized vaults utilizing ERC-20, offering basic functionality for depositing, withdrawing tokens and reading balances. + +**The role of ERC-4626 in yield-bearing vaults** + +Lending markets, aggregators, and intrinsically interest-bearing tokens help users find the best yield on their crypto tokens by executing different strategies. These strategies are done with slight variation, which might be error-prone or waste development resources. + +ERC-4626 in yield-bearing vaults will lower the integration effort and unlock access to yield in various applications with little specialized effort from developers by creating more consistent and robust implementation patterns. + +The ERC-4626 token is described fully in [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626). + +**Asynchronous vault extension (ERC-7540)** + +ERC-4626 is optimized for atomic deposits and redemptions up to a limit. If the limit is reached, no new deposits or redemptions can be submitted. This limitation does not work well for any smart contract system with asynchronous actions or delays as a prerequisite for interfacing with the Vault (e.g. real-world asset protocols, undercollateralized lending protocols, cross-chain lending protocols, liquid staking tokens, or insurance safety modules). + +ERC-7540 expands the utility of ERC-4626 Vaults for asynchronous use cases. The existing Vault interface (`deposit`/`withdraw`/`mint`/`redeem`) is fully utilized to claim asynchronous Requests. + +The ERC-7540 extension is described fully in [ERC-7540](https://eips.ethereum.org/EIPS/eip-7540). + +**Multi-asset vault extension (ERC-7575)** + +One missing use case that is not supported by ERC-4626 is Vaults which have multiple assets or entry points such as liquidity provider (LP) Tokens. These are generally unwieldy or non-compliant due to the requirement of ERC-4626 to itself be an ERC-20. + +ERC-7575 adds support for Vaults with multiple assets by externalizing the ERC-20 token implementation from the ERC-4626 implementation. + +The ERC-7575 extension is described fully in [ERC-7575](https://eips.ethereum.org/EIPS/eip-7575). + +## Prerequisites + +To better understand this page, we recommend you first read about [token standards](/developers/docs/standards/tokens/) and [ERC-20](/developers/docs/standards/tokens/erc-20/). + +## ERC-4626 Functions and Features: + +### Methods + +#### asset + +```solidity +function asset() public view returns (address assetTokenAddress) +``` + +This function returns the address of the underlying token used for the vault for accounting, depositing, withdrawing. + +#### totalAssets + +```solidity +function totalAssets() public view returns (uint256) +``` + +This function returns the total amount of underlying assets held by the vault. + +#### convertToShares + +```solidity +function convertToShares(uint256 assets) public view returns (uint256 shares) +``` + +This function returns the amount of `shares` that would be exchanged by the vault for the amount of `assets` provided. + +#### convertToAssets + +```solidity +function convertToAssets(uint256 shares) public view returns (uint256 assets) +``` + +This function returns the amount of `assets` that would be exchanged by the vault for the amount of `shares` provided. + +#### maxDeposit + +```solidity +function maxDeposit(address receiver) public view returns (uint256 maxAssets) +``` + +This function returns the maximum amount of underlying assets that can be deposited in a single [`deposit`](#deposit) call, with the shares minted for the `receiver`. + +#### previewDeposit + +```solidity +function previewDeposit(uint256 assets) public view returns (uint256 shares) +``` + +This function allows users to simulate the effects of their deposit at the current block. + +#### deposit + +```solidity +function deposit(uint256 assets, address receiver) public returns (uint256 shares) +``` + +This function deposits `assets` of underlying tokens into the vault and grants ownership of `shares` to `receiver`. + +#### maxMint + +```solidity +function maxMint(address receiver) public view returns (uint256 maxShares) +``` + +This function returns the maximum amount of shares that can be minted in a single [`mint`](#mint) call, with the shares minted for the `receiver`. + +#### previewMint + +```solidity +function previewMint(uint256 shares) public view returns (uint256 assets) +``` + +This function allows users to simulate the effects of their mint at the current block. + +#### mint + +```solidity +function mint(uint256 shares, address receiver) public returns (uint256 assets) +``` + +This function mints exactly `shares` vault shares to `receiver` by depositing `assets` of underlying tokens. + +#### maxWithdraw + +```solidity +function maxWithdraw(address owner) public view returns (uint256 maxAssets) +``` + +This function returns the maximum amount of underlying assets that can be withdrawn from the `owner` balance with a single [`withdraw`](#withdraw) call. + +#### previewWithdraw + +```solidity +function previewWithdraw(uint256 assets) public view returns (uint256 shares) +``` + +This function allows users to simulate the effects of their withdrawal at the current block. + +#### withdraw + +```solidity +function withdraw(uint256 assets, address receiver, address owner) public returns (uint256 shares) +``` + +This function burns `shares` from `owner` and send exactly `assets` token from the vault to `receiver`. + +#### maxRedeem + +```solidity +function maxRedeem(address owner) public view returns (uint256 maxShares) +``` + +This function returns the maximum amount of shares that can be redeemed from the `owner` balance through a [`redeem`](#redeem) call. + +#### previewRedeem + +```solidity +function previewRedeem(uint256 shares) public view returns (uint256 assets) +``` + +This function allows users to simulate the effects of their redemption at the current block. + +#### redeem + +```solidity +function redeem(uint256 shares, address receiver, address owner) public returns (uint256 assets) +``` + +This function redeems a specific number of `shares` from `owner` and sends `assets` of underlying token from the vault to `receiver`. + +#### totalSupply + +```solidity +function totalSupply() public view returns (uint256) +``` + +Returns the total number of unredeemed vault shares in circulation. + +#### balanceOf + +```solidity +function balanceOf(address owner) public view returns (uint256) +``` + +Returns the total amount of vault shares the `owner` currently has. + +### Map of the interface + +![Map of the ERC-4626 interface](./map-of-erc-4626.png) + +### Events + +#### Deposit Event + +**MUST** be emitted when tokens are deposited into the vault via the [`mint`](#mint) and [`deposit`](#deposit) methods. + +```solidity +event Deposit( + address indexed sender, + address indexed owner, + uint256 assets, + uint256 shares +) +``` + +Where `sender` is the user who exchanged `assets` for `shares`, and transferred those `shares` to `owner`. + +#### Withdraw Event + +**MUST** be emitted when shares are withdrawn from the vault by a depositor in the [`redeem`](#redeem) or [`withdraw`](#withdraw) methods. + +```solidity +event Withdraw( + address indexed sender, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares +) +``` + +Where `sender` is the user who triggered the withdrawal and exchanged `shares`, owned by `owner`, for `assets`. `receiver` is the user who received the withdrawn `assets`. + +## Further reading + +- [EIP-4626: Tokenized vault Standard](https://eips.ethereum.org/EIPS/eip-4626) +- [ERC-4626: GitHub Repo](https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC4626.sol) + +--- + +## Developers > Docs > Standards > Tokens > Erc 721 + +## Introduction + +**What is a Non-Fungible Token?** + +A Non-Fungible Token (NFT) is used to identify something or someone in a unique way. This type of Token is perfect to +be used on platforms that offer collectible items, access keys, lottery tickets, numbered seats for concerts and +sports matches, etc. This special type of Token has amazing possibilities so it deserves a proper Standard, the ERC-721 +came to solve that! + +**What is ERC-721?** + +The ERC-721 introduces a standard for NFT, in other words, this type of Token is unique and can have different value +than another Token from the same Smart Contract, maybe due to its age, rarity or even something else like its visual. +Wait, visual? + +Yes! All NFTs have a `uint256` variable called `tokenId`, so for any ERC-721 Contract, the pair +`contract address, uint256 tokenId` must be globally unique. That said, a dapp can have a "converter" that +uses the `tokenId` as input and outputs an image of something cool, like zombies, weapons, skills or amazing kitties! + +## Prerequisites + +- [Accounts](/developers/docs/accounts/) +- [Smart Contracts](/developers/docs/smart-contracts/) +- [Token standards](/developers/docs/standards/tokens/) + +## Body + +The ERC-721 (Ethereum Request for Comments 721), proposed by William Entriken, Dieter Shirley, Jacob Evans, +Nastassia Sachs in January 2018, is a Non-Fungible Token Standard that implements an API for tokens within Smart Contracts. + +It provides functionalities like to transfer tokens from one account to another, to get the current token balance of an +account, to get the owner of a specific token and also the total supply of the token available on the network. +Besides these it also has some other functionalities like to approve that an amount of token from an account can be +moved by a third party account. + +If a Smart Contract implements the following methods and events it can be called an ERC-721 Non-Fungible Token Contract +and, once deployed, it will be responsible to keep track of the created tokens on Ethereum. + +From [EIP-721](https://eips.ethereum.org/EIPS/eip-721): + +### Methods + +```solidity + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; + function setApprovalForAll(address _operator, bool _approved) external; + function getApproved(uint256 _tokenId) external view returns (address); + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +``` + +### Events + +```solidity + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); +``` + +### Examples + +Let's see how a Standard is so important to make things simple for us to inspect any ERC-721 Token Contract on Ethereum. +We just need the Contract Application Binary Interface (ABI) to create an interface to any ERC-721 Token. As you can +see below we will use a simplified ABI, to make it a low friction example. + +#### Web3.py Example + +First, make sure you have installed [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python library: + +``` +pip install web3 +``` + +```python +from web3 import Web3 +from web3._utils.events import get_event_data + + +w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com")) + +ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties Contract + +acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties Sales Auction + +# This is a simplified Contract Application Binary Interface (ABI) of an ERC-721 NFT Contract. +# It will expose only the methods: balanceOf(address), name(), ownerOf(tokenId), symbol(), totalSupply() +simplified_abi = [ + ], + 'name': 'balanceOf', + 'outputs': [], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'name': 'ownerOf', + 'outputs': [], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'stateMutability': 'view', 'type': 'function', 'constant': True + }, +] + +ck_extra_abi = [ + ], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + }, + ], + 'name': 'isPregnant', + 'outputs': [], + 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True + } +] + +ck_contract = w3.eth.contract(address=w3.to_checksum_address(ck_token_addr), abi=simplified_abi+ck_extra_abi) +name = ck_contract.functions.name().call() +symbol = ck_contract.functions.symbol().call() +kitties_auctions = ck_contract.functions.balanceOf(acc_address).call() +print(f" [] NFTs in Auctions: ") + +pregnant_kitties = ck_contract.functions.pregnantKitties().call() +print(f" [] NFTs Pregnants: ") + +# Using the Transfer Event ABI to get info about transferred Kitties. +tx_event_abi = , + , + ], + 'name': 'Transfer', + 'type': 'event' +} + +# We need the event's signature to filter the logs +event_signature = w3.keccak(text="Transfer(address,address,uint256)").hex() + +logs = w3.eth.get_logs() + +# Notes: +# - Increase the number of blocks up from 120 if no Transfer event is returned. +# - If you didn't find any Transfer event you can also try to get a tokenId at: +# https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#events +# Click to expand the event's logs and copy its "tokenId" argument +recent_tx = [get_event_data(w3.codec, tx_event_abi, log)["args"] for log in logs] + +if recent_tx: + kitty_id = recent_tx[0]['tokenId'] # Paste the "tokenId" here from the link above + is_pregnant = ck_contract.functions.isPregnant(kitty_id).call() + print(f" [] NFTs is pregnant: ") +``` + +CryptoKitties Contract has some interesting Events other than the Standard ones. + +Let's check two of them, `Pregnant` and `Birth`. + +```python +# Using the Pregnant and Birth Events ABI to get info about new Kitties. +ck_extra_events_abi = [ + , + , + , + ], + 'name': 'Pregnant', + 'type': 'event' + }, + , + , + , + , + ], + 'name': 'Birth', + 'type': 'event' + }] + +# We need the event's signature to filter the logs +ck_event_signatures = [ + w3.keccak(text="Pregnant(address,uint256,uint256,uint256)").hex(), + w3.keccak(text="Birth(address,uint256,uint256,uint256,uint256)").hex(), +] + +# Here is a Pregnant Event: +# - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog +pregnant_logs = w3.eth.get_logs() + +recent_pregnants = [get_event_data(w3.codec, ck_extra_events_abi[0], log)["args"] for log in pregnant_logs] + +# Here is a Birth Event: +# - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a +birth_logs = w3.eth.get_logs() + +recent_births = [get_event_data(w3.codec, ck_extra_events_abi[1], log)["args"] for log in birth_logs] +``` + +## Popular NFTs + +- [Etherscan NFT Tracker](https://etherscan.io/tokens-nft) list the top NFT on Ethereum by transfers volume. +- [CryptoKitties](https://www.cryptokitties.co/) is a game centered around breedable, collectible, and oh-so-adorable + creatures we call CryptoKitties. +- [Sorare](https://sorare.com/) is a global fantasy football game where you can collect limited editions collectibles, + manage your teams and compete to earn prizes. +- [The Ethereum Name Service (ENS)](https://ens.domains/) offers a secure & decentralized way to address resources both + on and off the blockchain using simple, human-readable names. +- [POAP](https://poap.xyz) delivers free NFTs to people who attend events or complete specific actions. POAPs are free to create and distribute. +- [Unstoppable Domains](https://unstoppabledomains.com/) is a San Francisco-based company building domains on + blockchains. Blockchain domains replace cryptocurrency addresses with human-readable names and can be used to enable + censorship-resistant websites. +- [Gods Unchained Cards](https://godsunchained.com/) is a TCG on the Ethereum blockchain that uses NFT's to bring real ownership + to in-game assets. +- [Bored Ape Yacht Club](https://boredapeyachtclub.com) is a collection of 10,000 unique NFTs, which, as well as being a provably-rare piece of art, acts as a membership token to the club, providing member perks and benefits that increase over time as a result of community efforts. + +## Further reading + +- [EIP-721: ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) +- [OpenZeppelin - ERC-721 Docs](https://docs.openzeppelin.com/contracts/3.x/erc721) +- [OpenZeppelin - ERC-721 Implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) +- [Alchemy NFT API](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) + +--- + +## Developers > Docs > Standards > Tokens > Erc 777 + +## Warning + +**ERC-777 is difficult to implement properly, due to its [susceptibility to different forms of attack](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2620). It is recommended to use [ERC-20](/developers/docs/standards/tokens/erc-20/) instead.** This page remains as a historical archive. + +## Introduction? + +ERC-777 is a fungible token standard improving the existing [ERC-20](/developers/docs/standards/tokens/erc-20/) standard. + +## Prerequisites + +To better understand this page, we recommend you first read about [ERC-20](/developers/docs/standards/tokens/erc-20/). + +## What improvements does ERC-777 propose over ERC-20? + +The ERC-777 provides the following improvements over ERC-20. + +### Hooks + +Hooks are a function described in the code of a smart contract. Hooks get called when tokens are sent or received through the contract. This allows a smart contract to react to incoming or outgoing tokens. + +The hooks are registered and discovered using the [ERC-1820](https://eips.ethereum.org/EIPS/eip-1820) standard. + +#### Why are hooks great? + +1. Hooks allow sending tokens to a contract and notifying the contract in a single transaction, unlike [ERC-20](https://eips.ethereum.org/EIPS/eip-20), which requires a double call (`approve`/`transferFrom`) to achieve this. +2. Contracts that have not registered hooks are incompatible with ERC-777. The sending contract will abort the transaction when the receiving contract has not registered a hook. This prevents accidental transfers to non-ERC-777 smart contracts. +3. Hooks can reject transactions. + +### Decimals + +The standard also solves the confusion around `decimals` caused in ERC-20. This clarity improves the developer experience. + +### Backwards compatibility with ERC-20 + +ERC-777 contracts can be interacted with as if they were ERC-20 contracts. + +## Further Reading + +[EIP-777: Token Standard](https://eips.ethereum.org/EIPS/eip-777) + +--- + +## Developers > Docs > Standards > Tokens + +## Introduction + +Many Ethereum development standards focus on token interfaces. These standards help ensure smart contracts remain composable, so for instance when a new project issues a token, that it remains compatible with existing decentralized exchanges. + +## Prerequisites + +- [Ethereum development standards](/developers/docs/standards/) +- [Smart contracts](/developers/docs/smart-contracts/) + +## Token standards + +Here are some of the most popular token standards on Ethereum: + +- [ERC-20](/developers/docs/standards/tokens/erc-20/) - A standard interface for fungible (interchangeable) tokens, like voting tokens, staking tokens or virtual currencies. + +### NFT standards + +- [ERC-721](/developers/docs/standards/tokens/erc-721/) - A standard interface for non-fungible tokens, like a deed for artwork or a song. +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - ERC-1155 allows for more efficient trades and bundling of transactions – thus saving costs. This token standard allows for creating both utility tokens (such as $BNB or $BAT) and Non-Fungible Tokens like CryptoPunks. + +The full list of [ERC](https://eips.ethereum.org/erc) proposals. + +## Further reading + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related tutorials + +- [Token integration checklist](/developers/tutorials/token-integration-checklist/) _– A checklist of things to consider when interacting with tokens._ +- [Understand the ERC20 token smart contract](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _– An introduction to deploying your first smart contract on an Ethereum test network._ +- [Transfers and approval of ERC20 tokens from a Solidity smart contract](/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/) _– How to use a smart contract to interact with a token using the Solidity language._ +- [Implementing an ERC721 market [a how-to guide]](/developers/tutorials/how-to-implement-an-erc721-market/) _– How to put tokenized items for sale on a decentralized classifieds board._ + +--- + +## Developers > Docs > Storage + +Unlike a centralized server operated by a single company or organization, decentralized storage systems consist of a peer-to-peer network of user-operators who hold a portion of the overall data, creating a resilient file storage sharing system. These can be in a blockchain-based application or any peer-to-peer-based network. + +Ethereum itself can be used as a decentralized storage system, and it is when it comes to code storage in all the smart contracts. However, when it comes to large amounts of data, that isn't what Ethereum was designed for. The chain is steadily growing, but at the time of writing, the Ethereum chain is around 500GB - 1TB ([depending on the client](https://etherscan.io/chartsync/chaindefault)), and every node on the network needs to be able to store all of the data. If the chain were to expand to large amounts of data (say 5TBs) it wouldn't be feasible for all nodes to continue to run. Also, the cost of deploying this much data to Mainnet would be prohibitively expensive due to [gas](/developers/docs/gas) fees. + +Due to these constraints, we need a different chain or methodology to store large amounts of data in a decentralized way. + +When looking at decentralized storage (dStorage) options, there are a few things a user must keep in mind. + +- Persistence mechanism / incentive structure +- Data retention enforcement +- Decentrality +- Consensus + +## Persistence mechanism / incentive structure + +### Blockchain-based + +For a piece of data to persist forever, we need to use a persistence mechanism. For example, on Ethereum, the persistence mechanism is that the whole chain needs to be accounted for when running a node. New pieces of data get tacked onto the end of the chain, and it continues to grow - requiring every node to replicate all the embedded data. + +This is known as **blockchain-based** persistence. + +The issue with blockchain-based persistence is that the chain could get far too big to upkeep and store all the data feasibly (e.g. [many sources](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/) estimate the Internet to require over 40 Zetabytes of storage capacity). + +The blockchain must also have some type of incentive structure. For blockchain-based persistence, there is a payment made to the validator. When the data is added to the chain, the validators are paid to add the data on. + +Platforms with blockchain-based persistence: + +- Ethereum +- [Arweave](https://www.arweave.org/) + +### Contract-based + +**Contract-based** persistence has the intuition that data cannot be replicated by every node and stored forever, and instead must be upkept with contract agreements. These are agreements made with multiple nodes that have promised to hold a piece of data for a period of time. They must be refunded or renewed whenever they run out to keep the data persisted. + +In most cases, instead of storing all data onchain, the hash of where the data is located on a chain gets stored. This way, the entire chain doesn't need to scale to keep all of the data. + +Platforms with contract-based persistence: + +- [Filecoin](https://docs.filecoin.io/about-filecoin/what-is-filecoin/) +- [Skynet](https://sia.tech/) +- [Storj](https://storj.io/) +- [Züs](https://zus.network/) +- [Crust Network](https://crust.network) +- [Swarm](https://www.ethswarm.org/) +- [4EVERLAND](https://www.4everland.org/) + +### Additional considerations + +IPFS is a distributed system for storing and accessing files, websites, applications, and data. It doesn't have a built-in incentive scheme, but can instead be used with any of the contract-based incentive solutions above for longer-term persistence. Another way to persist data on IPFS is to work with a pinning service, which will "pin" your data for you. You can even run your own IPFS node and contribute to the network to persist your and/or other's data for free! + +- [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/) +- [Pinata](https://www.pinata.cloud/) _(IPFS pinning service)_ +- [web3.storage](https://web3.storage/) _(IPFS/Filecoin pinning service)_ +- [Infura](https://infura.io/product/ipfs) _(IPFS pinning service)_ +- [IPFS Scan](https://ipfs-scan.io) _(IPFS pinning explorer)_ +- [4EVERLAND](https://www.4everland.org/)_(IPFS pinning service)_ +- [Filebase](https://filebase.com) _(IPFS Pinning Service)_ +- [Spheron Network](https://spheron.network/) _(IPFS/Filecoin pinning service)_ + +SWARM is a decentralized data storage and distribution technology with a storage incentive system and a storage rent price oracle. + +## Data retention + +In order to retain data, systems must have some sort of mechanism to make sure data is retained. + +### Challenge mechanism + +One of the most popular ways to make sure data is retained, is to use some type of cryptographic challenge that is issued to the nodes to make sure they still have the data. A simple one is looking at Arweave's proof-of-access. They issue a challenge to the nodes to see if they have the data at both the most recent block and a random block in the past. If the node can't come up with the answer, they are penalized. + +Types of dStorage with a challenge mechanism: + +- Züs +- Skynet +- Arweave +- Filecoin +- Crust Network +- 4EVERLAND + +### Decentrality + +There aren't great tools to measure the level of decentralization of platforms, but in general, you'll want to use tools that don't have some form of KYC to provide evidence they are not centralized. + +Decentralized tools without KYC: + +- Skynet +- Arweave +- Filecoin +- IPFS +- Ethereum +- Crust Network +- 4EVERLAND + +### Consensus + +Most of these tools have their own version of a [consensus mechanism](/developers/docs/consensus-mechanisms/) but generally they are based on either [**proof-of-work (PoW)**](/developers/docs/consensus-mechanisms/pow/) or [**proof-of-stake (PoS)**](/developers/docs/consensus-mechanisms/pos/). + +Proof-of-work based: + +- Skynet +- Arweave + +Proof-of-stake based: + +- Ethereum +- Filecoin +- Züs +- Crust Network + +## Related tools + +**IPFS - _InterPlanetary File System is a decentralized storage and file referencing system for Ethereum._** + +- [Ipfs.io](https://ipfs.io/) +- [Documentation](https://docs.ipfs.io/) +- [GitHub](https://github.com/ipfs/ipfs) + +**Storj DCS - _Secure, private, and S3-compatible decentralized cloud object storage for developers._** + +- [Storj.io](https://storj.io/) +- [Documentation](https://docs.storj.io/) +- [GitHub](https://github.com/storj/storj) + +**Sia - _Harnesseses cryptography to create a trustless cloud storage marketplace, allowing buyers and sellers to transact directly._** + +- [Skynet.net](https://sia.tech/) +- [Documentation](https://docs.sia.tech/) +- [GitHub](https://github.com/SiaFoundation/) + +**Filecoin - _Filecoin was created from the same team behind IPFS. It is an incentive layer on top of the IPFS ideals._** + +- [Filecoin.io](https://filecoin.io/) +- [Documentation](https://docs.filecoin.io/) +- [GitHub](https://github.com/filecoin-project/) + +**Arweave - _Arweave is a dStorage platform for storing data._** + +- [Arweave.org](https://www.arweave.org/) +- [Documentation](https://docs.arweave.org/info/) +- [Arweave](https://github.com/ArweaveTeam/arweave/) + +**Züs - _Züs is a proof-of-stake dStorage platform with sharding and blobbers._** + +- [zus.network](https://zus.network/) +- [Documentation](https://0chaindocs.gitbook.io/zus-docs) +- [GitHub](https://github.com/0chain/) + +**Crust Network - _Crust is a dStorage platform on top of the IPFS._** + +- [Crust.network](https://crust.network) +- [Documentation](https://wiki.crust.network) +- [GitHub](https://github.com/crustio) + +**Swarm - _A distributed storage platform and content distribution service for the Ethereum web3 stack._** + +- [EthSwarm.org](https://www.ethswarm.org/) +- [Documentation](https://docs.ethswarm.org/docs/) +- [GitHub](https://github.com/ethersphere/) + +**OrbitDB - _A decentralized peer to peer database on top of IPFS._** + +- [OrbitDB.org](https://orbitdb.org/) +- [Documentation](https://github.com/orbitdb/field-manual/) +- [GitHub](https://github.com/orbitdb/orbit-db/) + +**Aleph.im - _Decentralized cloud project (database, file storage, computing and DID). A unique blend of offchain and onchain peer-to-peer technology. IPFS and multi-chain compatibility._** + +- [Aleph.im](https://aleph.im/) +- [Documentation](https://aleph.im/#/developers/) +- [GitHub](https://github.com/aleph-im/) + +**Ceramic - _User-controlled IPFS database storage for data-rich and engaging applications._** + +- [Ceramic.network](https://ceramic.network/) +- [Documentation](https://developers.ceramic.network/learn/welcome/) +- [GitHub](https://github.com/ceramicnetwork/js-ceramic/) + +**Filebase - _S3-compatible decentralized storage and geo-redundant IPFS pinning service. All files uploaded to IPFS through Filebase are automatically pinned to the Filebase infrastructure with 3x replication across the globe._** + +- [Filebase.com](https://filebase.com/) +- [Documentation](https://docs.filebase.com/) +- [GitHub](https://github.com/filebase) + +**4EVERLAND - _A Web 3.0 cloud computing platform that integrates storage, compute and networking core capabilities, is S3 compatible and provides synchronous data storage on decentralized storage networks such as IPFS and Arweave._** + +- [4everland.org](https://www.4everland.org/) +- [Documentation](https://docs.4everland.org/) +- [GitHub](https://github.com/4everland) + +**Kaleido - _A blockchain-as-a-service platform with click-button IPFS Nodes_** + +- [Kaleido](https://kaleido.io/) +- [Documentation](https://docs.kaleido.io/kaleido-services/ipfs/) +- [GitHub](https://github.com/kaleido-io) + +**Spheron Network - _Spheron is a platform-as-a-service (PaaS) designed for dApps looking to launch their applications on decentralized infra with best performance. It provides compute, decentralized storage, CDN & web hosting out of the box._** + +- [spheron.network](https://spheron.network/) +- [Documentation](https://docs.spheron.network/) +- [GitHub](https://github.com/spheronFdn) + +## Further reading + +- [What Is Decentralized Storage?](https://coinmarketcap.com/alexandria/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ +- [Busting Five Common Myths about Decentralized Storage](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Development frameworks](/developers/docs/frameworks/) + +--- + +## Developers > Docs > Transactions + +Transactions are cryptographically signed instructions from accounts. An account will initiate a transaction to update the state of the Ethereum network. The simplest transaction is transferring ETH from one account to another. + +## Prerequisites + +To help you better understand this page, we recommend you first read [Accounts](/developers/docs/accounts/) and our [introduction to Ethereum](/developers/docs/intro-to-ethereum/). + +## What's a transaction? + +An Ethereum transaction refers to an action initiated by an externally-owned account, in other words an account managed by a human, not a contract. For example, if Bob sends Alice 1 ETH, Bob's account must be debited and Alice's must be credited. This state-changing action takes place within a transaction. + +![Diagram showing a transaction cause state change](./tx.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +Transactions, which change the state of the EVM, need to be broadcast to the whole network. Any node can broadcast a request for a transaction to be executed on the EVM; after this happens, a validator will execute the transaction and propagate the resulting state change to the rest of the network. + +Transactions require a fee and must be included in a validated block. To make this overview simpler we'll cover gas fees and validation elsewhere. + +A submitted transaction includes the following information: + +- `from` – the address of the sender, that will be signing the transaction. This will be an externally-owned account as contract accounts cannot send transactions +- `to` – the receiving address (if an externally-owned account, the transaction will transfer value. If a contract account, the transaction will execute the contract code) +- `signature` – the identifier of the sender. This is generated when the sender's private key signs the transaction and confirms the sender has authorized this transaction +- `nonce` - a sequentially incrementing counter which indicates the transaction number from the account +- `value` – amount of ETH to transfer from sender to recipient (denominated in WEI, where 1ETH equals 1e+18wei) +- `input data` – optional field to include arbitrary data +- `gasLimit` – the maximum amount of gas units that can be consumed by the transaction. The [EVM](/developers/docs/evm/opcodes) specifies the units of gas required by each computational step +- `maxPriorityFeePerGas` - the maximum price of the consumed gas to be included as a tip to the validator +- `maxFeePerGas` - the maximum fee per unit of gas willing to be paid for the transaction (inclusive of `baseFeePerGas` and `maxPriorityFeePerGas`) + +Gas is a reference to the computation required to process the transaction by a validator. Users have to pay a fee for this computation. The `gasLimit`, and `maxPriorityFeePerGas` determine the maximum transaction fee paid to the validator. [More on Gas](/developers/docs/gas/). + +The transaction object will look a little like this: + +```js + +``` + +But a transaction object needs to be signed using the sender's private key. This proves that the transaction could only have come from the sender and was not sent fraudulently. + +An Ethereum client like Geth will handle this signing process. + +Example [JSON-RPC](/developers/docs/apis/json-rpc) call: + +```json + + ] +} +``` + +Example response: + +```json + + } +} +``` + +- the `raw` is the signed transaction in [Recursive Length Prefix (RLP)](/developers/docs/data-structures-and-encoding/rlp) encoded form +- the `tx` is the signed transaction in JSON form + +With the signature hash, the transaction can be cryptographically proven that it came from the sender and submitted to the network. + +### The data field + +The vast majority of transactions access a contract from an externally-owned account. +Most contracts are written in Solidity and interpret their data field in accordance with the [application binary interface (ABI)](/glossary/#abi). + +The first four bytes specify which function to call, using the hash of the function's name and arguments. +You can sometimes identify the function from the selector using [this database](https://www.4byte.directory/signatures/). + +The rest of the calldata is the arguments, [encoded as specified in the ABI specs](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). + +For example, lets look at [this transaction](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1). +Use **Click to see More** to see the calldata. + +The function selector is `0xa9059cbb`. There are several [known functions with this signature](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb). +In this case [the contract source code](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code) has been uploaded to Etherscan, so we know the function is `transfer(address,uint256)`. + +The rest of the data is: + +``` +0000000000000000000000004f6742badb049791cd9a37ea913f2bac38d01279 +000000000000000000000000000000000000000000000000000000003b0559f4 +``` + +According to the ABI specifications, integer values (such as addresses, which are 20-byte integers) appear in the ABI as 32-byte words, padded with zeros in the front. +So we know that the `to` address is [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279). +The `value` is 0x3b0559f4 = 990206452. + +## Types of transactions + +On Ethereum there are a few different types of transactions: + +- Regular transactions: a transaction from one account to another. +- Contract deployment transactions: a transaction without a 'to' address, where the data field is used for the contract code. +- Execution of a contract: a transaction that interacts with a deployed smart contract. In this case, 'to' address is the smart contract address. + +### On gas + +As mentioned, transactions cost [gas](/developers/docs/gas/) to execute. Simple transfer transactions require 21000 units of Gas. + +So for Bob to send Alice 1 ETH at a `baseFeePerGas` of 190 gwei and `maxPriorityFeePerGas` of 10 gwei, Bob will need to pay the following fee: + +``` +(190 + 10) * 21000 = 4,200,000 gwei +--or-- +0.0042 ETH +``` + +Bob's account will be debited **-1.0042 ETH** (1 ETH for Alice + 0.0042 ETH in gas fees) + +Alice's account will be credited **+1.0 ETH** + +The base fee will be burned **-0.00399 ETH** + +Validator keeps the tip **+0.000210 ETH** + + +![Diagram showing how unused gas is refunded](./gas-tx.png) +_Diagram adapted from [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ + +Any gas not used in a transaction is refunded to the user account. + +### Smart contract interactions + +Gas is required for any transaction that involves a smart contract. + +Smart contracts can also contain functions known as [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) or [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions) functions, which do not alter the state of the contract. As such, calling these functions from an EOA will not require any gas. The underlying RPC call for this scenario is [`eth_call`](/developers/docs/apis/json-rpc#eth_call). + +Unlike when accessed using `eth_call`, these `view` or `pure` functions are also commonly called internally (i.e. from the contract itself or from another contract) which does cost gas. + +## Transaction lifecycle + +Once the transaction has been submitted the following happens: + +1. A transaction hash is cryptographically generated: + `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` +2. The transaction is then broadcasted to the network and added to a transaction pool consisting of all other pending network transactions. +3. A validator must pick your transaction and include it in a block in order to verify the transaction and consider it "successful". +4. As time passes the block containing your transaction will be upgraded to "justified" then "finalized". These upgrades make it much + more certain that your transaction was successful and will never be altered. Once a block is "finalized" it could only ever be changed + by a network level attack that would cost many billions of dollars. + +## A visual demo + +Watch Austin walk you through transactions, gas, and mining. + + + +## Typed Transaction Envelope + +Ethereum originally had one format for transactions. Each transaction contained a nonce, gas price, gas limit, to address, value, data, v, r, and s. These fields are [RLP-encoded](/developers/docs/data-structures-and-encoding/rlp/), to look something like this: + +`RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` + +Ethereum has evolved to support multiple types of transactions to allow for new features such as access lists and [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) to be implemented without affecting legacy transaction formats. + +[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) is what allows for this behavior. Transactions are interpreted as: + +`TransactionType || TransactionPayload` + +Where the fields are defined as: + +- `TransactionType` - a number between 0 and 0x7f, for a total of 128 possible transaction types. +- `TransactionPayload` - an arbitrary byte array defined by the transaction type. + +Based on the `TransactionType` value, a transaction can be classified as: + +1. **Type 0 (Legacy) Transactions:** The original transaction format used since Ethereum's launch. They do not include features from [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) such as dynamic gas fee calculations or access lists for smart contracts. Legacy transactions lack a specific prefix indicating their type in their serialized form, starting with the byte `0xf8` when using [Recursive Length Prefix (RLP)](/developers/docs/data-structures-and-encoding/rlp) encoding. The TransactionType value for these transactions is `0x0`. + +2. **Type 1 Transactions:** Introduced in [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) as part of Ethereum's [Berlin Upgrade](/history/#berlin), these transactions include an `accessList` parameter. This list specifies addresses and storage keys the transaction expects to access, helping to potentially reduce [gas](/developers/docs/gas/) costs for complex transactions involving smart contracts. EIP-1559 fee market changes are not included in Type 1 transactions. Type 1 transactions also include a `yParity` parameter, which can either be `0x0` or `0x1`, indicating the parity of the y-value of the secp256k1 signature. They are identified by starting with the byte `0x01`, and their TransactionType value is `0x1`. + +3. **Type 2 Transactions**, commonly referred to as EIP-1559 transactions, are transactions introduced in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), in Ethereum's [London Upgrade](/history/#london). They have become the standard transaction type on the Ethereum network. These transactions introduce a new fee market mechanism that improves predictability by separating the transaction fee into a base fee and a priority fee. They start with the byte `0x02` and include fields such as `maxPriorityFeePerGas` and `maxFeePerGas`. Type 2 transactions are now the default due to their flexibility and efficiency, especially favored during periods of high network congestion for their ability to help users manage transaction fees more predictably. The TransactionType value for these transactions is `0x2`. + +4. **Type 3 (Blob) Transactions** were introduced in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) as part of Ethereum's [Dencun Upgrade](/history/#dencun). These transactions are designed to handle "blob" data (Binary Large Objects) more efficiently, particularly benefiting Layer 2 rollups by providing a way to post data to the Ethereum network at a lower cost. Blob transactions include additional fields such as `blobVersionedHashes`, `maxFeePerBlobGas`, and `blobGasPrice`. They start with the byte `0x03`, and their TransactionType value is `0x3`. Blob transactions represent a significant improvement in Ethereum's data availability and scaling capabilities. + +## Further reading + +- [EIP-2718: Typed Transaction Envelope](https://eips.ethereum.org/EIPS/eip-2718) + +_Know of a community resource that helped you? Edit this page and add it!_ + +## Related topics + +- [Accounts](/developers/docs/accounts/) +- [Ethereum virtual machine (EVM)](/developers/docs/evm/) +- [Gas](/developers/docs/gas/) + +--- + +## Developers > Docs > Web2 Vs Web3 + +Web2 refers to the version of the internet most of us know today. An internet dominated by companies that provide services in exchange for your personal data. Web3, in the context of Ethereum, refers to decentralized apps that run on the blockchain. These are apps that allow anyone to participate without monetising their personal data. + +Looking for a more beginner-friendly resource? See our [introduction to web3](/web3/). + +## Web3 benefits + +Many Web3 developers have chosen to build dapps because of Ethereum's inherent decentralization: + +- Anyone who is on the network has permission to use the service – or in other words, permission isn't required. +- No one can block you or deny you access to the service. +- Payments are built in via the native token, ether (ETH). +- Ethereum is turing-complete, meaning you can program pretty much anything. + +## Practical comparisons + +| Web2 | Web3 | +| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| Twitter can censor any account or tweet | Web3 tweets would be uncensorable because control is decentralized | +| Payment service may decide to not allow payments for certain types of work | Web3 payment apps require no personal data and can't prevent payments | +| Servers for gig-economy apps could go down and affect worker income | Web3 servers can't go down – they use Ethereum, a decentralized network of 1000s of computers as their backend | + +This doesn't mean that all services need to be turned into a dapp. These examples are illustrative of the main differences between web2 and web3 services. + +## Web3 limitations + +Web3 has some limitations right now: + +- Scalability – transactions are slower on web3 because they're decentralized. Changes to state, like a payment, need to be processed by a node and propagated throughout the network. +- UX – interacting with web3 applications can require extra steps, software, and education. This can be a hurdle to adoption. +- Accessibility – the lack of integration in modern web browsers makes web3 less accessible to most users. +- Cost – most successful dapps put very small portions of their code on the blockchain as it's expensive. + +## Centralization vs decentralization + +In the table below, we list some of the broad-strokes advantages and disadvantages of centralized and decentralized digital networks. + +| Centralized Systems | Decentralized Systems | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Low network diameter (all participants are connected to a central authority); information propagates quickly, as propagation is handled by a central authority with lots of computational resources. | The furthest participants on the network may potentially be many edges away from each other. Information broadcast from one side of the network may take a long time to reach the other side. | +| Usually higher performance (higher throughput, fewer total computational resources expended) and easier to implement. | Usually lower performance (lower throughput, more total computational resources expended) and more complex to implement. | +| In the event of conflicting data, resolution is clear and easy: the ultimate source of truth is the central authority. | A protocol (often complex) is needed for dispute resolution, if peers make conflicting claims about the state of data which participants are meant to be synchronized on. | +| Single point of failure: malicious actors may be able to take down the network by targeting the central authority. | No single point of failure: network can still function even if a large proportion of participants are attacked/taken out. | +| Coordination among network participants is much easier, and is handled by a central authority. Central authority can compel network participants to adopt upgrades, protocol updates, etc., with very little friction. | Coordination is often difficult, as no single agent has the final say in network-level decisions, protocol upgrades, etc. In the worst case, network is prone to fracturing when there are disagreements about protocol changes. | +| Central authority can censor data, potentially cutting off parts of the network from interacting with the rest of the network. | Censorship is much harder, as information has many ways to propagate across the network. | +| Participation in the network is controlled by the central authority. | Anyone can participate in the network; there are no “gatekeepers.” Ideally, the cost of participation is very low. | + +Note that these are general patterns that may not hold true in every network. Furthermore, in reality the degree to which a network is centralized/decentralized lies on a spectrum; no network is entirely centralized or entirely decentralized. + +## Further reading + +- [What is Web3?](/web3/) - _ethereum.org_ +- [The Architecture of a Web 3.0 application](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ +- [The Meaning of Decentralization](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _Feb 6, 2017 - Vitalik Buterin_ +- [Why Decentralization Matters](https://medium.com/s/story/why-decentralization-matters-5e3f79f7638e) _Feb 18, 2018 - Chris Dixon_ +- [What Is Web 3.0 & Why It Matters](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _Dec 31, 2019 - Max Mersch and Richard Muirhead_ +- [Why We Need Web 3.0](https://medium.com/@gavofyork/why-we-need-web-3-0-5da4f2bf95ab) _Sep 12, 2018 - Gavin Wood_ + +--- + +## Developers > Tutorials > A Developers Guide To Ethereum Part One + +So, you’ve heard about this Ethereum thing and are ready to venture down the rabbit hole? This post will quickly cover some blockchain basics, then get you interacting with a simulated Ethereum node – reading block data, checking account balances, and sending transactions. Along the way, we’ll highlight the differences between traditional ways of building apps and this new decentralized paradigm. + +## (Soft) prerequisites + +This post aspires to be accessible to a wide range of developers. [Python tools](/developers/docs/programming-languages/python/) will be involved, but they are just a vehicle for the ideas – no problem if you are not a Python developer. I will, however, be making just a few assumptions about what you already know, so we can quickly move on the Ethereum-specific bits. + +Assumptions: + +- You can get around in a terminal, +- You've written a few lines of Python code, +- Python version 3.6 or greater is installed on your machine (use of a [virtual environment](https://realpython.com/effective-python-environment/#virtual-environments) is strongly encouraged), and +- you’ve used `pip`, Python’s package installer. + Again, if any of these are untrue, or you don’t plan to reproduce the code in this article, you can likely still follow along just fine. + +## Blockchains, briefly + +There are many ways to describe Ethereum, but at its heart is a blockchain. Blockchains are made up of a series of blocks, so let’s start there. In the simplest terms, each block on the Ethereum blockchain is just some metadata and a list of transactions. In JSON format, that looks something like this: + +```json + +``` + +Each [block](/developers/docs/blocks/) has a reference to the block that came before it; the `parentHash` is simply the hash of the previous block. + +Note: Ethereum makes regular use of hash functions to produce fixed-size values (“hashes”). Hashes play an important role in Ethereum, but you can safely think of them as unique IDs for now. + +![A diagram depicting a blockchain including the data inside each block](./blockchain-diagram.png) + +_A blockchain is essentially a linked list; each block has a reference to the previous block._ + +This data structure is nothing novel, but the rules (i.e., peer-to-peer protocols) that govern the network are. There’s no central authority; the network of peers must collaborate to sustain the network, and compete to decide which transactions to include in the next block. So, when you want to send some money to a friend, you’ll need to broadcast that transaction to the network, then wait for it to be included in an upcoming block. + +The only way for the blockchain to verify that money was truly sent from one user to another is to use a currency native to (i.e., created and governed by) that blockchain. In Ethereum, this currency is called ether, and the Ethereum blockchain contains the only official record of account balances. + +## A new paradigm + +This new decentralized tech stack has spawned new developer tools. Such tools exist in many programming languages, but we’ll be looking through the Python lens. To reiterate: even if Python isn’t your language of choice, it shouldn’t be much trouble to follow along. + +Python developers that want to interact with Ethereum are likely to reach for [Web3.py](https://web3py.readthedocs.io/). Web3.py is a library that greatly simplifies the way you connect to an Ethereum node, then send and receive data from it. + +Note: “Ethereum node” and “Ethereum client” are used interchangeably. In either case, it refers to the software that a participant in the Ethereum network runs. This software can read block data, receive updates when new blocks are added to the chain, broadcast new transactions, and more. Technically, the client is the software, the node is the computer running the software. + +[Ethereum clients](/developers/docs/nodes-and-clients/) can be configured to be reachable by [IPC](https://wikipedia.org/wiki/Inter-process_communication), HTTP, or Websockets, so Web3.py will need to mirror this configuration. Web3.py refers to these connection options as **providers**. You’ll want to choose one of the three providers to link the Web3.py instance with your node. + +![A diagram showing how web3.py uses IPC to connect your application to an Ethereum node](./web3py-and-nodes.png) + +_Configure the Ethereum node and Web3.py to communicate via the same protocol, e.g., IPC in this diagram._ + +Once Web3.py is properly configured, you can begin to interact with the blockchain. Here’s a couple of Web3.py usage examples as a preview of what’s to come: + +```python +# read block data: +w3.eth.get_block('latest') + +# send a transaction: +w3.eth.send_transaction() +``` + +## Installation + +In this walkthrough, we’ll just be working within a Python interpreter. We won't be creating any directories, files, classes or functions. + +Note: In the examples below, commands that begin with `$` are intended to be run in the terminal. (Do not type the `$`, it just signifies the start of the line.) + +First, install [IPython](https://ipython.org/) for a user-friendly environment to explore in. IPython offers tab completion, among other features, making it much easier to see what’s possible within Web3.py. + +```bash +pip install ipython +``` + +Web3.py is published under the name `web3`. Install it like so: + +```bash +pip install web3 +``` + +One more thing – we're going to simulate a blockchain later, which requires a couple more dependencies. You can install those via: + +```bash +pip install 'web3[tester]' +``` + +You’re all set up to go! + +Note: The `web3[tester]` package works up to Python 3.10.xx + +## Spin up a sandbox + +Open up a new Python environment by running `ipython` in your terminal. This is comparable to running `python`, but comes with more bells and whistles. + +```bash +ipython +``` + +This will print out some information about the versions of Python and IPython you’re running, then you should see a prompt waiting for input: + +```python +In [1]: +``` + +You’re looking at an interactive Python shell now. Essentially, it's a sandbox to play in. If you’ve made it this far, it's time to import Web3.py: + +```python +In [1]: from web3 import Web3 +``` + +## Introducing the Web3 module + +Besides being a gateway to Ethereum, the [Web3](https://web3py.readthedocs.io/en/stable/overview.html#base-api) module offers a few convenience functions. Let’s explore a couple. + +In an Ethereum application, you will commonly need to convert currency denominations. The Web3 module provides a couple of helper methods just for this: [from_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.from_wei) and [to_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.to_wei). + + +Note: Computers are notoriously bad at handling decimal math. To get around this, developers often store dollar amounts in cents. For example, an item with a price of $5.99 may be stored in the database as 599. + +A similar pattern is used when handling transactions in ether. However, instead of two decimal points, ether has 18! The smallest denomination of ether is called wei, so that’s the value specified when sending transactions. + +1 ether = 1000000000000000000 wei + +1 wei = 0.000000000000000001 ether + + + +Try converting some values to and from wei. Note that [there are names for many of the denominations](https://web3py.readthedocs.io/en/stable/troubleshooting.html#how-do-i-convert-currency-denominations) in between ether and wei. One of the better known among them is **gwei**, as it’s often how transaction fees are represented. + +```python +In [2]: Web3.to_wei(1, 'ether') +Out[2]: 1000000000000000000 + +In [3]: Web3.from_wei(500000000, 'gwei') +Out[3]: Decimal('0.5') +``` + +Other utility methods on the Web3 module include data format converters (e.g., [`toHex`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toHex)), address helpers (e.g., [`isAddress`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.isAddress)), and hash functions (e.g., [`keccak`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.keccak)). Many of these will be covered later in the series. To view all the available methods and properties, utilize IPython’s auto-complete by typing `Web3`. and hitting the tab key twice after the period. + +## Talk to the chain + +The convenience methods are lovely, but let’s move on to the blockchain. The next step is to configure Web3.py to communicate with an Ethereum node. Here we have the option to use the IPC, HTTP, or Websocket providers. + +We won't be going down this path, but an example of a complete workflow using the HTTP Provider might look something like this: + +- Download an Ethereum node, e.g., [Geth](https://geth.ethereum.org/). +- Start Geth in one terminal window and wait for it to sync the network. The default HTTP port is `8545`, but is configurable. +- Tell Web3.py to connect to the node via HTTP, on `localhost:8545`. + `w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))` +- Use the `w3` instance to interact with the node. + +While this is one “real” way to do it, the syncing process takes hours and is unnecessary if you just want a development environment. Web3.py exposes a fourth provider for this purpose, the **EthereumTesterProvider**. This tester provider links to a simulated Ethereum node with relaxed permissions and fake currency to play with. + +![A diagram showing the EthereumTesterProvider linking your web3.py application to a simulated Ethereum node](./ethereumtesterprovider.png) + +_The EthereumTesterProvider connects to a simulated node and is handy for quick development environments._ + +That simulated node is called [eth-tester](https://github.com/ethereum/eth-tester) and we installed it as part of the `pip install web3[tester]` command. Configuring Web3.py to use this tester provider is as simple as: + +```python +In [4]: w3 = Web3(Web3.EthereumTesterProvider()) +``` + +Now you’re ready to surf the chain! That’s not a thing people say. I just made that up. Let’s take a quick tour. + +## The quick tour + +First things first, a sanity check: + +```python +In [5]: w3.is_connected() +Out[5]: True +``` + +Since we’re using the tester provider, this isn’t a very valuable test, but if it does fail, chances are you typed something in wrong when instantiating the `w3` variable. Double-check that you included the inner parentheses, i.e., `Web3.EthereumTesterProvider()`. + +## Tour stop #1: [accounts](/developers/docs/accounts/) + +As a convenience, the tester provider created some accounts and preloaded them with test ether. + +First, let’s see a list of those accounts: + +```python +In [6]: w3.eth.accounts +Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', + '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', + '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...] +``` + +If you run this command, you should see a list of ten strings that begin with `0x`. Each is a **public address** and is, in some ways, analogous to the account number on a checking account. You would provide this address to someone that wanted to send you ether. + +As mentioned, the tester provider has preloaded each of these accounts with some test ether. Let’s find out how much is in the first account: + +```python +In [7]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[7]: 1000000000000000000000000 +``` + +That’s a lot of zeros! Before you go laughing all the way to the fake bank, recall that lesson about currency denominations from earlier. Ether values are represented in the smallest denomination, wei. Convert that to ether: + +```python +In [8]: w3.from_wei(1000000000000000000000000, 'ether') +Out[8]: Decimal('1000000') +``` + +One million test ether — still not too shabby. + +## Tour stop #2: block data + +Let’s take a peek at the state of this simulated blockchain: + +```python +In [9]: w3.eth.get_block('latest') +Out[9]: AttributeDict() +``` + +A lot of information gets returned about a block, but just a couple things to point out here: + +- The block number is zero — no matter how long ago you configured the tester provider. Unlike the real Ethereum network, which adds a new block every 12 seconds, this simulation will wait until you give it some work to do. +- `transactions` is an empty list, for the same reason: we haven’t done anything yet. This first block is an **empty block**, just to kick off the chain. +- Notice that the `parentHash` is just a bunch of empty bytes. This signifies that it's the first block in the chain, also known as the **genesis block**. + +## Tour stop #3: [transactions](/developers/docs/transactions/) + +We’re stuck at block zero until there’s a pending transaction, so let’s give it one. Send a few test ether from one account to another: + +```python +In [10]: tx_hash = w3.eth.send_transaction() +``` + +This is typically the point where you’d wait for several seconds for your transaction to get included in a new block. The full process goes something like this: + +1. Submit a transaction and hold on to the transaction hash. Until the block containing the transaction is created and broadcast, the transaction is “pending.” + `tx_hash = w3.eth.send_transaction()` +2. Wait for the transaction to be included in a block: + `w3.eth.wait_for_transaction_receipt(tx_hash)` +3. Continue application logic. To view the successful transaction: + `w3.eth.get_transaction(tx_hash)` + +Our simulated environment will add the transaction in a new block instantly, so we can immediately view the transaction: + +```python +In [11]: w3.eth.get_transaction(tx_hash) +Out[11]: AttributeDict() +``` + +You’ll see some familiar details here: the `from`, `to`, and `value` fields should match the inputs of our `send_transaction` call. The other reassuring bit is that this transaction was included as the first transaction (`'transactionIndex': 0`) within block number 1. + +We can also easily verify the success of this transaction by checking the balances of the two accounts involved. Three ether should have moved from one to another. + +```python +In [12]: w3.eth.get_balance(w3.eth.accounts[0]) +Out[12]: 999996999979000000000000 + +In [13]: w3.eth.get_balance(w3.eth.accounts[1]) +Out[13]: 1000003000000000000000000 +``` + +The latter looks good! The balance went from 1,000,000 to 1,000,003 ether. But what happened to the first account? It appears to have lost slightly more than three ether. Alas, nothing in life is free, and using the Ethereum public network requires that you compensate your peers for their supporting role. A small transaction fee was deducted from the account that submitted the transaction - this fee is the amount of gas burned (21000 units of gas for an ETH transfer) multiplied by a base fee that varies according to network activity plus a tip that goes to the validator that includes the transaction in a block. + +More on [gas](/developers/docs/gas/#post-london) + +Note: On the public network, transaction fees are variable based on network demand and how quickly you'd like a transaction to be processed. If you're interested in a breakdown of how fees are calculated, see my earlier post on how transactions are included in a block. + +## And breathe + +We’ve been at this for a while, so this seems as good a place as any to take a break. The rabbit hole continues on, and we’ll continue exploring in part two of this series. Some concepts to come: connecting to a real node, smart contracts, and tokens. Have follow-up questions? Let me know! Your feedback will influence where we go from here. Requests welcome via [Twitter](https://twitter.com/wolovim). + +--- + +## Developers > Tutorials > All You Can Cache + +When using rollups the cost of a byte in the transaction is a lot more expensive than the cost of a storage slot. Therefore, it makes sense to cache as much information as possible onchain. + +In this article you learn how to create and use a caching contract in such a way that any parameter value that is likely to be used multiple times will be cached and available for use (after the first time) with a much smaller number of bytes, and how to write offchain code that uses this cache. + +If you want to skip the article and just see the source code, [it is here](https://github.com/qbzzt/20220915-all-you-can-cache). The development stack is [Foundry](https://book.getfoundry.sh/getting-started/installation). + +## Overall design + +For the sake of simplicity we'll assume all transaction parameters are `uint256`, 32 bytes long. When we receive a transaction, we'll parse each parameter like this: + +1. If the first byte is `0xFF`, take the next 32 bytes as a parameter value and write it to the cache. + +2. If the first byte is `0xFE`, take the next 32 bytes as a parameter value but do _not_ write it to the cache. + +3. For any other value, take the top four bits as the number of additional bytes, and the bottom four bits as the most significant bits of the cache key. Here are some examples: + + | Bytes in calldata | Cache key | + | :---------------- | --------: | + | 0x0F | 0x0F | + | 0x10,0x10 | 0x10 | + | 0x12,0xAC | 0x02AC | + | 0x2D,0xEA, 0xD6 | 0x0DEAD6 | + +## Cache manipulation + +The cache is implemented in [`Cache.sol`](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol). Let's go over it line by line. + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + + +contract Cache // cacheWrite +``` + +Return the new length of `key2val`, which is the cell where the new value is stored. + +```solidity + function _calldataVal(uint startByte, uint length) + private pure returns (uint) +``` + +This function reads a value from the calldata of arbitrary length (up to 32 bytes, the word size). + +```solidity + // _calldataVal + + + // Read a single parameter from the calldata, starting at _fromByte + function _readParam(uint _fromByte) internal + returns (uint _nextByte, uint _parameterValue) + + + // If we got here it means that we need to read from the cache + + // Number of extra bytes to read + uint8 _extraBytes = _firstByte / 16; +``` + +Take the lower [nibble](https://en.wikipedia.org/wiki/Nibble) and combine it with the other bytes to read the value from the cache. + +```solidity + uint _key = (uint256(_firstByte & 0x0F) ` type into a byte array which can be any length. Despite the name, it works fine when provided with just one argument. + +```solidity + // Two byte value, encoded as 0x1vvv + if (_key 3, we can express it in two bytes. We first convert `_key`, which is a 256 bit value, to a 16 bit value and use logical or to add the number of extra bytes to the first byte. Then we just it into a `bytes2` value, which can be converted to `bytes`. + +```solidity + // There is probably a clever way to do the following lines as a loop, + // but it's a view function so I'm optimizing for programmer time and + // simplicity. + + if (_key 15. But `cacheWrite` limits the keys so we can't even get up to 14\*25616 (which would have a first byte of 0xFE, so it would look like `DONT_CACHE`). But it doesn't cost us much to add a test in case a future programmer introduces a bug. + +```solidity + } // encodeVal + +} // Cache +``` + +### Testing the cache + +One of the advantages of Foundry is that [it lets you write tests in Solidity](https://book.getfoundry.sh/forge/tests), which makes it easier to write unit tests. The tests for the `Cache` class are [here](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/Cache.t.sol). Because the testing code is repetitive, as tests tend to be, this article only explains the interesting parts. + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; + + +// Need to run `forge test -vv` for the console. +import "forge-std/console.sol"; +``` + +This is just boilerplate that is necessary to use the test package and `console.log`. + +```solidity +import "src/Cache.sol"; +``` + +We need to know the contract we are testing. + +```solidity +contract CacheTest is Test +``` + +The `setUp` function is called before each test. In this case we just create a new cache, so that our tests won't affect each other. + +```solidity + function testCaching() public +``` + +Yul does not support data structures beyond `uint256`, so when you refer to a more sophisticated data structure, such as the memory buffer `_bytes`, you get the address of that structure. Solidity stores `bytes memory` values as a 32 byte word that contains the length, followed by the actual bytes, so to get byte number `_start` we need to calculate `_bytes+32+_start`. + +```solidity + + return tempUint; + } // toUint256 + + // Function signature for fourParams(), courtesy of + // https://www.4byte.directory/signatures/?bytes4_signature=0x3edc1e6d + bytes4 constant FOUR_PARAMS = 0x3edc1e6d; + + // Just some constant values to see we're getting the correct values back + uint256 constant VAL_A = 0xDEAD60A7; + uint256 constant VAL_B = 0xBEEF; + uint256 constant VAL_C = 0x600D; + uint256 constant VAL_D = 0x600D60A7; +``` + +Some constants we need for testing. + +```solidity + function testReadParam() public // testReadParam +``` + +The tests after the call are identical to those after the first call. + +```solidity + function testEncodeVal() public // testEncodeVal +``` + +The only additional test in `testEncodeVal()` is to verify that the length of `_callInput` is correct. For the first call it is 4+33\*4. For the second, where every value is already in the cache, it is 4+1\*4. + +```solidity + // Test encodeVal when the key is more than a single byte + // Maximum three bytes because filling the cache to four bytes takes + // too long. + function testEncodeValBig() public +One thing you don't get with Solidity tests is JavaScript code you can cut and paste into your own application. To write that code I deployed WORM to [Optimism Goerli](https://community.optimism.io/docs/useful-tools/networks/#optimism-goerli), [Optimism's](https://www.optimism.io/) new testnet. It is at address [`0xd34335b1d818cee54e3323d3246bd31d94e6a78a`](https://goerli-optimism.etherscan.io/address/0xd34335b1d818cee54e3323d3246bd31d94e6a78a). + +[You can see JavaScript code for the client here](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/javascript/index.js). To use it: + +1. Clone the git repository: + + ```sh + git clone https://github.com/qbzzt/20220915-all-you-can-cache.git + ``` + +2. Install the necessary packages: + + ```sh + cd javascript + yarn + ``` + +3. Copy the configuration file: + + ```sh + cp .env.example .env + ``` + +4. Edit `.env` for your configuration: + + | Parameter | Value | + | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | MNEMONIC | The mnemonic for an account that has enough ETH to pay for a transaction. [You can get free ETH for the Optimism Goerli network here](https://optimismfaucet.xyz/). | + | OPTIMISM_GOERLI_URL | URL to Optimism Goerli. The public endpoint, `https://goerli.optimism.io`, is rate limited but sufficient to what we need here | + +5. Run `index.js`. + + ```sh + node index.js + ``` + + This sample application first writes an entry to WORM, displaying the calldata and a link to the transaction on Etherscan. Then it reads back that entry, and displays the key it uses and the values in the entry (value, block number, and author). + +Most of the client is normal Dapp JavaScript. So again we'll only go over the interesting parts. + +```javascript +. +. +. +const main = async () => + +The code in this article is a proof of concept, the purpose is to make the idea easy to understand. For a production-ready system you might want to implement some additional functionality: + +- Handle values that aren't `uint256`. For example, strings. +- Instead of a global cache, maybe have a mapping between users and caches. Different users use different values. +- Values used for addresses are distinct from those used for other purposes. It might make sense to have a separate cache just for addresses. +- Currently, the cache keys are on a "first come, smallest key" algorithm. The first sixteen values can be sent as a single byte. The next 4080 values can be sent as two bytes. The next approximately million values are three bytes, etc. A production system should keep usage counters on cache entries and reorganize them so that the sixteen _most common_ values are one byte, the next 4080 most common values two bytes, etc. + + However, that is a potentially dangerous operation. Imagine the following sequence of events: + + 1. Noam Naive calls `encodeVal` to encode the address to which he wants to send tokens. That address is one of the first used on the application, so the encoded value is 0x06. This is a `view` function, not a transaction, so it's between Noam and the node he uses, and nobody else knows about it + + 2. Owen Owner runs the cache reordering operation. Very few people actually use that address, so it is now encoded as 0x201122. A different value, 1018, is assigned 0x06. + + 3. Noam Naive sends his tokens to 0x06. They go to the address `0x0000000000000000000000000de0b6b3a7640000`, and since nobody knows the private key for that address, they are just stuck there. Noam is _not happy_. + + There are ways to solve this problem, and the related problem of transactions that are in the mempool during the cache reorder, but you must be aware of it. + +I demonstrated caching here with Optimism, because I'm an Optimism employee and this is the rollup I know best. But it should work with any rollup that charges a minimal cost for internal processing, so that in comparison writing the transaction data to L1 is the major expense. + +--- + +## Developers > Tutorials > Calling A Smart Contract From Javascript + +In this tutorial we’ll see how to call a [smart contract](/developers/docs/smart-contracts/) function from JavaScript. First is reading the state of a smart contract (e.g. the balance of an ERC20 holder), then we’ll modify the state of the blockchain by making a token transfer. You should already be familiar with [setting up a JS environment to interact with the blockchain](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/). + +For this example we’ll play with the DAI token, for testing purpose we’ll fork the blockchain using ganache-cli and unlock an address that already has a lot of DAI: + +```bash +ganache-cli -f https://mainnet.infura.io/v3/[YOUR INFURA KEY] -d -i 66 1 --unlock 0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81 +``` + +To interact with a smart contract we’ll need its address and ABI: + +```js +const ERC20TransferABI = [ + , + , + ], + name: "transfer", + outputs: [ + , + ], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + , + ], + name: "balanceOf", + outputs: [ + , + ], + payable: false, + stateMutability: "view", + type: "function", + }, +] + +const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f" +``` + +For this project we stripped the complete ERC20 ABI to just keep the `balanceOf` and `transfer` function but you can find [the full ERC20 ABI here](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/). + +We then need to instantiate our smart contract: + +```js +const web3 = new Web3("http://localhost:8545") + +const daiToken = new web3.eth.Contract(ERC20TransferABI, DAI_ADDRESS) +``` + +We’ll also set up two addresses: + +- the one who will receive the transfer and +- the one we already unlocked that will send it: + +```js +const senderAddress = "0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81" +const receiverAddress = "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" +``` + +In the next part we’ll call the `balanceOf` function to retrieve the current amount of tokens both addresses hold. + +## Call: Reading value from a smart contract + +The first example will call a “constant” method and execute its smart contract method in the EVM without sending any transaction. For this we’ll read the ERC20 balance of an address. [Read our article about ERC20 tokens](/developers/tutorials/understand-the-erc-20-token-smart-contract/). + +You can access an instantiated smart contract methods that you provided the ABI for as follows: `yourContract.methods.methodname`. By using the `call` function you’ll receive the result of executing the function. + +```js +daiToken.methods.balanceOf(senderAddress).call(function (err, res) + console.log("The balance is: ", res) +}) +``` + +Remember that DAI ERC20 has 18 decimals which means you need to remove 18 zeros to get the correct amount. uint256 are returned as strings as JavaScript does not handle big numeric values. If you’re not sure [how to deal with big numbers in JS check our tutorial about bignumber.js](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/). + +## Send: Sending a transaction to a smart contract function + +For the second example we’ll call the transfer function of the DAI smart contract to send 10 DAI to our second address. The transfer function accepts two parameters: the recipient address and the amount of token to transfers: + +```js +daiToken.methods + .transfer(receiverAddress, "100000000000000000000") + .send(, function (err, res) + console.log("Hash of the transaction: " + res) + }) +``` + +The call function returns the hash of the transaction that will be mined into the blockchain. On Ethereum, transaction hashes are predictable - that’s how we can get the hash of the transaction before it is executed ([learn how hashes are calculated here](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction)). + +As the function only submits the transaction to the blockchain, we can’t see the result until we know when it is mined and included in the blockchain. In the next tutorial we’ll learn [how to wait for a transaction to be executed on the blockchain by knowing its hash](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/). + +--- + +## Developers > Tutorials > Creating A Wagmi Ui For Your Contract + +You found a feature we need in the Ethereum ecosystem. You wrote the smart contracts to implement it, and maybe even some related code that runs offchain. This is great! Unfortunately, without a user interface you aren't going to have any users, and the last time you wrote a web site people used dial-up modems and JavaScript was new. + +This article is for you. I assume you know programming, and maybe a bit of JavaScript and HTML, but that your user interface skills are rusty and out of date. Together we will go over a simple modern application so you'll see how it's done these days. + +## Why is this important + +In theory, you could just have people use [Etherscan](https://holesky.etherscan.io/address/0x432d810484add7454ddb3b5311f0ac2e95cecea8#writeContract) or [Blockscout](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=write_contract) to interact with your contracts. That will be great for the experienced Ethereans. But we are trying to serve [another billion people](https://blog.ethereum.org/2021/05/07/ethereum-for-the-next-billion). This won't happen without a great user experience, and a friendly user interface is a big part of that. + +## Greeter application + +There is a lot of theory behind for a modern UI works, and [a lot of good sites](https://react.dev/learn/thinking-in-react) [that explain it](https://wagmi.sh/core/getting-started). Instead of repeating the fine work done by those sites, I'm going to assume you prefer to learn by doing and start with an application you can play with. You still need the theory to get things done, and we'll get to it - we'll just go source file by source file, and discuss things as we get to them. + +### Installation + +1. If necessary, add [the Holesky blockchain](https://chainlist.org/?search=holesky&testnets=true) to your wallet and [get test ETH](https://www.holeskyfaucet.io/). + +1. Clone the github repository. + + ```sh + git clone https://github.com/qbzzt/20230801-modern-ui.git + ``` + +1. Install the necessary packages. + + ```sh + cd 20230801-modern-ui + pnpm install + ``` + +1. Start the application. + + ```sh + pnpm dev + ``` + +1. Browse to the URL shown by the application. In most cases, that is [http://localhost:5173/](http://localhost:5173/). + +1. You can see the contract source code, a slightly modified version of Hardhat's Greeter, [on a blockchain explorer](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contract). + +### File walk through + +#### `index.html` + +This file is standard HTML boilerplate except for this line, which imports the script file. + +```html + +``` + +#### `src/main.tsx` + +The file extension tells us that this file is a [React component](https://www.w3schools.com/react/react_components.asp) written in [TypeScript](https://www.typescriptlang.org/), an extension of JavaScript that supports [type checking](https://en.wikipedia.org/wiki/Type_system#Type_checking). TypeScript is compiled into JavaScript, so we can use it for client-side execution. + +```tsx +import '@rainbow-me/rainbowkit/styles.css' +``` + +Import the library code we need. + +```tsx +``` + +Import the React component that implements the application (see below). + +```tsx +ReactDOM.createRoot(document.getElementById('root')!).render( +``` + +Create the root React component. The parameter to `render` is [JSX](https://www.w3schools.com/react/react_jsx.asp), an extension language that uses both HTML and JavaScript/TypeScript. The exclamation point here tells the TypeScript component: "you don't know that `document.getElementById('root')` will be a valid parameter to `ReactDOM.createRoot`, but don't worry - I'm the developer and I'm telling you there will be". + +```tsx + +``` + +The application is going inside [a `React.StrictMode` component](https://react.dev/reference/react/StrictMode). This component tells the React library to insert additional debugging checks, which is useful during development. + +```tsx + +``` + +The application is also inside [a `WagmiConfig` component](https://wagmi.sh/react/WagmiConfig). [The wagmi (we are going to make it) library](https://wagmi.sh/) connects the React UI definitions with [the viem library](https://viem.sh/) for writing an Ethereum decentralized application. + +```tsx + +``` + +And finally, [a `RainbowKitProvider` component](https://www.rainbowkit.com/). This component handles logging on and the communication between the wallet and the application. + +```tsx + +``` + +Now we can have the component for the application, which actually implements the UI. The `/>` at the end of the component tells React that this component doesn't have any definitions inside it, as per the XML standard. + +```tsx + + + , +) +``` + +Of course, we have to close off the other components. + +#### `src/App.tsx` + +```tsx + +export function App() = useAccount() +``` + +Here we use [`useAccount`](https://wagmi.sh/react/hooks/useAccount) to check if we are connected to a blockchain through a wallet or not. + +By convention, in React functions called `use...` are [hooks](https://www.w3schools.com/react/react_hooks.asp) that return some kind of data. When you use such hooks, not only does your component get the data, but when that data changes the component is re-rendered with the updated information. + +```tsx + return ( + <> +``` + +The JSX of a React component _has_ to return one component. When we have multiple components and we don't have anything that wraps up "naturally" we use an empty component (`<> ... `) to make them into a single component. + +```tsx + Greeter + +``` + +We get [the `ConnectButton` component](https://www.rainbowkit.com/docs/connect-button) from RainbowKit. When we are not connected, it gives us a `Connect Wallet` button that opens a modal that explains wallets and lets you choose which one you use. When we are connected, it displays the blockchain we use, our account address, and our ETH balance. We can use these displays to switch network or to disconnect. + +```tsx + `). + +The syntax `a && b` is short for [`a ? b : a`](https://www.w3schools.com/react/react_es6_ternary.asp). That is, if `a` is true it evaluates to `b` and otherwise it evaluates to `a` (which can be `false`, `0`, etc). This is an easy way to tell React that a component should only be displayed if a certain condition is fulfilled. + +In this case, we only want to show the user `Greeter` if the user is connected to a blockchain. + +```tsx + + )} + + ) +} +``` + +#### `src/components/Greeter.tsx` + +This file contains most of the UI functionality. It includes definitions that would normally be in multiple files, but as this is a tutorial the program is optimized for being easy to understand the first time, rather than performance or ease of maintenance. + +```tsx +import from 'wagmi' +``` + +We use these library functions. Again, they are explained below where they are used. + +```tsx +``` + +[The `abitype` library](https://abitype.dev/) provides us with TypeScript definitions for various Ethereum data types, such as [`AddressType`](https://abitype.dev/config#addresstype). + +```tsx +let greeterABI = [ + . + . + . +] as const // greeterABI +``` + +The ABI for the `Greeter` contract. +If you are developing the contracts and UI at the same time you'd normally put them in the same repository and use the ABI generated by the Solidity compiler as a file in your application. However, this is not necessary here because the contract is already developed and not going to change. + +```tsx +type AddressPerBlockchainType = +``` + +TypeScript is strongly typed. We use this definition to specify the address in which the `Greeter` contract is deployed on different chains. The key is a number (the chainId), and the value is an `AddressType` (an address). + +```tsx +const contractAddrs: AddressPerBlockchainType = +``` + +The address of the contract on the two supported networks: [Holesky](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contact_code) and [Sepolia](https://eth-sepolia.blockscout.com/address/0x7143d5c190F048C8d19fe325b748b081903E3BF0?tab=contact_code). + +Note: There is actually a third definition, for Redstone Holesky, it will be explained below. + +```tsx +type ShowObjectAttrsType = +``` + +This type is used as a parameter to the `ShowObject` component (explained later). It includes the name of the object and its value, which are displayed for debugging purposes. + +```tsx +type ShowGreetingAttrsType = +``` + +At any moment in time we may either know what the greeting is (because we read it from the blockchain) or not know (because we haven't received it yet). So it is useful to have a type that can be either a string or nothing. + +##### `Greeter` component + +```tsx +const Greeter = () => = useNetwork() +``` + +Information about the chain we are using, courtesy of [wagmi](https://wagmi.sh/react/hooks/useNetwork). +Because this is a hook (`use...`), every time this information changes the component gets redrawn. + +```tsx + const greeterAddr = chain && contractAddrs[chain.id] +``` + +The address of the Greeter contract, which varies by chain (and which is `undefined` if we don't have chain information or we are on a chain without that contract). + +```tsx + const readResults = useReadContract() +``` + +[The `useReadContract` hook](https://wagmi.sh/react/api/hooks/useReadContract) reads information from a contract. You can see exactly what information it returns expand `readResults` in the UI. In this case we want it to keep looking so we'll be informed when the greeting changes. + +**Note:** We could listen to [`setGreeting` events](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=logs) to know when the greeting changes and update that way. However, while it may be more efficient, it will not apply in all cases. When the user switches to a different chain the greeting also changes, but that change is not accompanied by an event. We could have one part of the code listening for events and another to identify chain changes, but that would be more complicated than just setting [the `watch` parameter](https://wagmi.sh/react/api/hooks/useReadContract#watch-optional). + +```tsx + const [ newGreeting, setNewGreeting ] = useState("") +``` + +React's [`useState` hook](https://www.w3schools.com/react/react_usestate.asp) lets us specify a state variable, whose value persists from one rendering of the component to another. The initial value is the parameter, in this case the empty string. + +The `useState` hook returns a list with two values: + +1. The current value of the state variable. +2. A function to modify the state variable when needed. As this is a hook, every time it is called the component is rendered again. + +In this case, we are using a state variable for the new greeting the user wants to set. + +```tsx + const greetingChange : ChangeEventHandler = (evt) => + setNewGreeting(evt.target.value) +``` + +This is the event handler for when the new greeting input field changes. The type, [`ChangeEventHandler`](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events/), specifies that this is handler for a value change of an HTML input element. The `` part is used because this is a [generic type](https://www.w3schools.com/typescript/typescript_basic_generics.php). + +```tsx + const preparedTx = usePrepareContractWrite() + const workingTx = useContractWrite(preparedTx.config) +``` + +This is the process to submit a blockchain transaction from the client perspective: + +1. Send the transaction to a node in the blockchain using [`eth_estimateGas`](https://docs.alchemy.com/reference/eth-estimategas). +2. Wait for a response from the node. +3. When the response is received, ask the user to sign the transaction through the wallet. This step _has_ to happen after the node response is received because the user is shown the gas cost of the transaction before signing it. +4. Wait for the user for approve. +5. Send the transaction again, this time using [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction). + +Step 2 is likely to take a perceptible amount of time, during which users would wonder if their command was really received by the user interface and why they aren't being asked to sign the transaction already. That makes for bad user experience (UX). + +The solution is to use [prepare hooks](https://wagmi.sh/react/prepare-hooks). Every time that a parameter changes, immediately send the node the `eth_estimateGas` request. Then, when the user actually wants to send the transaction (in this case by pressing **Update greeting**), the gas cost is known and the user can see the wallet page immediately. + +```tsx + return ( +``` + +Now we can finally create the actual HTML to return. + +```tsx + <> + Greeter + + +``` + +Create a `ShowGreeting` component (explained below), but only if the greeting was read successfully from the blockchain. + +```tsx + +``` + +This is the input text field where the user can set a new greeting. Every time the user presses a key, we call `greetingChange` which calls `setNewGreeting`. As `setNewGreeting` comes from the `useState` hook, it causes the `Greeter` component to be rendered again. This means that: + +- We need to specify `value` to keep the value of the new greeting, because otherwise it would turn back into the default, the empty string. +- `usePrepareContractWrite` is called every time `newGreeting` changes, which means it is always going to have the latest `newGreeting` in the prepared transaction. + +```tsx + + Update greeting + +``` + +If there is no `workingTx.write` then we are still waiting for information necessary for sending the greeting update, so the button is disabled. If there is a `workingTx.write` value then that is the function to call to send the transaction. + +```tsx + + + + + + ) +} +``` + +Finally, to help you see what we're doing, show the three objects we use: + +- `readResults` +- `preparedTx` +- `workingTx` + +##### `ShowGreeting` component + +This component shows + +```tsx +const ShowGreeting = (attrs : ShowGreetingAttrsType) => +} +``` + +##### `ShowObject` component + +For information purposes, we use the `ShowObject` component to show the important objects (`readResults` for reading the greeting and `preparedTx` and `workingTx` for transactions we create). + +```tsx +const ShowObject = (attrs: ShowObjectAttrsType ) => + + +``` + +Most of the fields are displayed using [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp). + +```tsx + + ` is interpreted as JavaScript. Then, the code inside the `(` regular brackets `)`, is interpreted again as JSX. + +```tsx + () + )} +``` + +React requires tags in the [DOM Tree](https://www.w3schools.com/js/js_htmldom.asp) to have distinct identifiers. This means that children of the same tag (in this case, [the unordered list](https://www.w3schools.com/tags/tag_ul.asp)), need different `key` attributes. + +```tsx + + + } + + +} +``` + +End the various HTML tags. + +##### The final `export` + +```tsx +export +``` + +The `Greeter` component is the one we need to export for the application. + +#### `src/wagmi.ts` + +Finally, various definitions related to WAGMI are in `src/wagmi.ts`. I am not going to explain everything here, because most of it is boilerplate you are unlikely to need to change. + +The code here isn't exactly the same as [on github](https://github.com/qbzzt/20230801-modern-ui/blob/main/src/wagmi.ts) because later in the article we add another chain ([Redstone Holesky](https://redstone.xyz/docs/network-info)). + +```ts +``` + +Import the blockchains the application supports. You can see the list of supported chains [in the viem github](https://github.com/wagmi-dev/viem/tree/main/src/chains/definitions). + +```ts + +const walletConnectProjectId = 'c96e690bb92b6311e8e9b2a6a22df575' +``` + +To be able to use [WalletConnect](https://walletconnect.com/) you need a project ID for your application. You can get it [on cloud.walletconnect.com](https://cloud.walletconnect.com/sign-in). + +```ts +const = configureChains( + [ holesky, sepolia ], + [ + publicProvider(), + ], +) + +const = getDefaultWallets() + +export const config = createConfig() + +export +``` + +### Adding another blockchain + +These days there are a lot of [L2 scaling solution](https://ethereum.org/en/layer-2/), and you might want to support some that viem does not support yet. To do it, you modify `src/wagmi.ts`. These instructions explain how to add [Redstone Holesky](https://redstone.xyz/docs/network-info). + +1. Import the `defineChain` type from viem. + + ```ts + ``` + +1. Add the network definition. + + ```ts + const redstoneHolesky = defineChain(, + rpcUrls: , + public: , + }, + blockExplorers: , + }, + }) + ``` + +1. Add the new chain to the `configureChains` call. + + ```ts + const = configureChains( + [ holesky, sepolia, redstoneHolesky ], + [ publicProvider(), ], + ) + ``` + +1. Ensure that the application knows the address for your contracts on the new network. In this case, we modify `src/components/Greeter.tsx`: + + ```ts + const contractAddrs : AddressPerBlockchainType = + ``` + +## Conclusion + +Of course, you don't really care about providing a user interface for `Greeter`. You want to create a user interface for your own contracts. To create your own application, run these steps: + +1. Specify to create a wagmi application. + + ```sh copy + pnpm create wagmi + ``` + +1. Name the application. + +1. Select **React** framework. + +1. Select the **Vite** variant. + +1. You can [add Rainbow kit](https://www.rainbowkit.com/docs/installation#manual-setup). + +Now go and make your contracts usable for the wide world. + +--- + +## Developers > Tutorials > Deploying Your First Smart Contract + +I guess you are as excited as us to [deploy](/developers/docs/smart-contracts/deploying/) and interact with your first [smart contract](/developers/docs/smart-contracts/) on the Ethereum blockchain. + +Don’t worry, as it’s our first smart contract, we’ll deploy it on a [local test network](/developers/docs/networks/) so it does not cost anything for you to deploy and play as much as you’d like with it. + +## Writing our contract + +First step is to [visit Remix](https://remix.ethereum.org/) and create a new file. On the upper left part of the Remix interface add a new file and enter the file name you want. + +![Adding a new file in the Remix interface](./remix.png) + +In the new file, we’ll paste the following code. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity >=0.5.17; + +contract Counter + + // Not necessary getter to get the count value + function getCount() public view returns (uint256) + +} +``` + +If you’re used to programming you can easily guess what this program does. Here is an explainer line by line: + +- Line 4: We define a contract with the name `Counter`. +- Line 7: Our contract stores one unsigned integer named `count` starting at 0. +- Line 10: The first function will modify the state of the contract and `increment()` our variable `count`. +- Line 15: The second function is just a getter to be able to read the value of the `count` variable outside of the smart contract. Note that, as we defined our `count` variable as public this is not necessary but is shown as an example. + +This is all for our first simple smart contract. As you may know, it looks like a class from OOP (Object-Oriented Programming) languages like Java or C++. It’s now time to play with our contract. + +## Deploying our contract + +As we wrote our very first smart contract, we’ll now deploy it to the blockchain to be able to play with it. + +[Deploying the smart contract on the blockchain](/developers/docs/smart-contracts/deploying/) is actually just sending a transaction containing the code of the compiled smart contract without specifying any recipients. + +We’ll first [compile the contract](/developers/docs/smart-contracts/compiling/) by clicking on the compile icon on the left hand side: + +![The compile icon in the Remix toolbar](./remix-compile-button.png) + +Then click on the compile button: + +![The compile button in the Remix solidity compiler](./remix-compile.png) + +You can choose to select the “Auto compile” option so the contract will always be compiled when you save the content on the text editor. + +Then navigate to the "deploy and run transactions" screen: + +![The deploy icon in the Remix toolbar](./remix-deploy.png) + +Once you are on the "deploy and run transactions" screen, double check that your contract name appears and click on Deploy. As you can see on the top of the page, the current environment is “JavaScript VM” that means that we’ll deploy and interact with our smart contract on a local test blockchain to be able to test faster and without any fees. + +![The deploy button in the Remix solidity compiler](./remix-deploy-button.png) + +Once you've clicked the “Deploy” button, you’ll see your contract appear on the bottom. Click the arrow on the left to expand it so we’ll see the content of our contract. This is our variable `counter`, our `increment()` function and the getter `getCounter()`. + +If you click on the `count` or `getCount` button, it will actually retrieve the content of the contract’s `count` variable and display it. As we did not called the `increment` function yet, it should display 0. + +![The function button in the Remix solidity compiler](./remix-function-button.png) + +Let’s now call the `increment` function by clicking on the button. You’ll see logs of the transactions that are made appearing on the bottom of the window. You’ll see that the logs are different when you’re pressing the button to retrieve the data instead of the `increment` button. It’s because reading data on the blockchain does not need any transactions (writing) or fees. Because only modifying the state of the blockchain requires to make a transaction: + +![A log of transactions](./transaction-log.png) + +After pressing the increment button that will generate a transaction to call our `increment()` function if we click back on the count or getCount buttons we’ll read the newly updated state of our smart contract with the count variable being bigger than 0. + +![Newly updated state of the smart contract](./updated-state.png) + +In the next tutorial, we’ll cover [how you can add events to your smart contracts](/developers/tutorials/logging-events-smart-contracts/). Logging events is a convenient way to debug your smart contract and understand what is happening while calling a function. + +--- + +## Developers > Tutorials > Develop And Test Dapps With A Multi Client Local Eth Testnet + +## Introduction + +This guide walks you through the process of instantiating a configurable local Ethereum testnet, deploying a smart contract to it, and using the testnet to run tests against your dApp. This guide is designed for dApp developers who want to develop and test their dApps locally against different network configurations before deploying to a live testnet or the mainnet. + +In this guide, you will: + +- Instantiate a local Ethereum testnet with the [`eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) using [Kurtosis](https://www.kurtosis.com/), +- Connect your Hardhat dApp development environment to the local testnet to compile, deploy, and test a dApp, and +- Configure the local testnet, including parameters like number of nodes and specific EL/CL client pairings, to enable development and testing workflows against various network configurations. + +### What is Kurtosis? + +[Kurtosis](https://www.kurtosis.com/) is a composable build system designed for configuring multi-container test environments. It specifically enables developers to create reproducible environments that require dynamic setup logic, such as blockchain testnets. + +In this guide, the Kurtosis eth-network-package spins up a local Ethereum testnet with support for the [`geth`](https://geth.ethereum.org/) Execution Layer (EL) client, as well as [`teku`](https://consensys.net/knowledge-base/ethereum-2/teku/), [`lighthouse`](https://lighthouse.sigmaprime.io/), and [`lodestar`](https://lodestar.chainsafe.io/) Consensus Layer (CL) clients. This package serves as a configurable and composable alternative to networks in frameworks like Hardhat Network, Ganache, and Anvil. Kurtosis offers developers greater control and flexibility over the testnets they use, which is a major reason why the [Ethereum Foundation used Kurtosis to test the Merge](https://www.kurtosis.com/blog/testing-the-ethereum-merge) and continues to use it for testing network upgrades. + +## Setting up Kurtosis + +Before you proceed, make sure you have: + +- [Installed and started the Docker engine](https://docs.kurtosis.com/install/#i-install--start-docker) on your local machine +- [Installed the Kurtosis CLI](https://docs.kurtosis.com/install#ii-install-the-cli) (or upgraded it to the latest release, if you already have the CLI installed) +- Installed [Node.js](https://nodejs.org/en), [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable), and [npx](https://www.npmjs.com/package/npx) (for your dApp environment) + +## Instantiating a local Ethereum testnet + +To spin up a local Ethereum testnet, run: + +```python +kurtosis --enclave local-eth-testnet run github.com/kurtosis-tech/eth-network-package +``` + +Note: This command names your network: "local-eth-testnet” using the `--enclave` flag. + +Kurtosis will print the steps its taking under the hood as it works to interpret, validate, and then execute the instructions. At the end, you should see an output that resembles the following: + +```python +INFO[2023-04-04T18:09:44-04:00] ====================================================== +INFO[2023-04-04T18:09:44-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-04T18:09:44-04:00] ====================================================== +Name: local-eth-testnet +UUID: 39372d756ae8 +Status: RUNNING +Creation Time: Tue, 04 Apr 2023 18:09:03 EDT + +========================================= Files Artifacts ========================================= +UUID Name +d4085a064230 cl-genesis-data +1c62cb792e4c el-genesis-data +bd60489b73a7 genesis-generation-config-cl +b2e593fe5228 genesis-generation-config-el +d552a54acf78 geth-prefunded-keys +5f7e661eb838 prysm-password +054e7338bb59 validator-keystore-0 + +========================================== User Services ========================================== +UUID Name Ports Status +e20f129ee0c5 cl-client-0-beacon http: 4000/tcp -> RUNNING + metrics: 5054/tcp -> + tcp-discovery: 9000/tcp -> 127.0.0.1:54263 + udp-discovery: 9000/udp -> 127.0.0.1:60470 +a8b6c926cdb4 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:54267 RUNNING + metrics: 5064/tcp -> +d7b802f623e8 el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:54253 RUNNING + rpc: 8545/tcp -> 127.0.0.1:54251 + tcp-discovery: 30303/tcp -> 127.0.0.1:54254 + udp-discovery: 30303/udp -> 127.0.0.1:53834 + ws: 8546/tcp -> 127.0.0.1:54252 +514a829c0a84 prelaunch-data-generator-1680646157905431468 STOPPED +62bd62d0aa7a prelaunch-data-generator-1680646157915424301 STOPPED +05e9619e0e90 prelaunch-data-generator-1680646157922872635 STOPPED + +``` + +Congratulations! You used Kurtosis to instantiate a local Ethereum testnet, with a CL (`lighthouse`) and EL client (`geth`), over Docker. + +### Review + +In this section, you executed a command that directed Kurtosis to use the [`eth-network-package` hosted remotely on GitHub](https://github.com/kurtosis-tech/eth-network-package) to spin up a local Ethereum testnet within a Kurtosis [Enclave](https://docs.kurtosis.com/advanced-concepts/enclaves/). Inside your enclave, you will find both "file artifacts" and "user services". + +The [File Artifacts](https://docs.kurtosis.com/advanced-concepts/files-artifacts/) in your enclave include all the data generated and utilized to bootstrap the EL and CL clients. The data was created using the `prelaunch-data-generator` service built from this [Docker image](https://github.com/ethpandaops/ethereum-genesis-generator) + +User services display all the containerized services operating in your enclave. You will notice that a single node, featuring both an EL client and a CL client, has been created. + +## Connect your dApp development environment to the local Ethereum testnet + +### Setup the dApp development environment + +Now that you have a running local testnet, you can connect your dApp development environment to use your local testnet. The Hardhat framework will be used in this guide to deploy a blackjack dApp to your local testnet. + +To set up your dApp development environment, clone the repository that contains our sample dApp and install its dependencies, run: + +```python +git clone https://github.com/kurtosis-tech/awesome-kurtosis.git && cd awesome-kurtosis/smart-contract-example && yarn +``` + +The [smart-contract-example](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example) folder used here contains the typical setup for a dApp developer using the [Hardhat](https://hardhat.org/) framework: + +- [`contracts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/contracts) contains a few simple smart contracts for a Blackjack dApp +- [`scripts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/scripts) contains a script to deploy a token contract to your local Ethereum network +- [`test/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/test) contains a simple .js test for your token contract to confirm each player in our Blackjack dApp has 1000 minted for them +- [`hardhat.config.ts`](https://github.com/kurtosis-tech/awesome-kurtosis/blob/main/smart-contract-example/hardhat.config.ts) configures your Hardhat setup + +### Configure Hardhat to use the local testnet + +With your dApp development environment set up, you will now connect Hardhat to use the local Ethereum testnet generated using Kurtosis. To accomplish this, replace `` in the `localnet` struct in your `hardhat.config.ts` config file with the port of the rpc uri output from any `el-client-` service. In this sample case, the port would be `64248`. Your port will be different. + +Example in `hardhat.config.ts`: + +```js +localnet: , +``` + +Once you save your file, your Hardhat dApp development environment is now connected to your local Ethereum testnet! You can verify that your testnet is working by running: + +```python +npx hardhat balances --network localnet +``` + +The output should look something like this: + +```python +0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766 has balance 10000000000000000000000000 +0x4E9A3d9D1cd2A2b2371b8b3F489aE72259886f1A has balance 10000000000000000000000000 +0xdF8466f277964Bb7a0FFD819403302C34DCD530A has balance 10000000000000000000000000 +0x5c613e39Fc0Ad91AfDA24587e6f52192d75FBA50 has balance 10000000000000000000000000 +0x375ae6107f8cC4cF34842B71C6F746a362Ad8EAc has balance 10000000000000000000000000 +0x1F6298457C5d76270325B724Da5d1953923a6B88 has balance 10000000000000000000000000 +``` + +This confirms that Hardhat is using your local testnet and detects the pre-funded accounts created by the `eth-network-package`. + +### Deploy and test your dApp locally + +With the dApp development environment fully connected to the local Ethereum testnet, you can now run development and testing workflows against your dApp using the local testnet. + +To compile and deploy the `ChipToken.sol` smart contract for local prototyping and development, run: + +```python +npx hardhat compile +npx hardhat run scripts/deploy.ts --network localnet +``` + +The output should look something like: + +```python +ChipToken deployed to: 0xAb2A01BC351770D09611Ac80f1DE076D56E0487d +``` + +Now try running the `simple.js` test against your local dApp to confirm each player in our Blackjack dApp has 1000 minted for them: + +The output should look something like this: + +```python +npx hardhat test --network localnet +``` + +The output should look something like this: + +```python +ChipToken + mint + ✔ should mint 1000 chips for PLAYER ONE + + 1 passing (654ms) +``` + +### Review + +At this point, you’ve now set up a dApp development environment, connected it to a local Ethereum network created by Kurtosis, and have compiled, deployed, and ran a simple test against your dApp. + +Now let’s explore how you can configure the underlying network for testing our dApps under varying network configurations. + +## Configuring the local Ethereum testnet + +### Changing the client configurations and number of nodes + +Your local Ethereum testnet can be configured to use different EL and CL client pairs, as well as a varying number of nodes, depending on the scenario and specific network configuration you want to develop or test. This means that, once set up, you can spin up a customized local testnet and use it to run the same workflows (deployment, tests, etc.) under various network configurations to ensure everything works as expected. To learn more about the other parameters you can modify, visit this link. + +Give it a try! You can pass various configuration options to the `eth-network-package` via a JSON file. This network params JSON file provides the specific configurations that Kurtosis will use to set up the local Ethereum network. + +Take the default configuration file and edit it to spin up two nodes with different EL/CL pairs: + +- Node 1 with `geth`/`lighthouse` +- Node 2 with `geth`/`lodestar` +- Node 3 with `geth`/`teku` + +This configuration creates a heterogeneous network of Ethereum node implementations for testing your dApp. Your configuration file should now look like: + +```yaml +, + , + , + ], + "network_params": + , +} +``` + +Each `participants` struct maps to a node in the network, so 3 `participants` structs will tell Kurtosis to spin up 3 nodes in your network. Each `participants` struct will allow you to specify the EL and CL pair used for that specific node. + +The `network_params` struct configures the network settings that are used to create the genesis files for each node as well as other settings like the seconds per slot of the network. + +Save your edited params file in any directory you wish (in the example below, it is saved to the desktop) and then use it to run your Kurtosis package by running: + +```python +kurtosis clean -a && kurtosis run --enclave local-eth-testnet github.com/kurtosis-tech/eth-network-package "$(cat ~/eth-network-params.json)" +``` + +Note: the `kurtosis clean -a` command is used here to instruct Kurtosis to destroy the old testnet and its contents before starting a new one up. + +Again, Kurtosis will work for a bit and print out the individual steps that are taking place. Eventually, the output should look something like: + +```python +Starlark code successfully run. No output was returned. +INFO[2023-04-07T11:43:16-04:00] ========================================================== +INFO[2023-04-07T11:43:16-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-07T11:43:16-04:00] ========================================================== +Name: local-eth-testnet +UUID: bef8c192008e +Status: RUNNING +Creation Time: Fri, 07 Apr 2023 11:41:58 EDT + +========================================= Files Artifacts ========================================= +UUID Name +cc495a8e364a cl-genesis-data +7033fcdb5471 el-genesis-data +a3aef43fc738 genesis-generation-config-cl +8e968005fc9d genesis-generation-config-el +3182cca9d3cd geth-prefunded-keys +8421166e234f prysm-password +d9e6e8d44d99 validator-keystore-0 +23f5ba517394 validator-keystore-1 +4d28dea40b5c validator-keystore-2 + +========================================== User Services ========================================== +UUID Name Ports Status +485e6fde55ae cl-client-0-beacon http: 4000/tcp -> http://127.0.0.1:65010 RUNNING + metrics: 5054/tcp -> http://127.0.0.1:65011 + tcp-discovery: 9000/tcp -> 127.0.0.1:65012 + udp-discovery: 9000/udp -> 127.0.0.1:54455 +73739bd158b2 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:65016 RUNNING + metrics: 5064/tcp -> http://127.0.0.1:65017 +1b0a233cd011 cl-client-1-beacon http: 4000/tcp -> 127.0.0.1:65021 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65023 + tcp-discovery: 9000/tcp -> 127.0.0.1:65024 + udp-discovery: 9000/udp -> 127.0.0.1:56031 + validator-metrics: 5064/tcp -> 127.0.0.1:65022 +949b8220cd53 cl-client-1-validator http: 4000/tcp -> 127.0.0.1:65028 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65030 + tcp-discovery: 9000/tcp -> 127.0.0.1:65031 + udp-discovery: 9000/udp -> 127.0.0.1:60784 + validator-metrics: 5064/tcp -> 127.0.0.1:65029 +c34417bea5fa cl-client-2 http: 4000/tcp -> 127.0.0.1:65037 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65035 + tcp-discovery: 9000/tcp -> 127.0.0.1:65036 + udp-discovery: 9000/udp -> 127.0.0.1:63581 +e19738e6329d el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:64986 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64988 + tcp-discovery: 30303/tcp -> 127.0.0.1:64987 + udp-discovery: 30303/udp -> 127.0.0.1:55706 + ws: 8546/tcp -> 127.0.0.1:64989 +e904687449d9 el-client-1 engine-rpc: 8551/tcp -> 127.0.0.1:64993 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64995 + tcp-discovery: 30303/tcp -> 127.0.0.1:64994 + udp-discovery: 30303/udp -> 127.0.0.1:58096 + ws: 8546/tcp -> 127.0.0.1:64996 +ad6f401126fa el-client-2 engine-rpc: 8551/tcp -> 127.0.0.1:65003 RUNNING + rpc: 8545/tcp -> 127.0.0.1:65001 + tcp-discovery: 30303/tcp -> 127.0.0.1:65000 + udp-discovery: 30303/udp -> 127.0.0.1:57269 + ws: 8546/tcp -> 127.0.0.1:65002 +12d04a9dbb69 prelaunch-data-generator-1680882122181135513 STOPPED +5b45f9c0504b prelaunch-data-generator-1680882122192182847 STOPPED +3d4aaa75e218 prelaunch-data-generator-1680882122201668972 STOPPED +``` + +Congratulations! You’ve successfully configured your local testnet to have 3 nodes instead of 1. To run the same workflows you did before against your dApp (deploy & test), perform the same operations we did before by replacing the `` in the `localnet` struct in your `hardhat.config.ts` config file with the port of the rpc uri output from any `el-client-` service in your new, 3-node local testnet. + +## Conclusion + +And that's it! To recap this short guide, you: + +- Created a local Ethereum testnet over Docker using Kurtosis +- Connected your local dApp development environment to the local Ethereum network +- Deployed a dApp and ran a simple test against it on the local Ethereum network +- Configured the underlying Ethereum network to have 3 nodes + +We’d love to hear from you on what went well for you, what could be improved, or to answer any of your questions. Don’t hesitate to reach out via [GitHub](https://github.com/kurtosis-tech/kurtosis/issues/new/choose) or [email us](mailto:feedback@kurtosistech.com)! + +### Other examples and guides + +We encourage you to check out our [quickstart](https://docs.kurtosis.com/quickstart) (where you’ll build a Postgres database and API on top) and our other examples in our [awesome-kurtosis repository](https://github.com/kurtosis-tech/awesome-kurtosis) where you’ll find some great examples, including packages for: + +- [Spinning up the same local Ethereum testnet](https://github.com/kurtosis-tech/eth2-package), but with additional services connected such as a transaction spammer (to simulate transactions), a fork monitor, and a connected Grafana and Prometheus instance +- Performing a [sub-networking test](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/ethereum-network-partition-test) against the same local Ethereum network + +--- + +## Developers > Tutorials > Downsizing Contracts To Fight The Contract Size Limit + +## Why is there a limit? + +On [November 22, 2016](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/) the Spurious Dragon hard-fork introduced [EIP-170](https://eips.ethereum.org/EIPS/eip-170) which added a smart contract size limit of 24.576 kb. For you as a Solidity developer this means when you add more and more functionality to your contract, at some point you will reach the limit and when deploying will see the error: + +`Warning: Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.` + +This limit was introduced to prevent denial-of-service (DOS) attacks. Any call to a contract is relatively cheap gas-wise. However, the impact of a contract call for Ethereum nodes increases disproportionately depending on the called contract code's size (reading the code from disk, pre-processing the code, adding data to the Merkle proof). Whenever you have such a situation where the attacker requires few resources to cause a lot of work for others, you get the potential for DOS attacks. + +Originally this was less of a problem because one natural contract size limit is the block gas limit. Obviously, a contract must be deployed within a transaction that holds all of the contract's bytecode. If you include only that one transaction into a block, you can use up all that gas, but it's not infinite. Since the [London Upgrade](/history/#london), the block gas limit has been able to vary between 15M and 30M units depending on network demand. + +In the following we will look at some methods ordered by their potential impact. Think about it in the terms of weight-loss. The best strategy for someone to hit their target weight (in our case 24kb) is to focus on the big impact methods first. In most cases just fixing your diet will get you there, but sometimes you need a little bit more. Then you might add some exercise (medium impact) or even supplements (small impact). + +## Big impact + +### Separate your contracts + +This should always be your first approach. How can you separate the contract into multiple smaller ones? It generally forces you to come up with a good architecture for your contracts. Smaller contracts are always preferred from a code readability perspective. For splitting contracts, ask yourself: + +- Which functions belong together? Each set of functions might be best in its own contract. +- Which functions don't require reading contract state or just a specific subset of the state? +- Can you split storage and functionality? + +### Libraries + +One simple way to move functionality code away from the storage is using a [library](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#libraries). Don't declare the library functions as internal as those will be [added to the contract](https://ethereum.stackexchange.com/questions/12975/are-internal-functions-in-libraries-not-covered-by-linking) directly during compilation. But if you use public functions, then those will be in fact in a separate library contract. Consider [using for](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#using-for) to make the use of libraries more convenient. + +### Proxies + +A more advanced strategy would be a proxy system. Libraries use `DELEGATECALL` in the back which simply executes another contract's function with the state of the calling contract. Check out [this blog post](https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2) to learn more about proxy systems. They give you more functionality, e.g., they enable upgradability, but they also add a lot of complexity. I wouldn't add those only to reduce contract sizes unless it's your only option for whatever reason. + +## Medium impact + +### Remove functions + +This one should be obvious. Functions increase a contract size quite a bit. + +- **External**: Often times we add a lot of view functions for convenience reasons. That's perfectly fine until you hit the size limit. Then you might want to really think about removing all but absolutely essential ones. +- **Internal**: You can also remove internal/private functions and simply inline the code as long the function is called only once. + +### Avoid additional variables + +A simple change like this: + +```solidity +function get(uint id) returns (address,address) +``` + +```solidity +function get(uint id) returns (address,address) +``` + +makes a difference of **0.28kb**. Chances are you can find many similar situations in your contracts and those can really add up to significant amounts. + +### Shorten error message + +Long revert messages and in particular many different revert messages can bloat up the contract. Instead use short error codes and decode them in your contract. A long message could be become much shorter: + +```solidity +require(msg.sender == owner, "Only the owner of this contract can call this function"); + +``` + +```solidity +require(msg.sender == owner, "OW1"); +``` + +### Use custom errors instead of error messages + +Custom errors have been introduced in [Solidity 0.8.4](https://blog.soliditylang.org/2021/04/21/custom-errors/). They are a great way to reduce the size of your contracts, because they are ABI-encoded as selectors (just like functions are). + +```solidity +error Unauthorized(); + +if (msg.sender != owner) +``` + +### Consider a low run value in the optimizer + +You can also change the optimizer settings. The default value of 200 means that it's trying to optimize the bytecode as if a function is called 200 times. If you change it to 1, you basically tell the optimizer to optimize for the case of running each function only once. An optimized function for running only one time means it is optimized for the deployment itself. Be aware that **this increases the [gas costs](/developers/docs/gas/) for running the functions**, so you may not want to do it. + +## Small impact + +### Avoid passing structs to functions + +If you are using the [ABIEncoderV2](https://solidity.readthedocs.io/en/v0.6.10/layout-of-source-files.html#abiencoderv2), it can help to not pass structs to a function. Instead of passing the parameter as a struct... + +```solidity +function get(uint id) returns (address,address) + +function _get(MyStruct memory myStruct) private view returns(address,address) +``` + +```solidity +function get(uint id) returns(address,address) + +function _get(address addr1, address addr2) private view returns(address,address) +``` + +... pass the required parameters directly. In this example we saved another **0.1kb**. + +### Declare correct visibility for functions and variables + +- Functions or variables that are only called from the outside? Declare them as `external` instead of `public`. +- Functions or variables only called from within the contract? Declare them as `private` or `internal` instead of `public`. + +### Remove modifiers + +Modifiers, especially when used intensely, could have a significant impact on the contract size. Consider removing them and instead use functions. + +```solidity +modifier checkStuff() {} + +function doSomething() checkStuff {} +``` + +```solidity +function checkStuff() private {} + +function doSomething() +``` + +Those tips should help you to significantly reduce the contract size. Once again, I cannot stress enough, always focus on splitting contracts if possible for the biggest impact. + +--- + +## Developers > Tutorials > Eip 1271 Smart Contract Signatures + +The [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) standard allows smart contracts to verify signatures. + +In this tutorial, we give an overview of digital signatures, EIP-1271's background, and the specific implementation of EIP-1271 used by [Safe](https://safe.global/) (previously Gnosis Safe). All together, this can serve as a starting point for implementing EIP-1271 in your own contracts. + +## What is a signature? + +In this context, a signature (more precisely, a “digital signature”) is a message plus some sort of proof that the message came from a specific person/sender/address. + +For instance, a digital signature might look like this: + +1. Message: “I want to log in to this website with my Ethereum wallet.” +2. Signer: My address is `0x000…` +3. Proof: Here is some proof that I, `0x000…`, actually created this entire message (this is usually something cryptographic). + +It’s important to note that a digital signature includes both a “message” and a “signature”. + +Why? For instance, if you gave me a contract to sign, and then I cut off the signature page and gave you back only my signatures without the rest of the contract, the contract would not be valid. + +In the same way, a digital signature doesn’t mean anything without an associated message! + +## Why does EIP-1271 exist? + +In order to create a digital signature for use on Ethereum-based blockchains, you generally need a secret private key which no one else knows. This is what makes your signature, yours (no one else can create the same signature without knowledge of the secret key). + +Your Ethereum account (i.e. your externally-owned account/EOA) has a private key associated with it, and this is the private key that’s typically used when a website or dapp asks you for a signature (e.g. for “Log in with Ethereum”). + +An app can [verify a signature](https://docs.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum) you create using a third-party library like ethers.js [without knowing your private key](https://en.wikipedia.org/wiki/Public-key_cryptography) and be confident that _you_ were the one that created the signature. + +> In fact, because EOA digital signatures use public-key cryptography, they can be generated and verified **offchain**! This is how gasless DAO voting works — instead of submitting votes onchain, digital signatures can be created and verified offchain using cryptographic libraries. + +While EOA accounts have a private key, smart contract accounts do not have any sort of private or secret key (so "Log in with Ethereum", etc. cannot natively work with smart contract accounts). + +The problem EIP-1271 aims to solve: how can we tell that a smart contract signature is valid if the smart contract has no “secret” it can incorporate into the signature? + +## How does EIP-1271 work? + +Smart contracts don’t have private keys that can be used to sign messages. So how can we tell if a signature is authentic? + +Well, one idea is that we can just _ask_ the smart contract if a signature is authentic! + +What EIP-1271 does is it standardizes this idea “asking” a smart contract if a given signature is valid. + +A contract that implements EIP-1271 must have a function called `isValidSignature` which takes in a message and a signature. The contract can then run some validation logic (the spec does not enforce anything specific here) and then return a value indicating whether the signature is valid or not. + +If `isValidSignature` returns a valid result, that’s pretty much the contract saying “yes, I approve this signature + message!” + +### Interface + +Here’s the exact interface in the EIP-1271 spec (we’ll talk about the `_hash` parameter below, but for now, think of it as the message that is being verified): + +```jsx +pragma solidity ^0.5.0; + +contract ERC1271 +``` + +## Example EIP-1271 Implementation: Safe + +Contracts can implement `isValidSignature` in many ways — the spec only doesn’t say much about the exact implementation. + +One notable contract which implements EIP-1271 is Safe (previously Gnosis Safe). + +In Safe’s code, `isValidSignature` [is implemented](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol) so that signatures can be created and verified in [two ways](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support): + +1. Onchain messages + 1. Creation: a safe owner creates a new safe transaction to “sign” a message, passing the message as data into the transaction. Once enough owners sign the transaction to reach the multisig threshold, the transaction is broadcast and run. In the transaction, there is a safe function called which adds the message to a list of “approved” messages. + 2. Verification: call `isValidSignature` on the Safe contract, and pass in the message to verify as the message parameter and [an empty value for the signature parameter](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32) (i.e. `0x`). The Safe will see that the signature parameter is empty and instead of cryptographically verifying the signature, it will know to just go ahead and check whether the message is on the list of “approved” messages. +2. Offchain messages: + 1. Creation: a safe owner creates a message offchain, then gets other safe owners to sign the message each individually until there are enough signatures to overcome the multisig approval threshold. + 2. Verification: call `isValidSignature`. In the message parameter, pass in the message to be verified. In the signature parameter, pass in each safe owner’s individual signatures all concatenated together, back-to-back. The Safe will check that there are enough signatures to meet the threshold **and** that each signature is valid. If so, it will return a value indicating successful signature verification. + +## What exactly is the `_hash` parameter? Why not pass the whole message? + +You might have noticed that the `isValidSignature` function in the [EIP-1271 interface](https://eips.ethereum.org/EIPS/eip-1271) doesn’t take in the message itself, but instead a `_hash` parameter. What this means is that instead of passing the full arbitrary-length message to `isValidSignature`, we instead pass a 32-byte hash of the message (generally keccak256). + +Each byte of calldata — i.e. function parameter data passed to a smart contract function — [costs 16 gas (4 gas if zero byte)](https://eips.ethereum.org/EIPS/eip-2028), so this can save a lot of gas if a message is long. + +### Previous EIP-1271 Specifications + +There are EIP-1271 specifications in the wild that have an `isValidSignature` function with a first parameter of type `bytes` (arbitrary-length, instead of a fixed-length `bytes32`) and parameter name `message`. This is an [older version](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206) of the EIP-1271 standard. + +## How should EIP-1271 be implemented in my own contracts? + +The spec is very open-ended here. The Safe implementation has some good ideas: + +- You can consider EOA signatures from the "owner" of the contract to be valid. +- You could store a list of approved messages and only consider those to be valid. + +In the end, it is up to you as the contract developer! + +## Conclusion + +[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) is a versatile standard that allows smart contracts to verify signatures. It opens the door for smart contracts to act more like EOAs — for instance providing a way for "Log in with Ethereum" to work with smart contracts — and it can be implemented in many ways (Safe having a nontrivial, interesting implementation to consider). + +--- + +## Developers > Tutorials > Erc 721 Vyper Annotated Code + +## Introduction + +The [ERC-721](/developers/docs/standards/tokens/erc-721/) standard is used to hold the ownership of Non-Fungible Tokens (NFT). +[ERC-20](/developers/docs/standards/tokens/erc-20/) tokens behave as a commodity, because there is no difference between individual tokens. +In contrast to that, ERC-721 tokens are designed for assets that are similar but not identical, such as different [cat +cartoons](https://www.cryptokitties.co/) +or titles to different pieces of real estate. + +In this article we will analyze [Ryuya Nakamura's ERC-721 contract](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy). +This contract is written in [Vyper](https://vyper.readthedocs.io/en/latest/index.html), a Python-like contract language designed to make +it harder to write insecure code than it is in Solidity. + +## The Contract + +```python +# @dev Implementation of ERC-721 non-fungible token standard. +# @author Ryuya Nakamura (@nrryuya) +# Modified from: https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy +``` + +Comments in Vyper, as in Python, start with a hash (`#`) and continue to the end of the line. Comments that include +`@` are used by [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) to produce human-readable +documentation. + +```python +from vyper.interfaces import ERC721 + +implements: ERC721 +``` + +The ERC-721 interface is built into the Vyper language. +[You can see the code definition here](https://github.com/vyperlang/vyper/blob/master/vyper/builtin_interfaces/ERC721.py). +The interface definition is written in Python, rather than Vyper, because interfaces are used not only within the +blockchain, but also when sending the blockchain a transaction from an external client, which may be written in +Python. + +The first line imports the interface, and the second specifies that we are implementing it here. + +### The ERC721Receiver Interface + +```python +# Interface for the contract called by safeTransferFrom() +interface ERC721Receiver: + def onERC721Received( +``` + +ERC-721 supports two types of transfer: + +- `transferFrom`, which lets the sender specify any destination address and places the responsibility + for the transfer on the sender. This means that you can transfer to an invalid address, in which case + the NFT is lost for good. +- `safeTransferFrom`, which checks if the destination address is a contract. If so, the ERC-721 contract + asks the receiving contract if it wants to receive the NFT. + +To answer `safeTransferFrom` requests a receiving contract has to implement `ERC721Receiver`. + +```python + _operator: address, + _from: address, +``` + +The `_from` address is the current owner of the token. The `_operator` address is the one that +requested the transfer (those two may not be the same, because of allowances). + +```python + _tokenId: uint256, +``` + +ERC-721 token IDs are 256 bits. Typically they are created by hashing a description of whatever +the token represents. + +```python + _data: Bytes[1024] +``` + +The request can have up to 1024 bytes of user data. + +```python + ) -> bytes32: view +``` + +To prevent cases in which a contract accidentally accepts a transfer the return value is not a boolean, +but 256 bits with a specific value. + +This function is a `view`, which means it can read the state of the blockchain, but not modify it. + +### Events + +[Events](https://media.consensys.net/technical-introduction-to-events-and-logs-in-ethereum-a074d65dd61e) +are emitted to inform users and servers outside of the blockchain of events. Note that the content of events +is not available to contracts on the blockchain. + +```python +# @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are +# created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any +# number of NFTs may be created and assigned without emitting Transfer. At the time of any +# transfer, the approved address for that NFT (if any) is reset to none. +# @param _from Sender of NFT (if address is zero address it indicates token creation). +# @param _to Receiver of NFT (if address is zero address it indicates token destruction). +# @param _tokenId The NFT that got transferred. +event Transfer: + sender: indexed(address) + receiver: indexed(address) + tokenId: indexed(uint256) +``` + +This is similar to the ERC-20 Transfer event, except that we report a `tokenId` instead of an amount. +Nobody owns address zero, so by convention we use it to report creation and destruction of tokens. + +```python +# @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero +# address indicates there is no approved address. When a Transfer event emits, this also +# indicates that the approved address for that NFT (if any) is reset to none. +# @param _owner Owner of NFT. +# @param _approved Address that we are approving. +# @param _tokenId NFT which we are approving. +event Approval: + owner: indexed(address) + approved: indexed(address) + tokenId: indexed(uint256) +``` + +An ERC-721 approval is similar to an ERC-20 allowance. A specific address is allowed to transfer a specific +token. This gives a mechanism for contracts to respond when they accept a token. Contracts cannot +listen for events, so if you just transfer the token to them they don't "know" about it. This way the +owner first submits an approval and then sends a request to the contract: "I approved for you to transfer token +X, please do ...". + +This is a design choice to make the ERC-721 standard similar to the ERC-20 standard. Because +ERC-721 tokens are not fungible, a contract can also identify that it got a specific token by +looking at the token's ownership. + +```python +# @dev This emits when an operator is enabled or disabled for an owner. The operator can manage +# all NFTs of the owner. +# @param _owner Owner of NFT. +# @param _operator Address to which we are setting operator rights. +# @param _approved Status of operator rights(true if operator rights are given and false if +# revoked). +event ApprovalForAll: + owner: indexed(address) + operator: indexed(address) + approved: bool +``` + +It is sometimes useful to have an _operator_ that can manage all of an account's tokens of a specific type (those that are managed by +a specific contract), similar to a power of attorney. For example, I might want to give such a power to a contract that checks if +I haven't contacted it for six months, and if so distributes my assets to my heirs (if one of them asks for it, contracts +can't do anything without being called by a transaction). In ERC-20 we can just give a high allowance to an inheritance contract, +but that doesn't work for ERC-721 because the tokens are not fungible. This is the equivalent. + +The `approved` value tells us whether the event is for an approval, or the withdrawal of an approval. + +### State Variables + +These variables contain the current state of the tokens: which ones are available and who owns them. Most of these +are `HashMap` objects, [unidirectional mappings that exist between two types](https://vyper.readthedocs.io/en/latest/types.html#mappings). + +```python +# @dev Mapping from NFT ID to the address that owns it. +idToOwner: HashMap[uint256, address] + +# @dev Mapping from NFT ID to approved address. +idToApprovals: HashMap[uint256, address] +``` + +User and contract identities in Ethereum are represented by 160-bit addresses. These two variables map +from token IDs to their owners and those approved to transfer them (at a maximum of one for each). In Ethereum, +uninitialized data is always zero, so if there is no owner or approved transferor the value for that token +is zero. + +```python +# @dev Mapping from owner address to count of his tokens. +ownerToNFTokenCount: HashMap[address, uint256] +``` + +This variable holds the count of tokens for each owner. There is no mapping from owners to tokens, so +the only way to identify the tokens that a specific owner owns is to look back in the blockchain's event history +and see the appropriate `Transfer` events. We can use this variable to know when we have all the NFTs and don't +need to look even further in time. + +Note that this algorithm only works for user interfaces and external servers. Code running on the blockchain +itself cannot read past events. + +```python +# @dev Mapping from owner address to mapping of operator addresses. +ownerToOperators: HashMap[address, HashMap[address, bool]] +``` + +An account may have more than a single operator. A simple `HashMap` is insufficient to +keep track of them, because each key leads to a single value. Instead, you can use +`HashMap[address, bool]` as the value. By default the value for each address is `False`, which means it +is not an operator. You can set values to `True` as needed. + +```python +# @dev Address of minter, who can mint a token +minter: address +``` + +New tokens have to be created somehow. In this contract there is a single entity that is allowed to do so, the +`minter`. This is likely to be sufficient for a game, for example. For other purposes, it might be necessary +to create a more complicated business logic. + +```python +# @dev Mapping of interface id to bool about whether or not it's supported +supportedInterfaces: HashMap[bytes32, bool] + +# @dev ERC165 interface ID of ERC165 +ERC165_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7 + +# @dev ERC165 interface ID of ERC721 +ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000080ac58cd +``` + +[ERC-165](https://eips.ethereum.org/EIPS/eip-165) specifies a mechanism for a contract to disclose how applications +can communicate with it, to which ERCs it conforms. In this case, the contract conforms to ERC-165 and ERC-721. + +### Functions + +These are the functions that actually implement ERC-721. + +#### Constructor + +```python +@external +def __init__(): +``` + +In Vyper, as in Python, the constructor function is called `__init__`. + +```python + """ + @dev Contract constructor. + """ +``` + +In Python, and in Vyper, you can also create a comment by specifying a multi-line string (which starts and ends +with `"""`), and not using it in any way. These comments can also include +[NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html). + +```python + self.supportedInterfaces[ERC165_INTERFACE_ID] = True + self.supportedInterfaces[ERC721_INTERFACE_ID] = True + self.minter = msg.sender +``` + +To access state variables you use `self.` (again, same as in Python). + +#### View Functions + +These are functions that do not modify the state of the blockchain, and therefore can be executed for +free if they are called externally. If the view functions are called by a contract they still have to be executed on +every node and therefore cost gas. + +```python +@view +@external +``` + +These keywords prior to a function definition that start with an at sign (`@`) are called _decorations_. They +specify the circumstances in which a function can be called. + +- `@view` specifies that this function is a view. +- `@external` specifies that this particular function can be called by transactions and by other contracts. + +```python +def supportsInterface(_interfaceID: bytes32) -> bool: +``` + +In contrast to Python, Vyper is a [static typed language](https://wikipedia.org/wiki/Type_system#Static_type_checking). +You can't declare a variable, or a function parameter, without identifying the [data type](https://vyper.readthedocs.io/en/latest/types.html). In this case the input parameter is `bytes32`, a 256-bit value +(256 bits is the native word size of the [Ethereum Virtual Machine](/developers/docs/evm/)). The output is a boolean +value. By convention, the names of function parameters start with an underscore (`_`). + +```python + """ + @dev Interface identification is specified in ERC-165. + @param _interfaceID Id of the interface + """ + return self.supportedInterfaces[_interfaceID] +``` + +Return the value from the `self.supportedInterfaces` HashMap, which is set in the constructor (`__init__`). + +```python +### VIEW FUNCTIONS ### +``` + +These are the view functions that make information about the tokens available to users and other contracts. + +```python +@view +@external +def balanceOf(_owner: address) -> uint256: + """ + @dev Returns the number of NFTs owned by `_owner`. + Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. + @param _owner Address for whom to query the balance. + """ + assert _owner != ZERO_ADDRESS +``` + +This line [asserts](https://vyper.readthedocs.io/en/latest/statements.html#assert) that `_owner` is not +zero. If it is, there is an error and the operation is reverted. + +```python + return self.ownerToNFTokenCount[_owner] + +@view +@external +def ownerOf(_tokenId: uint256) -> address: + """ + @dev Returns the address of the owner of the NFT. + Throws if `_tokenId` is not a valid NFT. + @param _tokenId The identifier for an NFT. + """ + owner: address = self.idToOwner[_tokenId] + # Throws if `_tokenId` is not a valid NFT + assert owner != ZERO_ADDRESS + return owner +``` + +In the Ethereum Virtual Machine (evm) any storage that does not have a value stored in it is zero. +If there is no token at `_tokenId` then the value of `self.idToOwner[_tokenId]` is zero. In that +case the function reverts. + +```python +@view +@external +def getApproved(_tokenId: uint256) -> address: + """ + @dev Get the approved address for a single NFT. + Throws if `_tokenId` is not a valid NFT. + @param _tokenId ID of the NFT to query the approval of. + """ + # Throws if `_tokenId` is not a valid NFT + assert self.idToOwner[_tokenId] != ZERO_ADDRESS + return self.idToApprovals[_tokenId] +``` + +Note that `getApproved` _can_ return zero. If the token is valid it returns `self.idToApprovals[_tokenId]`. +If there is no approver that value is zero. + +```python +@view +@external +def isApprovedForAll(_owner: address, _operator: address) -> bool: + """ + @dev Checks if `_operator` is an approved operator for `_owner`. + @param _owner The address that owns the NFTs. + @param _operator The address that acts on behalf of the owner. + """ + return (self.ownerToOperators[_owner])[_operator] +``` + +This function checks if `_operator` is allowed to manage all of `_owner`'s tokens in this contract. +Because there can be multiple operators, this is a two level HashMap. + +#### Transfer Helper Functions + +These functions implement operations that are part of transferring or managing tokens. + +```python + +### TRANSFER FUNCTION HELPERS ### + +@view +@internal +``` + +This decoration, `@internal`, means that the function is only accessible from other functions within the +same contract. By convention, these function names also start with an underscore (`_`). + +```python +def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool: + """ + @dev Returns whether the given spender can transfer a given token ID + @param spender address of the spender to query + @param tokenId uint256 ID of the token to be transferred + @return bool whether the msg.sender is approved for the given token ID, + is an operator of the owner, or is the owner of the token + """ + owner: address = self.idToOwner[_tokenId] + spenderIsOwner: bool = owner == _spender + spenderIsApproved: bool = _spender == self.idToApprovals[_tokenId] + spenderIsApprovedForAll: bool = (self.ownerToOperators[owner])[_spender] + return (spenderIsOwner or spenderIsApproved) or spenderIsApprovedForAll +``` + +There are three ways in which an address can be allowed to transfer a token: + +1. The address is the owner of the token +2. The address is approved to spend that token +3. The address is an operator for the owner of the token + +The function above can be a view because it doesn't change the state. To reduce operating costs, any +function that _can_ be a view _should_ be a view. + +```python +@internal +def _addTokenTo(_to: address, _tokenId: uint256): + """ + @dev Add a NFT to a given address + Throws if `_tokenId` is owned by someone. + """ + # Throws if `_tokenId` is owned by someone + assert self.idToOwner[_tokenId] == ZERO_ADDRESS + # Change the owner + self.idToOwner[_tokenId] = _to + # Change count tracking + self.ownerToNFTokenCount[_to] += 1 + + +@internal +def _removeTokenFrom(_from: address, _tokenId: uint256): + """ + @dev Remove a NFT from a given address + Throws if `_from` is not the current owner. + """ + # Throws if `_from` is not the current owner + assert self.idToOwner[_tokenId] == _from + # Change the owner + self.idToOwner[_tokenId] = ZERO_ADDRESS + # Change count tracking + self.ownerToNFTokenCount[_from] -= 1 +``` + +When there's a problem with a transfer we revert the call. + +```python +@internal +def _clearApproval(_owner: address, _tokenId: uint256): + """ + @dev Clear an approval of a given address + Throws if `_owner` is not the current owner. + """ + # Throws if `_owner` is not the current owner + assert self.idToOwner[_tokenId] == _owner + if self.idToApprovals[_tokenId] != ZERO_ADDRESS: + # Reset approvals + self.idToApprovals[_tokenId] = ZERO_ADDRESS +``` + +Only change the value if necessary. State variables live in storage. Writing to storage is +one of the most expensive operations the EVM (Ethereum Virtual Machine) does (in terms of +[gas](/developers/docs/gas/)). Therefore, it is a good idea to minimize it, even writing the +existing value has a high cost. + +```python +@internal +def _transferFrom(_from: address, _to: address, _tokenId: uint256, _sender: address): + """ + @dev Execute transfer of a NFT. + Throws unless `msg.sender` is the current owner, an authorized operator, or the approved + address for this NFT. (NOTE: `msg.sender` not allowed in private function so pass `_sender`.) + Throws if `_to` is the zero address. + Throws if `_from` is not the current owner. + Throws if `_tokenId` is not a valid NFT. + """ +``` + +We have this internal function because there are two ways to transfer tokens (regular and safe), but +we want only a single location in the code where we do it to make auditing easier. + +```python + # Check requirements + assert self._isApprovedOrOwner(_sender, _tokenId) + # Throws if `_to` is the zero address + assert _to != ZERO_ADDRESS + # Clear approval. Throws if `_from` is not the current owner + self._clearApproval(_from, _tokenId) + # Remove NFT. Throws if `_tokenId` is not a valid NFT + self._removeTokenFrom(_from, _tokenId) + # Add NFT + self._addTokenTo(_to, _tokenId) + # Log the transfer + log Transfer(_from, _to, _tokenId) +``` + +To emit an event in Vyper you use a `log` statement ([see here for more details](https://vyper.readthedocs.io/en/latest/event-logging.html#event-logging)). + +#### Transfer Functions + +```python + +### TRANSFER FUNCTIONS ### + +@external +def transferFrom(_from: address, _to: address, _tokenId: uint256): + """ + @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved + address for this NFT. + Throws if `_from` is not the current owner. + Throws if `_to` is the zero address. + Throws if `_tokenId` is not a valid NFT. + @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else + they maybe be permanently lost. + @param _from The current owner of the NFT. + @param _to The new owner. + @param _tokenId The NFT to transfer. + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +This function lets you transfer to an arbitrary address. Unless the address is a user, or a contract that +knows how to transfer tokens, any token you transfer will be stuck in that address and useless. + +```python +@external +def safeTransferFrom( + _from: address, + _to: address, + _tokenId: uint256, + _data: Bytes[1024]=b"" + ): + """ + @dev Transfers the ownership of an NFT from one address to another address. + Throws unless `msg.sender` is the current owner, an authorized operator, or the + approved address for this NFT. + Throws if `_from` is not the current owner. + Throws if `_to` is the zero address. + Throws if `_tokenId` is not a valid NFT. + If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if + the return value is not `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + NOTE: bytes4 is represented by bytes32 with padding + @param _from The current owner of the NFT. + @param _to The new owner. + @param _tokenId The NFT to transfer. + @param _data Additional data with no specified format, sent in call to `_to`. + """ + self._transferFrom(_from, _to, _tokenId, msg.sender) +``` + +It is OK to do the transfer first because if there's a problem we are going to revert anyway, +so everything done in the call will be cancelled. + +```python + if _to.is_contract: # check if `_to` is a contract address +``` + +First check to see if the address is a contract (if it has code). If not, assume it is a user +address and the user will be able to use the token or transfer it. But don't let it lull you +into a false sense of security. You can lose tokens, even with `safeTransferFrom`, if you transfer +them to an address for which nobody knows the private key. + +```python + returnValue: bytes32 = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) +``` + +Call the target contract to see if it can receive ERC-721 tokens. + +```python + # Throws if transfer destination is a contract which does not implement 'onERC721Received' + assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes32) +``` + +If the destination is a contract, but one that doesn't accept ERC-721 tokens (or that decided not to accept this +particular transfer), revert. + +```python +@external +def approve(_approved: address, _tokenId: uint256): + """ + @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address. + Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. + Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP) + Throws if `_approved` is the current owner. (NOTE: This is not written the EIP) + @param _approved Address to be approved for the given NFT ID. + @param _tokenId ID of the token to be approved. + """ + owner: address = self.idToOwner[_tokenId] + # Throws if `_tokenId` is not a valid NFT + assert owner != ZERO_ADDRESS + # Throws if `_approved` is the current owner + assert _approved != owner +``` + +By convention if you want not to have an approver you appoint the zero address, not yourself. + +```python + # Check requirements + senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender + senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender] + assert (senderIsOwner or senderIsApprovedForAll) +``` + +To set an approval you can either be the owner, or an operator authorized by the owner. + +```python + # Set the approval + self.idToApprovals[_tokenId] = _approved + log Approval(owner, _approved, _tokenId) + + +@external +def setApprovalForAll(_operator: address, _approved: bool): + """ + @dev Enables or disables approval for a third party ("operator") to manage all of + `msg.sender`'s assets. It also emits the ApprovalForAll event. + Throws if `_operator` is the `msg.sender`. (NOTE: This is not written the EIP) + @notice This works even if sender doesn't own any tokens at the time. + @param _operator Address to add to the set of authorized operators. + @param _approved True if the operators is approved, false to revoke approval. + """ + # Throws if `_operator` is the `msg.sender` + assert _operator != msg.sender + self.ownerToOperators[msg.sender][_operator] = _approved + log ApprovalForAll(msg.sender, _operator, _approved) +``` + +#### Mint New Tokens and Destroy Existing Ones + +The account that created the contract is the `minter`, the super user that is authorized to mint +new NFTs. However, even it is not allowed to burn existing tokens. Only the owner, or an entity +authorized by the owner, can do that. + +```python +### MINT & BURN FUNCTIONS ### + +@external +def mint(_to: address, _tokenId: uint256) -> bool: +``` + +This function always returns `True`, because if the operation fails it is reverted. + +```python + """ + @dev Function to mint tokens + Throws if `msg.sender` is not the minter. + Throws if `_to` is zero address. + Throws if `_tokenId` is owned by someone. + @param _to The address that will receive the minted tokens. + @param _tokenId The token id to mint. + @return A boolean that indicates if the operation was successful. + """ + # Throws if `msg.sender` is not the minter + assert msg.sender == self.minter +``` + +Only the minter (the account that created the ERC-721 contract) can mint new tokens. This can be a +problem in the future if we want to change the minter's identity. In +a production contract you would probably want a function that allows the minter to transfer +minter privileges to somebody else. + +```python + # Throws if `_to` is zero address + assert _to != ZERO_ADDRESS + # Add NFT. Throws if `_tokenId` is owned by someone + self._addTokenTo(_to, _tokenId) + log Transfer(ZERO_ADDRESS, _to, _tokenId) + return True +``` + +By convention, the minting of new tokens counts as a transfer from address zero. + +```python + +@external +def burn(_tokenId: uint256): + """ + @dev Burns a specific ERC721 token. + Throws unless `msg.sender` is the current owner, an authorized operator, or the approved + address for this NFT. + Throws if `_tokenId` is not a valid NFT. + @param _tokenId uint256 id of the ERC721 token to be burned. + """ + # Check requirements + assert self._isApprovedOrOwner(msg.sender, _tokenId) + owner: address = self.idToOwner[_tokenId] + # Throws if `_tokenId` is not a valid NFT + assert owner != ZERO_ADDRESS + self._clearApproval(owner, _tokenId) + self._removeTokenFrom(owner, _tokenId) + log Transfer(owner, ZERO_ADDRESS, _tokenId) +``` + +Anybody who is allowed to transfer a token is allowed to burn it. While a burn appears equivalent to +transfer to the zero address, the zero address does not actually receives the token. This allows us to +free up all the storage that was used for the token, which can reduce the gas cost of the transaction. + +## Using this Contract + +In contrast to Solidity, Vyper does not have inheritance. This is a deliberate design choice to make the +code clearer and therefore easier to secure. So to create your own Vyper ERC-721 contract you take [this +contract](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy) and modify it +to implement the business logic you want. + +## Conclusion + +For review, here are some of the most important ideas in this contract: + +- To receive ERC-721 tokens with a safe transfer, contracts have to implement the `ERC721Receiver` interface. +- Even if you use safe transfer, tokens can still get stuck if you send them to an address whose private key + is unknown. +- When there is a problem with an operation it is a good idea to `revert` the call, rather than just return + a failure value. +- ERC-721 tokens exist when they have an owner. +- There are three ways to be authorized to transfer an NFT. You can be the owner, be approved for a specific token, + or be an operator for all of the owner's tokens. +- Past events are visible only outside the blockchain. Code running inside the blockchain cannot view them. + +Now go and implement secure Vyper contracts. + +--- + +## Developers > Tutorials > Erc20 Annotated Code + +## Introduction + +One of the most common uses for Ethereum is for a group to create a tradable token, in a sense their own currency. These tokens typically follow a standard, +[ERC-20](/developers/docs/standards/tokens/erc-20/). This standard makes it possible to write tools, such as liquidity pools and wallets, that work with all ERC-20 +tokens. In this article we will analyze the +[OpenZeppelin Solidity ERC20 implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol), as well as the +[interface definition](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol). + +This is annotated source code. If you want to implement ERC-20, +[read this tutorial](https://docs.openzeppelin.com/contracts/2.x/erc20-supply). + +## The Interface + +The purpose of a standard like ERC-20 is to allow many tokens implementations that are interoperable across applications, like wallets and decentralized exchanges. To achieve that, we create an +[interface](https://www.geeksforgeeks.org/solidity-basics-of-interface/). Any code that needs to use the token contract +can use the same definitions in the interface and be compatible with all token contracts that use it, whether it is a wallet such as +MetaMask, a dapp such as etherscan.io, or a different contract such as liquidity pool. + +![Illustration of the ERC-20 interface](erc20_interface.png) + +If you are an experienced programmer, you probably remember seeing similar constructs in [Java](https://www.w3schools.com/java/java_interface.asp) +or even in [C header files](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html). + +This is a definition of the [ERC-20 Interface](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) +from OpenZeppelin. It is a translation of the [human readable standard](https://eips.ethereum.org/EIPS/eip-20) into Solidity code. Of course, the +interface itself does not define _how_ to do anything. That is explained in the contract source code below. + +  + +```solidity +// SPDX-License-Identifier: MIT +``` + +Solidity files are supposed to includes a license identifier. [You can see the list of licenses here](https://spdx.org/licenses/). If you need a different +license, just explain it in the comments. + +  + +```solidity +pragma solidity >=0.6.0 =0.6.0 `. + +The first two variables are [mappings](https://www.tutorialspoint.com/solidity/solidity_mappings.htm), +meaning they behave roughly the same as [associative arrays](https://wikipedia.org/wiki/Associative_array), +except that the keys are numeric values. Storage is only allocated for entries that have values different +from the default (zero). + +```solidity + mapping (address => uint256) private _balances; +``` + +The first mapping, `_balances`, is addresses and their respective balances of this token. To access +the balance, use this syntax: `_balances[]`. + +  + +```solidity + mapping (address => mapping (address => uint256)) private _allowances; +``` + +This variable, `_allowances`, stores the allowances explained earlier. The first index is the owner +of the tokens, and the second is the contract with the allowance. To access the amount address A can +spend from address B's account, use `_allowances[B][A]`. + +  + +```solidity + uint256 private _totalSupply; +``` + +As the name suggests, this variable keeps track of the total supply of tokens. + +  + +```solidity + string private _name; + string private _symbol; + uint8 private _decimals; +``` + +These three variables are used to improve readability. The first two are self-explanatory, but `_decimals` +isn't. + +On one hand, ethereum does not have floating point or fractional variables. On the other hand, +humans like being able to divide tokens. One reason people settled on gold for currency was that +it was hard to make change when somebody wanted to buy a duck's worth of cow. + +The solution is to keep track of integers, but count instead of the real token a fractional token that is +nearly worthless. In the case of ether, the fractional token is called wei, and 10^18 wei is equal to one +ETH. At writing, 10,000,000,000,000 wei is approximately one US or Euro cent. + +Applications need to know how to display the token balance. If a user has 3,141,000,000,000,000,000 wei, is that +3.14 ETH? 31.41 ETH? 3,141 ETH? In the case of ether it is defined 10^18 wei to the ETH, but for your +token you can select a different value. If dividing the token doesn't make sense, you can use a +`_decimals` value of zero. If you want to use the same standard as ETH, use the value **18**. + +### The Constructor + +```solidity + /** + * @dev Sets the values for and , initializes with + * a default value of 18. + * + * To select a different value for , use . + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + constructor (string memory name_, string memory symbol_) public +``` + +The constructor is called when the contract is first created. By convention, function parameters are named `_`. + +### User Interface Functions + +```solidity + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * ether and wei. This is the value uses, unless is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * and . + */ + function decimals() public view returns (uint8) +``` + +These functions, `name`, `symbol`, and `decimals` help user interfaces know about your contract so they'll be able to display it properly. + +The return type is `string memory`, meaning return a string that is stored in memory. Variables, such as +strings, can be stored in three locations: + +| | Lifetime | Contract Access | Gas Cost | +| -------- | ------------- | --------------- | -------------------------------------------------------------- | +| Memory | Function call | Read/Write | Tens or hundreds (higher for higher locations) | +| Calldata | Function call | Read Only | Can't be used as a return type, only a function parameter type | +| Storage | Until changed | Read/Write | High (800 for read, 20k for write) | + +In this case, `memory` is the best choice. + +### Read Token Information + +These are functions that provide information about the token, either the total supply or an +account's balance. + +```solidity + /** + * @dev See . + */ + function totalSupply() public view override returns (uint256) +``` + +The `totalSupply` function returns the total supply of tokens. + +  + +```solidity + /** + * @dev See . + */ + function balanceOf(address account) public view override returns (uint256) +``` + +Read an account's balance. Note that anybody is allowed to get anybody else's account +balance. There is no point in trying to hide this information, because it is available on every +node anyway. _There are no secrets on the blockchain._ + +### Transfer Tokens + +```solidity + /** + * @dev See . + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) +``` + +The `_transfer` function does the actual work. It is a private function that can only be called by +other contract functions. By convention private functions are named `_`, same as state +variables. + +Normally in Solidity we use `msg.sender` for the message sender. However, that breaks +[OpenGSN](http://opengsn.org/). If we want to allow etherless transactions with our token, we +need to use `_msgSender()`. It returns `msg.sender` for normal transactions, but for etherless ones +return the original signer and not the contract that relayed the message. + +### Allowance Functions + +These are the functions that implement the allowance functionality: `allowance`, `approve`, `transferFrom`, +and `_approve`. Additionally, the OpenZeppelin implementation goes beyond the basic standard to include some features that improve +security: `increaseAllowance`, and `decreaseAllowance`. + +#### The allowance function + +```solidity + /** + * @dev See . + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) +``` + +The `allowance` function allows everybody to check any allowance. + +#### The approve function + +```solidity + /** + * @dev See . + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) +``` + +We use internal functions to minimize the number of places where state changes happen. _Any_ function that changes the +state is a potential security risk that needs to be audited for security. This way we have less chances to get it wrong. + +#### The transferFrom function + +This is the function that a spender calls to spend an allowance. This requires two operations: transfer the amount +being spent and reduce the allowance by that amount. + +```solidity + /** + * @dev See . + * + * Emits an event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of . + * + * Requirements: + * + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom(address sender, address recipient, uint256 amount) public virtual + override returns (bool) +``` + +#### OpenZeppelin safety additions + +It is dangerous to set a non-zero allowance to another non-zero value, +because you only control the order of your own transactions, not anybody else's. Imagine you +have two users, Alice who is naive and Bill who is dishonest. Alice wants some service from +Bill, which she thinks costs five tokens - so she gives Bill an allowance of five tokens. + +Then something changes and Bill's price rises to ten tokens. Alice, who still wants the service, +sends a transaction that sets Bill's allowance to ten. The moment Bill sees this new transaction +in the transaction pool he sends a transaction that spends Alice's five tokens and has a much +higher gas price so it will be mined faster. That way Bill can spend first five tokens and then, +once Alice's new allowance is mined, spend ten more for a total price of fifteen tokens, more than +Alice meant to authorize. This technique is called +[front-running](https://consensys.github.io/smart-contract-best-practices/attacks/#front-running) + +| Alice Transaction | Alice Nonce | Bill Transaction | Bill Nonce | Bill's Allowance | Bill Total Income from Alice | +| ----------------- | ----------- | ----------------------------- | ---------- | ---------------- | ---------------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| approve(Bill, 10) | 11 | | | 10 | 5 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 | + +To avoid this problem, these two functions (`increaseAllowance` and `decreaseAllowance`) allow you +to modify the allowance by a specific amount. So if Bill had already spent five tokens, he'll just +be able to spend five more. Depending on the timing, there are two ways this can work, both of +which end with Bill only getting ten tokens: + +A: + +| Alice Transaction | Alice Nonce | Bill Transaction | Bill Nonce | Bill's Allowance | Bill Total Income from Alice | +| -------------------------- | ----------: | ---------------------------- | ---------: | ---------------: | ---------------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| increaseAllowance(Bill, 5) | 11 | | | 0+5 = 5 | 5 | +| | | transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 | + +B: + +| Alice Transaction | Alice Nonce | Bill Transaction | Bill Nonce | Bill's Allowance | Bill Total Income from Alice | +| -------------------------- | ----------: | ----------------------------- | ---------: | ---------------: | ---------------------------: | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| increaseAllowance(Bill, 5) | 11 | | | 5+5 = 10 | 0 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 | + +```solidity + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to that can be used as a mitigation for + * problems described in . + * + * Emits an event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) +``` + +The `a.add(b)` function is a safe add. In the unlikely case that `a`+`b`>=`2^256` it does not wrap around +the way normal addition does. + +```solidity + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to that can be used as a mitigation for + * problems described in . + * + * Emits an event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) +``` + +### Functions that Modify Token Information + +These are the four functions that do the actual work: `_transfer`, `_mint`, `_burn`, and `_approve`. + +#### The _transfer function + +```solidity + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to , and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer(address sender, address recipient, uint256 amount) internal virtual +``` + +Finally, emit a `Transfer` event. Events are not accessible to smart contracts, but code running outside the blockchain +can listen for events and react to them. For example, a wallet can keep track of when the owner gets more tokens. + +#### The _mint and _burn functions + +These two functions (`_mint` and `_burn`) modify the total supply of tokens. +They are internal and there is no function that calls them in this contract, +so they are only useful if you inherit from the contract and add your own +logic to decide under what conditions to mint new tokens or burn existing +ones. + +**NOTE:** Every ERC-20 token has its own business logic that dictates token management. +For example, a fixed supply contract might only call `_mint` +in the constructor and never call `_burn`. A contract that sells tokens +will call `_mint` when it is paid, and presumably call `_burn` at some point +to avoid runaway inflation. + +```solidity + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a event with `from` set to the zero address. + * + * Requirements: + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual +``` + +Make sure to update `_totalSupply` when the total number of tokens changes. + +  + +```solidity + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual +``` + +The `_burn` function is almost identical to `_mint`, except it goes in the other direction. + +#### The _approve function + +This is the function that actually specifies allowances. Note that it allows an owner to specify +an allowance that is higher than the owner's current balance. This is OK because the balance is +checked at the time of transfer, when it could be different from the balance when the allowance is +created. + +```solidity + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual + +``` + +### Modify The Decimals Variable + +```solidity + + + /** + * @dev Sets to a value other than the default one of 18. + * + * WARNING: This function should only be called from the constructor. Most + * applications that interact with token contracts will not expect + * to ever change, and may work incorrectly if it does. + */ + function _setupDecimals(uint8 decimals_) internal +``` + +This function modifies the `_decimals` variable which is used to tell user interfaces how to interpret the amount. +You should call it from the constructor. It would be dishonest to call it at any subsequent point, and applications +are not designed to handle it. + +### Hooks + +```solidity + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual +} +``` + +This is the hook function to be called during transfers. It is empty here, but if you need +it to do something you just override it. + +## Conclusion + +For review, here are some of the most important ideas in this contract (in my opinion, yours is likely to vary): + +- _There are no secrets on the blockchain_. Any information that a smart contract can access + is available to the whole world. +- You can control the order of your own transactions, but not when other people's transaction + happen. This is the reason that changing an allowance can be dangerous, because it lets + the spender spend the sum of both allowances. +- Values of type `uint256` wrap around. In other words, _0-1=2^256-1_. If that is not desired + behavior, you have to check for it (or use the SafeMath library that does it for you). Note that this changed in + [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html). +- Do all state changes of a specific type in a specific place, because it makes auditing easier. + This is the reason that we have, for example, `_approve`, which is called by `approve`, `transferFrom`, + `increaseAllowance`, and `decreaseAllowance` +- State changes should be atomic, without any other action in their middle (as you can see + in `_transfer`). This is because during the state change you have an inconsistent state. For example, + between the time you deduct from the balance of the sender and the time you add to the balance of the + recipient there are less token in existence than there should be. This could be potentially abused if there + are operations between them, especially calls to a different contract. + +Now that you've seen how the OpenZeppelin ERC-20 contract is written, and especially how it is +made more secure, go and write your own secure contracts and applications. + +--- + +## Developers > Tutorials > Erc20 With Safety Rails + +## Introduction + +One of the great things about Ethereum is that there is no central authority that can modify or undo your transactions. One of the great problems with Ethereum is that there is no central authority with the power to undo user mistakes or illicit transactions. In this article you learn about some of the common mistakes that users commit with [ERC-20](/developers/docs/standards/tokens/erc-20/) tokens, as well as how to create ERC-20 contracts that help users to avoid those mistakes, or that give a central authority some power (for example to freeze accounts). + +Note that while we will use the [OpenZeppelin ERC-20 token contract](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20), this article does not explain it in great details. You can find this information [here](/developers/tutorials/erc20-annotated-code). + +If you want to see the complete source code: + +1. Open the [Remix IDE](https://remix.ethereum.org/). +2. Click the clone github icon (![clone github icon](icon-clone.png)). +3. Clone the github repository `https://github.com/qbzzt/20220815-erc20-safety-rails`. +4. Open **contracts > erc20-safety-rails.sol**. + +## Creating an ERC-20 contract + +Before we can add the safety rail functionality we need an ERC-20 contract. In this article we'll use [the OpenZeppelin Contracts Wizard](https://docs.openzeppelin.com/contracts/5.x/wizard). Open it in another browser and follow these instructions: + +1. Select **ERC20**. +2. Enter these settings: + + | Parameter | Value | + | -------------- | ---------------- | + | Name | SafetyRailsToken | + | Symbol | SAFE | + | Premint | 1000 | + | Features | None | + | Access Control | Ownable | + | Upgradability | None | + +3. Scroll up and click **Open in Remix** (for Remix) or **Download** to use a different environment. I'm going to assume you're using Remix, if you use something else just make the appropriate changes. +4. We now have a fully functional ERC-20 contract. You can expand `.deps` > `npm` to see the imported code. +5. Compile, deploy, and play with the contract to see that it functions as an ERC-20 contract. If you need to learn how to use Remix, [use this tutorial](https://remix.ethereum.org/?#activate=udapp,solidity,LearnEth). + +## Common mistakes + +### The mistakes + +Users sometimes send tokens to the wrong address. While we cannot read their minds to know what they meant to do, there are two error types that happen a lot and are easy to detect: + +1. Sending the tokens to the contract's own address. For example, [Optimism's OP token](https://optimism.mirror.xyz/qvd0WfuLKnePm1Gxb9dpGchPf5uDz5NSMEFdgirDS4c) managed to accumulate [over 120,000](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000042#tokentxns) OP tokens in less than two months. This represents a significant amount of wealth that presumably people just lost. + +2. Sending the tokens to an empty address, one that doesn't correspond to an [externally owned account](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs) or a [smart contract](/developers/docs/smart-contracts). While I don't have statistics on how often this happens, [one incident could have cost 20,000,000 tokens](https://gov.optimism.io/t/message-to-optimism-community-from-wintermute/2595). + +### Preventing transfers + +The OpenZeppelin ERC-20 contract includes [a hook, `_beforeTokenTransfer`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L364-L368), that is called before a token is transferred. By default this hook does not do anything, but we can hang our own functionality on it, such as checks that revert if there's a problem. + +To use the hook, add this function after the constructor: + +```solidity + function _beforeTokenTransfer(address from, address to, uint256 amount) + internal virtual + override(ERC20) + +``` + +Some parts of this function may be new if you aren't very familiar with Solidity: + +```solidity + internal virtual +``` + +The `virtual` keyword means that just as we inherited functionality from `ERC20` and overrode this function, other contracts can inherit from us and override this function. + +```solidity + override(ERC20) +``` + +We have to specify explicitly that we're [overriding](https://docs.soliditylang.org/en/v0.8.15/contracts.html#function-overriding) the ERC20 token definition of `_beforeTokenTransfer`. In general, explicit definitions are a lot better, from the security standpoint, than implicit ones - you cannot forget that you've done something if it's right in front of you. That is also the reason we need to specify which superclass's `_beforeTokenTransfer` we are overriding. + +```solidity + super._beforeTokenTransfer(from, to, amount); +``` + +This line calls the `_beforeTokenTransfer` function of the contract or contracts from which we inherited which have it. In this case, that is only `ERC20`, `Ownable` does not have this hook. Even though currently `ERC20._beforeTokenTransfer` doesn't do anything, we call it in case functionality is added in the future (and we then decide to redeploy the contract, because contracts don't change after deployment). + +### Coding the requirements + +We want to add these requirements to the function: + +- The `to` address cannot equal `address(this)`, the address of the ERC-20 contract itself. +- The `to` address cannot be empty, it has to be either: + - An externally owned account (EOA). We can't check if an address is an EOA directly, but we can check an address's ETH balance. EOAs almost always have a balance, even if they are no longer used - it's difficult to clear them to the last wei. + - A smart contract. Testing if an address is a smart contract is a bit harder. There is an opcode that checks the external code length, called [`EXTCODESIZE`](https://www.evm.codes/#3b), but it is not available directly in Solidity. We have to use [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html), which is EVM assembly, for it. There are other values we could use from Solidity ([`.code` and `.codehash`](https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#members-of-address-types)), but they cost more. + +Lets go over the new code line by line: + +```solidity + require(to != address(this), "Can't send tokens to the contract address"); +``` + +This is the first requirement, check that `to` and `this(address)` are not the same thing. + +```solidity + bool isToContract; + assembly +``` + +This is how we check if an address is a contract. We cannot receive output directly from Yul, so instead we define a variable to hold the result (`isToContract` in this case). The way Yul works is that every opcode is considered a function. So first we call [`EXTCODESIZE`](https://www.evm.codes/#3b) to get the contract size, and then use [`GT`](https://www.evm.codes/#11) to check it is not zero (we are dealing with unsigned integers, so of course it can't be negative). We then write the result to `isToContract`. + +```solidity + require(to.balance != 0 || isToContract, "Can't send tokens to an empty address"); +``` + +And finally, we have the actual check for empty addresses. + +## Administrative access + +Sometimes it is useful to have an administrator that can undo mistakes. To reduce the potential for abuse, this administrator can be a [multisig](https://blog.logrocket.com/security-choices-multi-signature-wallets/) so multiple people have to agree on an action. In this article we'll have two administrative features: + +1. Freezing and unfreezing accounts. This can be useful, for example, when an account might be compromised. +2. Asset cleanup. + + Sometimes frauds send fraudulent tokens to the real token's contract to gain legitimacy. For example, [see here](https://optimistic.etherscan.io/token/0x2348b1a1228ddcd2db668c3d30207c3e1852fbbe?a=0x4200000000000000000000000000000000000042). The legitimate ERC-20 contract is [0x4200....0042](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000042). The scam that pretends to be it is [0x234....bbe](https://optimistic.etherscan.io/address/0x2348b1a1228ddcd2db668c3d30207c3e1852fbbe). + + It is also possible that people send legitimate ERC-20 tokens to our contract by mistake, which is another reason to want to have a way to get them out. + +OpenZeppelin provides two mechanisms to enable administrative access: + +- [`Ownable`](https://docs.openzeppelin.com/contracts/4.x/access-control#ownership-and-ownable) contracts have a single owner. Functions that have the `onlyOwner` [modifier](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm) can only be called by that owner. Owners can transfer ownership to somebody else or renounce it completely. The rights of all other accounts are typically identical. +- [`AccessControl`](https://docs.openzeppelin.com/contracts/4.x/access-control#role-based-access-control) contracts have [role based access control (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control). + +For the sake of simplicity, in this article we use `Ownable`. + +### Freezing and thawing contracts + +Freezing and thawing contracts requires several changes: + +- A [mapping](https://www.tutorialspoint.com/solidity/solidity_mappings.htm) from addresses to [booleans](https://en.wikipedia.org/wiki/Boolean_data_type) to keep track of which addresses are frozen. All values are initially zero, which for boolean values is interpreted as false. This is what we want because by default accounts are not frozen. + + ```solidity + mapping(address => bool) public frozenAccounts; + ``` + +- [Events](https://www.tutorialspoint.com/solidity/solidity_events.htm) to inform anybody interested when an account is frozen or thawed. Technically speaking events are not required for these actions, but it helps offchain code to be able to listen to these events and know what is happening. It's considered good manners for a smart contract to emit them when something that might be relevant to somebody else happens. + + The events are indexed so will be possible to search for all the times an account has been frozen or thawed. + + ```solidity + // When accounts are frozen or unfrozen + event AccountFrozen(address indexed _addr); + event AccountThawed(address indexed _addr); + ``` + +- Functions for freezing and thawing accounts. These two functions are nearly identical, so we'll only go over the freeze function. + + ```solidity + function freezeAccount(address addr) + public + onlyOwner + ``` + + Functions marked [`public`](https://www.tutorialspoint.com/solidity/solidity_contracts.htm) can be called from other smart contracts or directly by a transaction. + + ```solidity + // freezeAccount + ``` + + If the account is already frozen, revert. Otherwise, freeze it and `emit` an event. + +- Change `_beforeTokenTransfer` to prevent money being moved from a frozen account. Note that money can still be transferred into the frozen account. + + ```solidity + require(!frozenAccounts[from], "The account is frozen"); + ``` + +### Asset cleanup + +To release ERC-20 tokens held by this contract we need to call a function on the token contract to which they belong, either [`transfer`](https://eips.ethereum.org/EIPS/eip-20#transfer) or [`approve`](https://eips.ethereum.org/EIPS/eip-20#approve). There's no point wasting gas in this case on allowances, we might as well transfer directly. + +```solidity + function cleanupERC20( + address erc20, + address dest + ) + public + onlyOwner + +``` + +This is a cleanup function, so presumably we don't want to leave any tokens. Instead of getting the balance from the user manually, we might as well automate the process. + +## Conclusion + +This is not a perfect solution - there is no perfect solution for the "user made a mistake" problem. However, using these kinds of checks can at least prevent some mistakes. The ability to freeze accounts, while dangerous, can be used to limit the damage of certain hacks by denying the hacker the stolen funds. + +--- + +## Developers > Tutorials > Ethereum For Web2 Auth + +## Introduction + +[SAML](https://www.onelogin.com/learn/saml) is a standard used on web2 to allow an [identity provider (IdP)](https://en.wikipedia.org/wiki/Identity_provider#SAML_identity_provider) to provide user information for [service providers (SP)](https://en.wikipedia.org/wiki/Service_provider_(SAML)). + +In this tutorial you learn how to integrate Ethereum signatures with SAML to allow users to use their Ethereum wallets to authenticate themselves to web2 services that don't support Ethereum natively yet. + +Note that this tutorial is written for two separate audiences: + +- Ethereum people who understand Ethereum and need to learn SAML +- Web2 people who understand SAML and web2 authentication and need to learn Ethereum + +As a result, it is going to contain a lot of introductory material that you already know. Feel free to skip it. + +### SAML for Ethereum people + +SAML is a centralized protocol. A service provider (SP) only accepts assertions (such as "this is my user John, he should have permissions to do A, B, and C") from an identity provider (IdP) if it has a pre-existing trust relationship either with it, or with the [certificate authority](https://www.ssl.com/article/what-is-a-certificate-authority-ca/) that signed that IdP's certificate. + +For example, the SP can be a travel agency providing travel services to companies, and the IdP can be a company's internal web site. When employees need to book business travel, the travel agency sends them for authentication by the company before letting them actually book travel. + +![Step by step SAML process](./fig-01-saml.png) + +This is the way the three entities, the browser, SP, and IdP, negotiate for access. The SP does not need to know anything about the user using the browser in advance, just to trust the IdP. + +### Ethereum for SAML people + +Ethereum is a decentralized system. + +![Ethereum logon](./fig-02-eth-logon.png) + +Users have a a private key (typically held in a browser extension). From the private key you can derive a public key, and from that a 20-byte address. When users need to log into a system, they are requested to sign a message with a nonce (a single-use value). The server can verify the signature was created by that address. + +![Getting extra data from attestations](./fig-03-eas-data.png) + +The signature only verifies the Ethereum address. To get other user attributes, you typically use [attestations](https://attest.org/). An attestation typically has these fields: + +- **Attestor**, the address that made the attestation +- **Recipient**, the address to which the attestation applies +- **Data**, the data being attested, such as name, permissions, etc. +- **Schema**, the ID of the schema used to interpret the data. + +Because of the decentralized nature of Ethereum, any user can make attestations. The attestor's identity is important to identify which attestations we consider reliable. + +## Setup + +The first step is to have a SAML SP and a SAML IdP communicating between themselves. + +1. Download the software. The sample software for this article is [on github](https://github.com/qbzzt/250420-saml-ethereum). Different stages are stored in different branches, for this stage you want `saml-only` + + ```sh + git clone https://github.com/qbzzt/250420-saml-ethereum -b saml-only + cd 250420-saml-ethereum + pnpm install + ``` + +2. Create keys with self-signed certificates. This means that the key is its own certificate authority, and needs to be imported manually to the service provider. See [the OpenSSL docs](https://docs.openssl.org/master/man1/openssl-req/) for more information. + + ```sh + mkdir keys + cd keys + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-sp.crt -keyout saml-sp.pem -subj /CN=sp/ + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-idp.crt -keyout saml-idp.pem -subj /CN=idp/ + cd .. + ``` + +3. Start the servers (both SP and IdP) + + ```sh + pnpm start + ``` + +4. Browse to the SP at URL [http://localhost:3000/](http://localhost:3000/) and click the button to be redirected to the IdP (port 3001). + +5. Provide the IdP with your email address and click **Login to the service provider**. See that you get redirected back to the service provider (port 3000) and that it knows you by your email address. + +### Detailed explanation + +This is what happens, step by step: + +![Normal SAML logon without Ethereum](./fig-04-saml-no-eth.png) + +#### src/config.mts + +This file contains the configuration for both the Identity Provider and the Service Provider. Normally these two would be different entities, but here we can share code for simplicity. + +```typescript +const fs = await import("fs") + +const protocol="http" +``` + +For now we're just testing, so it's fine to use HTTP. + +```typescript +export const spCert = fs.readFileSync("keys/saml-sp.crt").toString() +export const idpCert = fs.readFileSync("keys/saml-idp.crt").toString() +``` + +Read the public keys, which are normally available to both components (and either trusted directly, or signed by a trusted certificate authority). + +```typescript +export const spPort = 3000 +export const spHostname = "localhost" +export const spDir = "sp" + +export const idpPort = 3001 +export const idpHostname = "localhost" +export const idpDir = "idp" + +export const spUrl = `$://$:$/$` +export const idpUrl = `$://$:$/$` +``` + +The URLs for both components. + +```typescript +export const spPublicData = /metadata`, +``` + +By convention, in SAML the `entityID` is the URL where the metadata of the entity is available. This metadata corresponds to the public data here, except it is in XML form. + +```typescript + wantAssertionsSigned: true, + authnRequestsSigned: false, + signingCert: spCert, + allowCreate: true, + assertionConsumerService: [/assertion`, + }] + } +``` + +The most important definition for our purposes is the `assertionConsumerServer`. It means that to assert something (for example, "the user who sends you this information is somebody@example.com") to the service provider we need to use [HTTP POST](https://www.w3schools.com/tags/ref_httpmethods.asp) to URL `http://localhost:3000/sp/assertion`. + +```typescript +export const idpPublicData = /metadata`, + signingCert: idpCert, + wantAuthnRequestsSigned: false, + singleSignOnService: [/login` + }], + singleLogoutService: [/logout` + }], + } +``` + +The public data for the identity provider is similar. It specifies that to log a user in you POST to `http://localhost:3001/idp/login` and to log a user out you POST to `http://localhost:3001/idp/logout`. + +#### src/sp.mts + +This is the code that implements a service provider. + +```typescript +const fs = await import("fs") +const saml = await import("samlify") +``` + +We use the [`samlify`](https://www.npmjs.com/package/samlify) library to implement SAML. + +```typescript +saml.setSchemaValidator(validator) +``` + +The `samlify` library expects to have a package validate that XML is correct, signed with the expected public key, etc. We use [`@authenio/samlify-node-xmllint`](https://www.npmjs.com/package/@authenio/samlify-node-xmllint) for this purpose. + +```typescript +const express = (await import("express")).default +const spRouter = express.Router() +const app = express() +``` + +An [`express`](https://expressjs.com/) [`Router`](https://expressjs.com/en/5x/api.html#router) is a "mini web site" that can be mounted inside a web site. In this case, we use it to group all the service provider definitions together. + +```typescript +const spPrivateKey = fs.readFileSync("keys/saml-sp.pem").toString() + +const sp = saml.ServiceProvider() +``` + +The service provider's own representation of itself is all the public data, and the private key it uses to sign information. + +```typescript +const idp = saml.IdentityProvider(config.idpPublicData); +``` + +The public data contains everything the service provider needs to know about the identity provider. + +```typescript +spRouter.get(`/metadata`, + (req, res) => res.header("Content-Type", "text/xml").send(sp.getMetadata()) +) +``` + +To enable interoperability with other SAML components, service and identity providers should have their public data (called the metadata) available in XML format in `/metadata`. + +```typescript +spRouter.post(`/assertion`, +``` + +This is the page accessed by the browser to identify itself. The assertion includes the user identifier (here we use email address), and can include additional attributes. This is the handler for step 7 in the sequence diagram above. + +```typescript + async (req, res) => `) +``` + +You can use the commented out command to see the XML data provided in the assertion. It is [base64 encoded](https://en.wikipedia.org/wiki/Base64). + +```typescript + try + + + `) + res.send(); +``` + +Send an HTML response, just to show the user we got the login. + +```typescript + } catch (err) + } +) +``` + +Inform the user in case of failure. + +```typescript +spRouter.get('/login', +``` + +Create a login request when the browser attempts to get this page. This is the handler for step 1 in the sequence diagram above. + +```typescript + async (req, res) => + +``` + +This page submits the form (see below) automatically. This way the user does not have to do anything to be redirected. This is step 2 in the sequence diagram above. + +```typescript + +``` + +Post to `loginRequest.entityEndpoint` (the URL of the identity provider endpoint). + +```typescript + +``` + +The input name is `loginRequest.type` (`SAMLRequest`). The content for that field is `loginRequest.context`, which is again XML that is base64 encoded. + +```typescript + + + + `) + } +) + +app.use(express.urlencoded()) +``` + +[This middleware](https://expressjs.com/en/5x/api.html#express.urlencoded) reads the body of the [HTTP request](https://www.tutorialspoint.com/http/http_requests.htm). By default express ignores it, because most requests don't require it. We need it because POST does use the body. + +```typescript +app.use(`/$`, spRouter) +``` + +Mount the router in the service provider directory (`/sp`). + +```typescript +app.get("/", (req, res) => ) +``` + +If a browser tries to get the root directory, provide it with a link to the login page. + +```typescript +app.listen(config.spPort, () => :$`) +}) +``` + +Listen to the `spPort` with this express application. + +#### src/idp.mts + +This is the identity provider. It is very similar to the service provider, the explanations below are for the parts that are different. + +```typescript +const xmlParser = new (await import("fast-xml-parser")).XMLParser( + +) +``` + +We need to read and understand the XML request we receive from the service provider. + +```typescript +const getLoginPage = requestId => ` +``` + +This function creates the page with the auto-submitted form that is returned in step 4 of the sequence diagram above. + +```typescript + + + Login page + + + Login page + + + Email address: + + + Login to the service provider + +``` + +There are two fields we send to the service provider: + +1. The `requestId` to which we are responding. +2. The user identifier (we use the email address the user provides for now). + +```typescript + + + + +const idpRouter = express.Router() + +idpRouter.post("/loginSubmitted", async (req, res) => + }, +``` + +Information extracted from the request. The one parameter we care about in the request is the requestId, which lets the service provider match requests and their responses. + +```typescript + signingKey: // Ensure signing +``` + +We need `signingKey` to have the data to sign the response. The service provider doesn't trust unsigned requests. + +```typescript + }, + "post", + + ); + + res.send(` + + + + window.onload = function () + + + + + + + + `) +}) +``` + +Again, use an auto-submitted form. This is step 6 of the sequence diagram above. + +```typescript + +// IdP endpoint for login requests +idpRouter.post(`/login`, +``` + +This is the endpoint that receives a login request from the service provider. This is the handler the step 3 of the sequence diagram above. + +```typescript + async (req, res) => +``` + +We need the request information to be able to respond to it. We could send it with the request (step 4), and receive it back (step 5). However, we cannot trust the information we get from the browser, which is under the control of a potentially hostile user. So it's better to store it here, with the nonce as key. + +Note that we are doing it here as a variable for the sake of simplicity. However, this has several disadvantages: + +- We are vulnerable to a denial of service attack. A malicious user could attempt to log on multiple times, filling up our memory. +- If the IdP process needs to be restarted, we lose the existing values. +- We cannot load balance across multiple processes, because each would have its own variable. + +On a production system we'd use a database and implement some kind of expiry mechanism. + +```typescript +const getSignaturePage = requestId => +``` + +We can only work if there is a wallet on the browser. + +```typescript + const [account] = await window.ethereum.request() +``` + +Request the list of accounts from the wallet (`window.ethereum`). Assume there is at least one, and only store the first one. + +```typescript + const walletClient = createWalletClient() +``` + +Create a [wallet client](https://viem.sh/docs/clients/wallet) to interact with the browser wallet. + +```typescript + window.goodSignature = () => $" +``` + +Ask the user to sign a message. Because this whole HTML is in a [template string](https://viem.sh/docs/clients/wallet), we can use variables defined in the idp process. This is step 4.5 in the sequence diagram. + +```typescript + }).then(signature => /signature/$/" + account + "/" + signature + window.location.href = path + }) + } +``` + +Redirect to `/idp/signature///`. This is step 5 in the sequence diagram. + +```typescript + window.badSignature = () => /signature/$/" + + getAddress("0x" + "BAD060A7".padEnd(40, "0")) + + "/0x" + "BAD0516".padStart(130, "0") + window.location.href = path + } +``` + +The signature is sent back by the browser, which is potentially malicious (there is nothing to stop you from just opening `http://localhost:3001/idp/signature/bad-nonce/bad-address/bad-signature` in the browser). Therefore, it is important to verify the IdP process handles bad signatures correctly. + +```typescript + + + + Please sign + + Submit a good (valid) signature + + + + Submit a bad (invalid) signature + + + +` +} +``` + +The rest is just standard HTML. + +```typescript +idpRouter.get("/signature/:nonce/:account/:signature", async (req, res) => + + nonces[req.params.nonce] = undefined +``` + +Get the request ID, and delete the nonce from `nonces` to make sure it cannot be reused. + +```typescript + try $`, + signature: req.params.signature + }) +``` + +Use [`verifyMessage`](https://viem.sh/docs/actions/public/verifyMessage#verifymessage) to implement step 5.5 in the sequence diagram. + +```typescript + if (!validSignature) + throw("Bad signature") + } catch (err) +``` + +The rest of the handler is equivalent to what we've done in the `/loginSubmitted` handler previously, except for one small change. + +```typescript + const loginResponse = await idp.createLoginResponse( + . + . + . + + ); +``` + +We don't have the actual email address (we will get it in the next section), so for now we return the Ethereum address and mark it clearly as not an email address. + + +```typescript +// IdP endpoint for login requests +idpRouter.post(`/login`, + async (req, res) => catch (err) + } +) +``` + +Instead of `getLoginPage`, now use `getSignaturePage` in the step 3 handler. + +## Getting the email address + +The next step is to obtain the email address, the identifier requested by the service provider. To do that, we use [Ethereum Attestation Service (EAS)](https://attest.org/). + +The easiest way to get attestations is to use the [GraphQL API](https://docs.attest.org/docs/developer-tools/api). We use this query: + +``` +query GetAttestationsByRecipient " } + schemaId: + } + take: 1 + ) +} +``` + +This [`schemaId`](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977) includes just an e-mail address. This query asks for attestations of this schema. The subject of the attestation is called the `recipient`. It is always an Ethereum address. + +Warning: The way we are getting attestations here has two security issues. + +- We are going to the API endpoint, `https://optimism.easscan.org/graphql`, which is a centralized component. We can get the `id` attribute and then do a lookup onchain to verify that an attestation is real, but the API endpoint can still censor attestations by not telling us about them. + + This problem is not impossible to solve, we could run our own GraphQL endpoint and get the attestations from the chain logs, but that is excessive for our purposes. + +- We don't look at the attester identity. Anybody can feed us false information. In a real world implementation we would have a set of trusted attesters and only look at their attestations. + +To see this in action, stop the existing IdP and SP and run these commands: + +```sh +git checkout email-address +pnpm install +pnpm start +``` + +Then provide your e-mail address. You have two ways to do that: + +- Import a wallet using a private key, and use the testing private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`. + +- Add an attestation for your own e-mail address: + + 1. Browse to [the schema in the attestation explorer](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977). + + 2. Click **Attest with Schema**. + + 3. Enter your Ethereum address as the recipient, your e-mail address as email address, and select **Onchain**. Then click **Make Attestation**. + + 4. Approve the transaction in your wallet. You will need some ETH on [the Optimism Blockchain](https://app.optimism.io/bridge/deposit) to pay for gas. + +Either way, after you do this browse to [http://localhost:3000](http://localhost:3000) and follow the directions. If you imported the testing private key, the e-mail you receive is `test_addr_0@example.com`. If you used your own address, it should be whatever you attested. + +### Detailed explanation + +![Getting from Ethereum address to e-mail](./fig-06-saml-sig-n-email.png) + +The new steps are the GraphQL communication, steps 5.6 and 5.7. + +Again, here are the changed parts of `idp.mts`. + +```typescript +``` + +Import the libraries we need. + +```typescript +const graphqlEndpointUrl = "https://optimism.easscan.org/graphql" +``` + +There is [a separate endpoint for each blockchain](https://docs.attest.org/docs/developer-tools/api). + +```typescript +const graphqlClient = new GraphQLClient(graphqlEndpointUrl, ) +``` + +Create a new `GraphQLClient` client we can use for querying the endpoint. + +```typescript +const graphqlSchema = 'string emailAddress' +const graphqlEncoder = new SchemaEncoder(graphqlSchema) +``` + +GraphQL only gives us an opaque data object with bytes. To understand it we need the schema. + +```typescript +const ethereumAddressToEmail = async ethAddr => " } + schemaId: + } +``` + +The attestations we want are those in our schema, where the recipient is `getAddress(ethAddr)`. The [`getAddress`](https://viem.sh/docs/utilities/getAddress#getaddress) function makes sure our address has the correct [checksum](https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md). This is necessary about GraphQL is case-significant. "0xBAD060A7", "0xBad060A7", and "0xbad060a7" are differemt values. + +```typescript + take: 1 +``` + +Regardless of how many attestations we find, we only want the first one. + +```typescript + ) + }` +``` + +The fields we want to receive. + +- `attester`: The address that submitted the attestation. Normally this is used to decide whether to trust the attestation or not. +- `id`: The attestation ID. You can use this value to [read the attestation onchain](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000021?tab=read_proxy&source_address=0x4E0275Ea5a89e7a3c1B58411379D1a0eDdc5b088#0xa3112a64) to verify that the information from the GraphQL query is correct. +- `data`: The schema data (in this case, the e-mail address). + +```typescript + const queryResult = await graphqlClient.request(query) + + if (queryResult.attestations.length == 0) + return "no_address@available.is" +``` + +If there is no attestation, return a value that is obviously incorrect, but that would appear valid to the service provider. + +```typescript + const attestationDataFields = graphqlEncoder.decodeData(queryResult.attestations[0].data) + return attestationDataFields[0].value.value +} +``` + +If there is a value, use `decodeData` to decode the data. We don't need the metadata it provides, just the value itself. + +```typescript + const loginResponse = await idp.createLoginResponse( + sp, + , + "post", + + ); +``` + +Use the new function to get the e-mail address. + +## What about decentralization? + +In this configuration users cannot pretend to be somebody they are not, as long as we rely on trustworthy attesters for the Ethereum to e-mail address mapping. However, our identity provider is still a centralized component. Whoever has the private key of the identity provider can send false information to the service provider. + +There may be a solution using [multi-party computation (MPC)](https://en.wikipedia.org/wiki/Secure_multi-party_computation). I hope to write about it in a future tutorial. + +## Conclusion + +Adoption of a log on standard, such as Ethereum signatures, faces a chicken and egg problem. Service providers want to appeal to the broadest possible market. Users want to be able to access services without having to worry about supporting their log on standard. +Creating adapters, such as an Ethereum IdP, can help us get over this hurdle. + +--- + +## Developers > Tutorials > Getting Started With Ethereum Development Using Alchemy + +![Ethereum and Alchemy logos](./ethereum-alchemy.png) + +This is a beginners guide to getting started with Ethereum development. For this tutorial we'll be using [Alchemy](https://alchemyapi.io/), the leading blockchain developer platform powering millions of users from 70% of the top blockchain apps, including Maker, 0x, MyEtherWallet, Dharma, and Kyber. Alchemy will give us access to an API endpoint on the Ethereum chain so we can read and write transactions. + +We’ll take you from signing up with Alchemy to writing your first web3 script! No blockchain development experience necessary! + +## 1. Sign Up for a Free Alchemy Account + +Creating an account with Alchemy is easy, [sign up for free here](https://auth.alchemyapi.io/signup). + +## 2. Create an Alchemy App + +To communicate with the Ethereum chain and to use Alchemy’s products, you need an API key to authenticate your requests. + +You can [create API keys from the dashboard](http://dashboard.alchemyapi.io/). To make a new key, navigate to “Create App” as shown below: + +Special thanks to [_ShapeShift_](https://shapeshift.com/) _for letting us show their dashboard!_ + +![Alchemy dashboard](./alchemy-dashboard.png) + +Fill in the details under “Create App” to get your new key. You can also see apps you previously made and those made by your team here. Pull existing keys by clicking on “View Key” for any app. + +![Create app with Alchemy screenshot](./create-app.png) + +You can also pull existing API keys by hovering over “Apps” and selecting one. You can “View Key” here, as well as “Edit App” to whitelist specific domains, see several developer tools, and view analytics. + +![Gif showing a user how to pull API keys](./pull-api-keys.gif) + +## 3. Make a Request from the Command Line + +Interact with the Ethereum blockchain through Alchemy using JSON-RPC and curl. + +For manual requests, we recommend interacting with the `JSON-RPC` via `POST` requests. Simply pass in the `Content-Type: application/json` header and your query as the `POST` body with the following fields: + +- `jsonrpc`: The JSON-RPC version—currently, only `2.0` is supported. +- `method`: The ETH API method. [See API reference.](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) +- `params`: A list of parameters to pass to the method. +- `id`: The ID of your request. Will be returned by the response so you can keep track of which request a response belongs to. + +Here is an example you can run from the command line to retrieve the current gas price: + +```bash +curl https://eth-mainnet.alchemyapi.io/v2/demo \ +-X POST \ +-H "Content-Type: application/json" \ +-d '' +``` + +_**NOTE:** Replace [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) with your own API key `https://eth-mainnet.alchemyapi.io/v2/**your-api-key`._ + +**Results:** + +```json + +``` + +## 4. Set up your Web3 Client + +**If you have an existing client,** change your current node provider URL to an Alchemy URL with your API key: `“https://eth-mainnet.alchemyapi.io/v2/your-api-key"` + +**_NOTE:_** The scripts below need to be run in a **node context** or **saved in a file**, not run from the command line. If you don’t already have Node or npm installed, check out this quick [set-up guide for macs](https://app.gitbook.com/@alchemyapi/s/alchemy/guides/alchemy-for-macs). + +There are tons of [Web3 libraries](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries) you can integrate with Alchemy, however, we recommend using [Alchemy Web3](https://docs.alchemy.com/reference/api-overview), a drop-in replacement for web3.js, built and configured to work seamlessly with Alchemy. This provides multiple advantages such as automatic retries and robust WebSocket support. + +To install AlchemyWeb3.js, **navigate to your project directory** and run: + +**With Yarn:** + +``` +yarn add @alch/alchemy-web3 +``` + +**With NPM:** + +``` +npm install @alch/alchemy-web3 +``` + +To interact with Alchemy’s node infrastructure, run in NodeJS or add this to a JavaScript file: + +```js +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3( + "https://eth-mainnet.alchemyapi.io/v2/your-api-key" +) +``` + +## 5. Write your first Web3 Script! + +Now to get our hands dirty with a little web3 programming we’ll write a simple script that prints out the latest block number from the Ethereum Mainnet. + +**1. If you haven’t already, in your terminal create a new project directory and cd into it:** + +``` +mkdir web3-example +cd web3-example +``` + +**2. Install the Alchemy web3 (or any web3) dependency into your project if you have not already:** + +``` +npm install @alch/alchemy-web3 +``` + +**3. Create a file named `index.js` and add the following contents:** + +> You should ultimately replace `demo` with your Alchemy HTTP API key. + +```js +async function main() = require("@alch/alchemy-web3") + const web3 = createAlchemyWeb3("https://eth-mainnet.alchemyapi.io/v2/demo") + const blockNumber = await web3.eth.getBlockNumber() + console.log("The latest block number is " + blockNumber) +} +main() +``` + +Unfamiliar with the async stuff? Check out this [Medium post](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c). + +**4. Run it in your terminal using node** + +``` +node index.js +``` + +**5. You should now see the latest block number output in your console!** + +``` +The latest block number is 11043912 +``` + +**Woo! Congrats! You just wrote your first web3 script using Alchemy 🎉** + +Not sure what to do next? Try deploying your first smart contract and get your hands dirty with some solidity programming in our [Hello World Smart Contract Guide](https://docs.alchemyapi.io/tutorials/hello-world-smart-contract), or test your dashboard knowledge with the [Dashboard Demo App](https://docs.alchemyapi.io/tutorials/demo-app)! + +_[Sign up with Alchemy for free](https://auth.alchemyapi.io/signup), check out our [documentation](https://docs.alchemyapi.io/), and for the latest news, follow us on [Twitter](https://twitter.com/AlchemyPlatform)_. + +--- + +## Developers > Tutorials > Guide To Smart Contract Security Tools + +We are going to use three distinctive testing and program analysis techniques: + +- **Static analysis with [Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/).** All the paths of the program are approximated and analyzed at the same time, through different program presentations (e.g. control-flow-graph) +- **Fuzzing with [Echidna](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/).** The code is executed with a pseudo-random generation of transactions. The fuzzer will try to find a sequence of transactions to violate a given property. +- **Symbolic execution with [Manticore](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/).** A formal verification technique, which translates each execution path to a mathematical formula, on which on top constraints can be checked. + +Each technique has advantages and pitfalls, and will be useful in [specific cases](#determining-security-properties): + +| Technique | Tool | Usage | Speed | Bugs missed | False Alarms | +| ------------------ | --------- | ----------------------------- | ------- | ----------- | ------------ | +| Static Analysis | Slither | CLI & scripts | seconds | moderate | low | +| Fuzzing | Echidna | Solidity properties | minutes | low | none | +| Symbolic Execution | Manticore | Solidity properties & scripts | hours | none\* | none | + +\* if all the paths are explored without timeout + +**Slither** analyzes contracts within seconds, however, static analysis might lead to false alarms and will be less suitable for complex checks (e.g. arithmetic checks). Run Slither via the API for push-button access to built-in detectors or via the API for user-defined checks. + +**Echidna** needs to run for several minutes and will only produce true positives. Echidna checks user-provided security properties, written in Solidity. It might miss bugs since it is based on random exploration. + +**Manticore** performs the "heaviest weight" analysis. Like Echidna, Manticore verifies user-provided properties. It will need more time to run, but it can prove the validity of a property and will not report false alarms. + +## Suggested workflow + +Start with Slither's built-in detectors to ensure that no simple bugs are present now or will be introduced later. Use Slither to check properties related to inheritance, variable dependencies, and structural issues. As the codebase grows, use Echidna to test more complex properties of the state machine. Revisit Slither to develop custom checks for protections unavailable from Solidity, like protecting against a function being overridden. Finally, use Manticore to perform targeted verification of critical security properties, e.g., arithmetic operations. + +- Use Slither's CLI to catch common issues +- Use Echidna to test high-level security properties of your contract +- Use Slither to write custom static checks +- Use Manticore once you want in-depth assurance of critical security properties + +**A note on unit tests**. Unit tests are necessary to build high-quality software. However, these techniques are not the best suited to find security flaws. They are typically used to test positive behaviors of code (i.e. the code works as expected in the normal context), while security flaws tend to reside in edge cases that the developers did not consider. In our study of dozens of smart contract security reviews, [unit test coverage had no effect on the number or severity of security flaws](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/) we found in our client's code. + +## Determining Security Properties + +To effectively test and verify your code, you must identify the areas that need attention. As your resources spent on security are limited, scoping the weak or high-value parts of your codebase is important to optimize your effort. Threat modeling can help. Consider reviewing: + +- [Rapid Risk Assessments](https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment.html) (our preferred approach when time is short) +- [Guide to Data-Centric System Threat Modeling](https://csrc.nist.gov/publications/detail/sp/800-154/draft) (aka NIST 800-154) +- [Shostack threat modeling](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) +- [STRIDE]() / [DREAD]() +- [PASTA](https://wikipedia.org/wiki/Threat_model#P.A.S.T.A.) +- [Use of Assertions](https://blog.regehr.org/archives/1091) + +### Components + +Knowing what you want to check will also help you to select the right tool. + +The broad areas that are frequently relevant for smart contracts include: + +- **State machine.** Most contracts can be represented as a state machine. Consider checking that (1) No invalid state can be reached, (2) if a state is valid that it can be reached, and (3) no state traps the contract. + + - Echidna and Manticore are the tools to favor to test state-machine specifications. + +- **Access controls.** If your system has privileged users (e.g. an owner, controllers, ...) you must ensure that (1) each user can only perform the authorized actions and (2) no user can block actions from a more privileged user. + + - Slither, Echidna and Manticore can check for correct access controls. For example, Slither can check that only whitelisted functions lack the onlyOwner modifier. Echidna and Manticore are useful for more complex access control, such as a permission given only if the contract reaches a given state. + +- **Arithmetic operations.** Checking the soundness of the arithmetic operations is critical. Using `SafeMath` everywhere is a good step to prevent overflow/underflow, however, you must still consider other arithmetic flaws, including rounding issues and flaws that trap the contract. + + - Manticore is the best choice here. Echidna can be used if the arithmetic is out-of-scope of the SMT solver. + +- **Inheritance correctness.** Solidity contracts rely heavily on multiple inheritance. Mistakes such as a shadowing function missing a `super` call and misinterpreted c3 linearization order can easily be introduced. + + - Slither is the tool to ensure detection of these issues. + +- **External interactions.** Contracts interact with each other, and some external contracts should not be trusted. For example, if your contract relies on external oracles, will it remain secure if half the available oracles are compromised? + + - Manticore and Echidna are the best choice for testing external interactions with your contracts. Manticore has an built-in mechanism to stub external contracts. + +- **Standard conformance.** Ethereum standards (e.g. ERC20) have a history of flaws in their design. Be aware of the limitations of the standard you are building on. + - Slither, Echidna, and Manticore will help you to detect deviations from a given standard. + +### Tool selection cheatsheet + +| Component | Tools | Examples | +| ----------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| State machine | Echidna, Manticore | +| Access control | Slither, Echidna, Manticore | [Slither exercise 2](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/slither/exercise2.md), [Echidna exercise 2](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-2.md) | +| Arithmetic operations | Manticore, Echidna | [Echidna exercise 1](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-1.md), [Manticore exercises 1 - 3](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore/exercises) | +| Inheritance correctness | Slither | [Slither exercise 1](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/slither/exercise1.md) | +| External interactions | Manticore, Echidna | +| Standard conformance | Slither, Echidna, Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | + +Other areas will need to be checked depending on your goals, but these coarse-grained areas of focus are a good start for any smart contract system. + +Our public audits contain examples of verified or tested properties. Consider reading the `Automated Testing and Verification` sections of the following reports to review real-world security properties: + +- [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) +- [Balancer](https://github.com/trailofbits/publications/blob/master/reviews/BalancerCore.pdf) + +--- + +## Developers > Tutorials > Hello World Smart Contract Fullstack + +This guide is for you if you are new to blockchain development and don't know where to start or how to deploy and interact with smart contracts. We will walk through creating and deploying a simple, smart contract on the Goerli test network using [MetaMask](https://metamask.io), [Solidity](https://docs.soliditylang.org/en/v0.8.0/), [Hardhat](https://hardhat.org), and [Alchemy](https://alchemyapi.io/eth). + +You'll need an Alchemy account to complete this tutorial. [Sign up for a free account](https://www.alchemy.com/). + +If you have questions at any point, feel free to reach out in the [Alchemy Discord](https://discord.gg/gWuC7zB)! + +## Part 1 - Create and Deploy your Smart Contract using Hardhat + +### Connect to the Ethereum network + +There are many ways to make requests to the Ethereum chain. For simplicity, we'll use a free account on Alchemy, a blockchain developer platform and API that allows us to communicate with the Ethereum chain without running a node ourselves. Alchemy also has developer tools for monitoring and analytics; we'll take advantage of these in this tutorial to understand what's going on under the hood in our smart contract deployment. + +### Create your app and API key + +Once you've created an Alchemy account, you can generate an API key by creating an app. This will allow you to make requests to the Goerli testnet. If you're not familiar with testnets you can [read Alchemy's guide to choosing a network](https://docs.alchemyapi.io/guides/choosing-a-network). + +On the Alchemy dashboard, find the **Apps** dropdown in the navigation bar and click **Create App**. + +![Hello world create app](./hello-world-create-app.png) + +Give your app the name '_Hello World_' and write a short description. Select **Staging** as your environment and **Goerli** as your network. + +![create app view hello world](./create-app-view-hello-world.png) + +_Note: be sure to select **Goerli**, or this tutorial won't work._ + +Click **Create app**. Your app will appear in the table below. + +### Create an Ethereum account + +You need an Ethereum account to send and receive transactions. We'll use MetaMask, a virtual wallet in the browser that lets users manage their Ethereum account address. + +You can download and create a MetaMask account for free [here](https://metamask.io/download). When you are creating an account, or if you already have an account, make sure to switch over to the “Goerli Test Network” in the upper right (so that we’re not dealing with real money). + +### Step 4: Add ether from a Faucet + +To deploy your smart contract to the test network, you'll need some fake ETH. To get ETH on the Goerli network, go to a Goerli faucet and enter your Goerli account address. Note that Goerli faucets can be a bit unreliable recently - see the [test networks page](/developers/docs/networks/#goerli) for a list of options to try: + +_Note: due to network congestion, this might take a while._ +`` + +### Step 5: Check your Balance + +To double-check the ETH is in your wallet, let’s make an [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) request using [Alchemy’s composer tool](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). This will return the amount of ETH in our wallet. To learn more check out [Alchemy's short tutorial on how to use the composer tool](https://youtu.be/r6sjRxBZJuU). + +Enter you input your MetaMask account address and click **Send Request**. You will see a response that looks like the code snippet below. + +```json + +``` + +> _Note: This result is in wei, not ETH. Wei is used as the smallest denomination of ether._ + +Phew! Our fake money is all there. + +### Step 6: Initialize our project + +First, we'll need to create a folder for our project. Navigate to your command line and input the following. + +``` +mkdir hello-world +cd hello-world +``` + +Now that we’re inside our project folder, we’ll use `npm init` to initialize the project. + +> If you don’t have npm installed yet, follow [these instructions to install Node.js and npm](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm). + +For the purpose of this tutorial, it doesn't matter how you answer the initialization questions. Here is how we did it for reference: + +``` +package name: (hello-world) +version: (1.0.0) +description: hello world smart contract +entry point: (index.js) +test command: +git repository: +keywords: +author: +license: (ISC) + +About to write to /Users/.../.../.../hello-world/package.json: + +, + "author": "", + "license": "ISC" +} +``` + +Approve the package.json and we’re good to go! + +### Step 7: Download Hardhat + +Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. It helps developers when building smart contracts and dapps locally before deploying to the live chain. + +Inside our `hello-world` project run: + +``` +npm install --save-dev hardhat +``` + +Check out this page for more details on [installation instructions](https://hardhat.org/getting-started/#overview). + +### Step 8: Create Hardhat project + +Inside our `hello-world` project folder, run: + +``` +npx hardhat +``` + +You should then see a welcome message and option to select what you want to do. Select “create an empty hardhat.config.js”: + +``` +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 Welcome to Hardhat v2.0.11 👷‍ + +What do you want to do? … +Create a sample project +❯ Create an empty hardhat.config.js +Quit +``` + +This will generate a `hardhat.config.js` file in the project. We'll use this later in the tutorial to specify the setup for our project. + +### Step 9: Add project folders + +To keep the project organized, let's create two new folders. In the command line, navigate to the root directory of your `hello-world` project and type: + +``` +mkdir contracts +mkdir scripts +``` + +- `contracts/` is where we’ll keep our hello world smart contract code file +- `scripts/` is where we’ll keep scripts to deploy and interact with our contract + +### Step 10: Write our contract + +You might be asking yourself, when are we going to write code? It's time! + +Open up the hello-world project in your favorite editor. Smart contracts most commonly are written in Solidity, which we will use to write our smart contract.‌ + +1. Navigate to the `contracts` folder and create a new file called `HelloWorld.sol` +2. Below is a sample Hello World smart contract that we will be using for this tutorial. Copy the contents below into the `HelloWorld.sol` file. + +_Note: Be sure to read the comments to understand what this contract does._ + +``` +// Specifies the version of Solidity, using semantic versioning. +// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity >=0.7.3; + +// Defines a contract named `HelloWorld`. +// A contract is a collection of functions and data (its state). Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld + + // A public function that accepts a string argument and updates the `message` storage variable. + function update(string memory newMessage) public +} +``` + +This is a basic smart contract that stores a message upon creation. It can be updated by calling the `update` function. + +### Step 11: Connect MetaMask & Alchemy to your project + +We’ve created a MetaMask wallet, Alchemy account, and written our smart contract, now it’s time to connect the three. + +Every transaction sent from your wallet requires a signature using your unique private key. To provide our program with this permission, we can safely store our private key in an environment file. We will also store an API key for Alchemy here. + +> To learn more about sending transactions, check out [this tutorial](https://docs.alchemyapi.io/alchemy/tutorials/sending-transactions-using-web3-and-alchemy) on sending transactions using web3. + +First, install the dotenv package in your project directory: + +``` +npm install dotenv --save +``` + +Then, create a `.env` file in the root directory of the project. Add your MetaMask private key and HTTP Alchemy API URL to it. + +Your environment file must be named `.env` or it won't be recognized as an environment file. + +Do not name it `process.env` or `.env-custom` or anything else. + +- Follow [these instructions](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key) to export your private key +- See below to get HTTP Alchemy API URL + +![](./get-alchemy-api-key.gif) + +Your `.env` should look like this: + +``` +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PRIVATE_KEY = "your-metamask-private-key" +``` + +To actually connect these to our code, we’ll reference these variables in our `hardhat.config.js` file on step 13. + +### Step 12: Install Ethers.js + +Ethers.js is a library that makes it easier to interact and make requests to Ethereum by wrapping [standard JSON-RPC methods](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc) with more user friendly methods. + +Hardhat allows us to integrate [plugins](https://hardhat.org/plugins/) for additional tooling and extended functionality. We’ll be taking advantage of the [Ethers plugin](https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html) for contract deployment. + +In your project directory type: + +```bash +npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" +``` + +### Step 13: Update hardhat.config.js + +We’ve added several dependencies and plugins so far, now we need to update `hardhat.config.js` so that our project knows about all of them. + +Update your `hardhat.config.js` to look like this: + +```javascript +/** + * @type import('hardhat/config').HardhatUserConfig + */ + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") + +const = process.env + +module.exports = , + goerli: `], + }, + }, +} +``` + +### Step 14: Compile our contract + +To make sure everything is working so far, let’s compile our contract. The `compile` task is one of the built-in hardhat tasks. + +From the command line run: + +```bash +npx hardhat compile +``` + +You might get a warning about `SPDX license identifier not provided in source file`, but no need to worry about that — hopefully everything else looks good! If not, you can always message in the [Alchemy discord](https://discord.gg/u72VCg3). + +### Step 15: Write our deploy script + +Now that our contract is written and our configuration file is good to go, it’s time to write our contract deploy script. + +Navigate to the `scripts/` folder and create a new file called `deploy.js` , adding the following contents to it: + +```javascript +async function main() + +main() + .then(() => process.exit(0)) + .catch((error) => ) +``` + +Hardhat does an amazing job of explaining what each of these lines of code does in their [Contracts tutorial](https://hardhat.org/tutorial/testing-contracts.html#writing-tests), we’ve adopted their explanations here. + +```javascript +const HelloWorld = await ethers.getContractFactory("HelloWorld") +``` + +A `ContractFactory` in ethers.js is an abstraction used to deploy new smart contracts, so `HelloWorld` here is a [factory]() for instances of our hello world contract. When using the `hardhat-ethers` plugin `ContractFactory` and `Contract`, instances are connected to the first signer (owner) by default. + +```javascript +const hello_world = await HelloWorld.deploy() +``` + +Calling `deploy()` on a `ContractFactory` will start the deployment, and return a `Promise` that resolves to a `Contract` object. This is the object that has a method for each of our smart contract functions. + +### Step 16: Deploy our contract + +We’re finally ready to deploy our smart contract! Navigate to the command line and run: + +```bash +npx hardhat run scripts/deploy.js --network goerli +``` + +You should then see something like: + +```bash +Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +``` + +**Please save this address**. We will be using it later in the tutorial. + +If we go to the [Goerli etherscan](https://goerli.etherscan.io) and search for our contract address we should able to see that it has been deployed successfully. The transaction will look something like this: + +![](./etherscan-contract.png) + +The `From` address should match your MetaMask account address and the `To` address will say **Contract Creation**. If we click into the transaction we’ll see our contract address in the `To` field. + +![](./etherscan-transaction.png) + +Congrats! You just deployed a smart contract to an Ethereum testnet. + +To understand what’s going on under the hood, let’s navigate to the Explorer tab in our [Alchemy dashboard](https://dashboard.alchemyapi.io/explorer). If you have multiple Alchemy apps make sure to filter by app and select **Hello World**. + +![](./hello-world-explorer.png) + +Here you’ll see a handful of JSON-RPC methods that Hardhat/Ethers made under the hood for us when we called the `.deploy()` function. Two important methods here are [`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction), which is the request to write our contract onto the Goerli chain, and [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash), which is a request to read information about our transaction given the hash. To learn more about sending transactions, check out [our tutorial on sending transactions using Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/). + +## Part 2: Interact with your Smart Contract + +Now that we've successfully deployed a smart contract to the Goerli network let's learn how to interact with it. + +### Create a interact.js file + +This is the file where we'll write our interaction script. We'll be using the Ethers.js library that you previously installed in Part 1. + +Inside the `scripts/`folder, create a new file named `interact.js` add the following code: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS +``` + +### Update your .env file + +We will be using new environment variables, so we need to define them in the `.env`file that [we created earlier](#step-11-connect-metamask-&-alchemy-to-your-project). + +We'll need to add a definition for our Alchemy `API_KEY` and the `CONTRACT_ADDRESS` where your smart contract was deployed. + +Your `.env` file should look something like this: + +```bash +# .env + +API_URL = "https://eth-goerli.alchemyapi.io/v2/" +API_KEY = "" +PRIVATE_KEY = "" +CONTRACT_ADDRESS = "0x" +``` + +### Grab your contract ABI + +Our contract [ABI (Application Binary Interface)](/glossary/#abi) is the interface to interact with our smart contract. Hardhat automatically generates an ABI and saves it in `HelloWorld.json`. To use the ABI, we'll need to parse out the contents by adding the following lines of code to our `interact.js` file: + +```javascript +// interact.js +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") +``` + +If you want to see the ABI you can print it to your console: + +```javascript +console.log(JSON.stringify(contract.abi)) +``` + +To see your ABI printed to the console, navigate to your terminal and run: + +```bash +npx hardhat run scripts/interact.js +``` + +### Create an instance of your contract + +To interact with our contract, we need to create a contract instance in our code. To do so with Ethers.js, we'll need to work with three concepts: + +1. Provider - a node provider that gives you read and write access to the blockchain +2. Signer - represents an Ethereum account that can sign transactions +3. Contract - an Ethers.js object representing a specific contract deployed onchain + +We'll use the contract ABI from the previous step to create our instance of the contract: + +```javascript +// interact.js + +// Provider +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// Signer +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// Contract +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) +``` + +Learn more about Providers, Signers, and Contracts in the [ethers.js documentation](https://docs.ethers.io/v5/). + +### Read the init message + +Remember when we deployed our contract with the `initMessage = "Hello world!"`? We are now going to read that message stored in our smart contract and print it to the console. + +In JavaScript, asynchronous functions get used when interacting with networks. To learn more about asynchronous functions, [read this medium article](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff). + +Use the code below to call the `message` function in our smart contract and read the init message: + +```javascript +// interact.js + +// ... + +async function main() +main() +``` + +After running the file using `npx hardhat run scripts/interact.js` in the terminal we should see this response: + +``` +The message is: Hello world! +``` + +Congrats! You've just successfully read smart contract data from the Ethereum blockchain, way to go! + +### Update the message + +Instead of just reading the message, we can also update the message saved in our smart contract using the `update` function! Pretty cool, right? + +To update the message, we can directly call the `update` function on our instantiated Contract object: + +```javascript +// interact.js + +// ... + +async function main() +main() +``` + +Note that on line 11, we make a call to `.wait()` on the returned transaction object. This ensures that our script waits for the transaction to get mined on the blockchain before exiting the function. If the `.wait()` call isn't included, the script may not see the updated `message` value in the contract. + +### Read the new message + +You should be able to repeat the [previous step](#read-the-init-message) to read the updated `message` value. Take a moment and see if you can make the changes necessary to print out that new value! + +If you need a hint, here's what your `interact.js` file should look like at this point: + +```javascript +// interact.js + +const API_KEY = process.env.API_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY +const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS + +const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") + +// provider - Alchemy +const alchemyProvider = new ethers.providers.AlchemyProvider( + (network = "goerli"), + API_KEY +) + +// signer - you +const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider) + +// contract instance +const helloWorldContract = new ethers.Contract( + CONTRACT_ADDRESS, + contract.abi, + signer +) + +async function main() + +main() +``` + +Now just run the script and you should be able to see the old message, the updating status, and the new message printed out to your terminal! + +`npx hardhat run scripts/interact.js --network goerli` + +``` +The message is: Hello World! +Updating the message... +The new message is: This is the new message. +``` + +While running that script, you may notice that the `Updating the message...` step takes a while to load before the new message loads. That is due to the mining process; if you are curious about tracking transactions while they are being mined, visit the [Alchemy mempool](https://dashboard.alchemyapi.io/mempool) to see the status of a transaction. If the transaction is dropped, it's also helpful to check [Goerli Etherscan](https://goerli.etherscan.io) and search for your transaction hash. + +## Part 3: Publish your Smart Contract to Etherscan + +You did all the hard work of bringing your smart contract to life; now it's time to share it with the world! + +By verifying your smart contract on Etherscan, anyone can view your source code and interact with your smart contract. Let's get started! + +### Step 1: Generate an API Key on your Etherscan account + +An Etherscan API Key is necessary to verify that you own the smart contract you are trying to publish. + +If you don't have an Etherscan account already, [sign up for an account](https://etherscan.io/register). + +Once logged in, find your username in the navigation bar, hover over it and select the **My profile** button. + +On your profile page, you should see a side navigation bar. From the side navigation bar, select **API Keys**. Next, press the "Add" button to create a new API key, name your app **hello-world**and press the **Create New API Key** button. + +Your new API key should appear in the API key table. Copy the API key to your clipboard. + +Next, we need to add the Etherscan API key to our `.env` file. + +After adding it, your `.env`file should look like this: + +```javascript +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PUBLIC_KEY = "your-public-account-address" +PRIVATE_KEY = "your-private-account-address" +CONTRACT_ADDRESS = "your-contract-address" +ETHERSCAN_API_KEY = "your-etherscan-key" +``` + +### Hardhat-deployed smart contracts + +#### Install hardhat-etherscan + +Publishing your contract to Etherscan using Hardhat is straightforward. You will first need to install the `hardhat-etherscan` plugin to get started. `hardhat-etherscan` will automatically verify the smart contract's source code and ABI on Etherscan. To add this, in the `hello-world` directory run: + +```text +npm install --save-dev @nomiclabs/hardhat-etherscan +``` + +Once installed, include the following statement at the top of your `hardhat.config.js`, and add the Etherscan config options: + +```javascript +// hardhat.config.js + +require("dotenv").config() +require("@nomiclabs/hardhat-ethers") +require("@nomiclabs/hardhat-etherscan") + +const = process.env + +module.exports = , + goerli: `], + }, + }, + etherscan: , +} +``` + +#### Verify your smart contract on Etherscan + +Ensure all files are saved and all `.env` variables are correctly configured. + +Run the `verify` task, passing the contract address, and the network to where it's deployed: + +```text +npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!' +``` + +Make sure that `DEPLOYED_CONTRACT_ADDRESS` is the address of your deployed smart contract on the Goerli test network. Also, the final argument (`'Hello World!'`) must be the same string value used [during the deploy step in part 1](#write-our-deploy-script). + +If all goes well, you will see the following message in your terminal: + +```text +Successfully submitted source code for contract +contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address +for verification on Etherscan. Waiting for verification result... + + +Successfully verified contract HelloWorld on Etherscan. +https://goerli.etherscan.io/address/#contracts +``` + +Congrats! Your smart contract code is on Etherscan! + +### Check out your smart contract on Etherscan! + +When you navigate to the link provided in your terminal, you should be able to see your smart contract code and ABI published on Etherscan! + +**Wahooo - you did it champ! Now anyone can call or write to your smart contract! We can't wait to see what you build next!** + +## Part 4 - Integrating your smart contract with the frontend + +By the end of this tutorial, you'll know how to: + +- Connect a MetaMask wallet to your dapp +- Read data from your smart contract using the [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API +- Sign Ethereum transactions using MetaMask + +For this dapp, we'll be using [React](https://reactjs.org/) as our frontend framework; however, it's important to note that we won't be spending much time breaking down its fundamentals, as we'll mostly be focusing on bringing Web3 functionality to our project. + +As a prerequisite, you should have a beginner-level understanding of React. If not, we recommend completing the official [Intro to React tutorial](https://reactjs.org/tutorial/tutorial.html). + +### Clone the starter files + +First, go to the [hello-world-part-four GitHub repository](https://github.com/alchemyplatform/hello-world-part-four-tutorial) to get the starter files for this project and clone this repository to your local machine. + +Open the cloned repository locally. Notice that it contains two folders: `starter-files` and `completed`. + +- `starter-files`- **we will be working in this directory**, we will connect the UI to your Ethereum wallet and the smart contract we published to Etherscan in [Part 3](#part-3). +- `completed` contains the entire completed tutorial and should only be used as a reference if you get stuck. + +Next, open your copy of `starter-files` to your favorite code editor, and then navigate into the `src` folder. + +All of the code we'll write will live under the `src` folder. We'll be editing the `HelloWorld.js` component and the `util/interact.js` JavaScript files to give our project Web3 functionality. + +### Check out the starter files + +Before we start coding, let's explore what is provided to us in the starter files. + +#### Get your react project running + +Let's start by running the React project in our browser. The beauty of React is that once we have our project running in our browser, any changes we save will be updated live in our browser. + +To get the project running, navigate to the root directory of the `starter-files` folder, and the run `npm install` in your terminal to install the dependencies of the project: + +```bash +cd starter-files +npm install +``` + +Once those have finished installing, run `npm start` in your terminal: + +```bash +npm start +``` + +Doing so should open [http://localhost:3000/](http://localhost:3000/) in your browser, where you'll see the frontend for our project. It should consist of one field \(a place to update the message stored in your smart contract\), a "Connect Wallet" button, and an "Update" button. + +If you try clicking either button, you'll notice that they don't work—that's because we still need to program their functionality. + +#### The `HelloWorld.js` component + +Let's go back into the `src` folder in our editor and open the `HelloWorld.js` file. It's super important that we understand everything in this file, as it is the primary React component we will be working on. + +At the top of this file, you'll notice we have several import statements that are necessary to get our project running, including the React library, useEffect and useState hooks, some items from the `./util/interact.js` (we'll describe them in more details soon!), and the Alchemy logo. + +```javascript +// HelloWorld.js + +import from "./util/interact.js" + +``` + +Next, we have our state variables that we will update after specific events. + +```javascript +// HelloWorld.js + +//State variables +const [walletAddress, setWallet] = useState("") +const [status, setStatus] = useState("") +const [message, setMessage] = useState("No connection to the network.") +const [newMessage, setNewMessage] = useState("") +``` + +Here's what each of the variables represents: + +- `walletAddress` - a string that stores the user's wallet address +- `status`- a string that stores a helpful message that guides the user on how to interact with the dapp +- `message` - a string that stores the current message in the smart contract +- `newMessage` - a string that stores the new message that will be written to the smart contract + +After the state variables, you'll see five un-implemented functions: `useEffect` ,`addSmartContractListener`, `addWalletListener` , `connectWalletPressed`, and `onUpdatePressed`. We'll explain what they do below: + +```javascript +// HelloWorld.js + +//called only once +useEffect(async () => , []) + +function addSmartContractListener() + +function addWalletListener() + +const connectWalletPressed = async () => + +const onUpdatePressed = async () => +``` + +- [`useEffect`](https://reactjs.org/docs/hooks-effect.html)- this is a React hook that is called after your component is rendered. Because it has an empty array `[]` prop passed into it \(see line 4\), it will only be called on the component's _first_ render. Here we'll load the current message stored in our smart contract, call our smart contract and wallet listeners, and update our UI to reflect whether a wallet is already connected. +- `addSmartContractListener`- this function sets up a listener that will watch for our HelloWorld contract's `UpdatedMessages` event and update our UI when the message is changed in our smart contract. +- `addWalletListener`- this function sets up a listener that detects changes in the user's MetaMask wallet state, such as when the user disconnects their wallet or switches addresses. +- `connectWalletPressed`- this function will be called to connect the user's MetaMask wallet to our dapp. +- `onUpdatePressed` - this function will be called when the user wants to update the message stored in the smart contract. + +Near the end of this file, we have the UI of our component. + +```javascript +// HelloWorld.js + +//the UI of our component +return ( + + + + + + + Current Message: + + + New Message: + + + setNewMessage(e.target.value)} + value= + /> + + + + Update + + + +) +``` + +If you scan this code carefully, you'll notice where we use our various state variables in our UI: + +- On lines 6-12, if the user's wallet is connected \(i.e. `walletAddress.length > 0`\), we display a truncated version of the user `walletAddress` in the button with ID "walletButton;" otherwise it simply says "Connect Wallet." +- On line 17, we display the current message stored in the smart contract, which is captured in the `message` string. +- On lines 23-26, we use a [controlled component](https://reactjs.org/docs/forms.html#controlled-components) to update our `newMessage` state variable when the input in the text field changes. + +In addition to our state variables, you'll also see that `connectWalletPressed` and `onUpdatePressed` functions are called when the buttons with IDs `publishButton` and `walletButton` are clicked respectively. + +Finally, let's address where is this `HelloWorld.js` component added. + +If you go to the `App.js` file, which is the main component in React that acts as a container for all other components, you'll see that our `HelloWorld.js` component is injected on line 7. + +Last but not least, let's check out one more file provided for you, the `interact.js` file. + +#### The `interact.js` file + +Because we want to prescribe to the [M-V-C](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) paradigm, we'll want a separate file that contains all our functions to manage the logic, data, and rules of our dapp, and then be able to export those functions to our frontend \(our `HelloWorld.js` component\). + +👆🏽This is the exact purpose of our `interact.js` file! + +Navigate to the `util` folder in your `src` directory, and you'll notice we've included a file called `interact.js` that will contain all of our smart contract interaction and wallet functions and variables. + +```javascript +// interact.js + +//export const helloWorldContract; + +export const loadCurrentMessage = async () => {} + +export const connectWallet = async () => {} + +const getCurrentWalletConnected = async () => {} + +export const updateMessage = async (message) => {} +``` + +You'll notice at the top of the file that we've commented out the `helloWorldContract` object. Later in this tutorial, we will uncomment this object and instantiate our smart contract in this variable, which we will then export into our `HelloWorld.js` component. + +The four unimplemented functions after our `helloWorldContract` object do the following: + +- `loadCurrentMessage` - this function handles the logic of loading the current message stored in the smart contract. It will make a _read_ call to the Hello World smart contract using the [Alchemy Web3 API](https://github.com/alchemyplatform/alchemy-web3). +- `connectWallet` - this function will connect the user's MetaMask to our dapp. +- `getCurrentWalletConnected` - this function will check if an Ethereum account is already connected to our dapp on page load and update our UI accordingly. +- `updateMessage` - this function will update the message stored in the smart contract. It will make a _write_ call to the Hello World smart contract, so the user's MetaMask wallet will have to sign an Ethereum transaction to update the message. + +Now that we understand what we're working with, let's figure out how to read from our smart contract! + +### Step 3: Read from your smart contract + +To read from your smart contract, you'll need to successfully set up: + +- An API connection to the Ethereum chain +- A loaded instance of your smart contract +- A function to call to your smart contract function +- A listener to watch for updates when the data you're reading from the smart contract changes + +This may sounds like a lot of steps, but don't worry! We'll walk you through how to do each of them step-by-step! :\) + +#### Establish an API connection to the Ethereum chain + +So remember how in Part 2 of this tutorial, we used our [Alchemy Web3 key to read from our smart contract](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library)? You'll also need an Alchemy Web3 key in your dapp to read from the chain. + +If you don't have it already, first install [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) by navigating to the root directory of your `starter-files` and running the following in your terminal: + +```text +npm install @alch/alchemy-web3 +``` + +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) is a wrapper around [Web3.js](https://docs.web3js.org/), providing enhanced API methods and other crucial benefits to make your life as a web3 developer easier. It is designed to require minimal configuration so you can start using it in your app right away! + +Then, install the [dotenv](https://www.npmjs.com/package/dotenv) package in your project directory, so we have a secure place to store our API key after we fetch it. + +```text +npm install dotenv --save +``` + +For our dapp, **we'll be using our Websockets API key** instead of our HTTP API key, as it will allow us to set up a listener that detects when the message stored in the smart contract changes. + +Once you have your API key, create a `.env` file in your root directory and add your Alchemy Websockets url to it. Afterwards, your `.env` file should look like so: + +```javascript +REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/ +``` + +Now, we're ready to set up our Alchemy Web3 endpoint in our dapp! Let's go back to our `interact.js`, which is nested inside our `util` folder and add the following code at the top of the file: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +//export const helloWorldContract; +``` + +Above, we first imported the Alchemy key from our `.env` file and then passed our `alchemyKey` to `createAlchemyWeb3` to establish our Alchemy Web3 endpoint. + +With this endpoint ready, it's time to load our smart contract! + +#### Loading your Hello World smart contract + +To load your Hello World smart contract, you'll need its contract address and ABI, both of which can be found on Etherscan if you completed [Part 3 of this tutorial.](/developers/tutorials/hello-world-smart-contract-fullstack/#part-3-publish-your-smart-contract-to-etherscan-part-3-publish-your-smart-contract-to-etherscan) + +#### How to get your contract ABI from Etherscan + +If you skipped Part 3 of this tutorial, you can use the HelloWorld contract with address [0x6f3f635A9762B47954229Ea479b4541eAF402A6A](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code). Its ABI can be found [here](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code). + +A contract ABI is necessary for specifying which function a contract will invoke as well ensuring that the function will return data in the format you're expecting. Once we've copied our contract ABI, let's save it as a JSON file called `contract-abi.json` in your `src` directory. + +Your contract-abi.json should be stored in your src folder. + +Armed with our contract address, ABI, and Alchemy Web3 endpoint, we can use the [contract method](https://docs.web3js.org/api/web3-eth-contract/class/Contract) to load an instance of our smart contract. Import your contract ABI into the `interact.js` file and add your contract address. + +```javascript +// interact.js + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" +``` + +We can now finally uncomment our `helloWorldContract` variable, and load the smart contract using our AlchemyWeb3 endpoint: + +```javascript +// interact.js +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +To recap, the first 12 lines of your `interact.js` should now look like this: + +```javascript +// interact.js + +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" + +export const helloWorldContract = new web3.eth.Contract( + contractABI, + contractAddress +) +``` + +Now that we have our contract loaded, we can implement our `loadCurrentMessage` function! + +#### Implementing `loadCurrentMessage` in your `interact.js` file + +This function is super simple. We're going make a simple async web3 call to read from our contract. Our function will return the message stored in the smart contract: + +Update the `loadCurrentMessage` in your `interact.js` file to the following: + +```javascript +// interact.js + +export const loadCurrentMessage = async () => +``` + +Since we want to display this smart contract in our UI, let's update the `useEffect` function in our `HelloWorld.js` component to the following: + +```javascript +// HelloWorld.js + +//called only once +useEffect(async () => , []) +``` + +Note, we only want our `loadCurrentMessage` to be called once during the component's first render. We'll soon implement `addSmartContractListener` to automatically update the UI after the message in the smart contract changes. + +Before we dive into our listener, let's check out what we have so far! Save your `HelloWorld.js` and `interact.js` files, and then go to [http://localhost:3000/](http://localhost:3000/) + +You'll notice that the current message no longer says "No connection to the network." Instead it reflects the message stored in the smart contract. Sick! + +#### Your UI should now reflect the message stored in the smart contract + +Now speaking of that listener... + +#### Implement `addSmartContractListener` + +If you think back to the `HelloWorld.sol` file we wrote in [Part 1 of this tutorial series](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract#step-10-write-our-contract), you'll recall that there is a smart contract event called `UpdatedMessages` that is emitted after our smart contract's `update` function is invoked \(see lines 9 and 27\): + +```javascript +// HelloWorld.sol + +// Specifies the version of Solidity, using semantic versioning. +// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity ^0.7.3; + +// Defines a contract named `HelloWorld`. +// A contract is a collection of functions and data (its state). Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld + + // A public function that accepts a string argument and updates the `message` storage variable. + function update(string memory newMessage) public +} +``` + +Smart contract events are a way for your contract to communicate that something happened \(i.e. there was an _event_\) on the blockchain to your front-end application, which can be 'listening' for specific events and take action when they happen. + +The `addSmartContractListener` function is going to specifically listen for our Hello World smart contract's `UpdatedMessages` event, and update our UI to display the new message. + +Modify `addSmartContractListener` to the following: + +```javascript +// HelloWorld.js + +function addSmartContractListener() , (error, data) => else + }) +} +``` + +Let's break down what happens when the listener detects an event: + +- If an error occurs when the event is emitted, it will be reflected in the UI via our `status` state variable. +- Otherwise, we will use the `data` object returned. The `data.returnValues` is an array indexed at zero where the first element in the array stores the previous message and second element stores the updated one. Altogether, on a successful event we'll set our `message` string to the updated message, clear the `newMessage` string, and update our `status` state variable to reflect that a new message has been published on our smart contract. + +Finally, let's call our listener in our `useEffect` function so it is initialized on the `HelloWorld.js` component's first render. Altogether, your `useEffect` function should look like this: + +```javascript +// HelloWorld.js + +useEffect(async () => , []) +``` + +Now that we're able to read from our smart contract, it would be great to figure out how to write to it too! However, to write to our dapp, we must first have an Ethereum wallet connected to it. + +So, next we'll tackle setting up our Ethereum wallet \(MetaMask\) and then connecting it to our dapp! + +### Step 4: Set up your Ethereum wallet + +To write anything to the Ethereum chain, users must sign transactions using their virtual wallet's private keys. For this tutorial, we’ll use [MetaMask](https://metamask.io/), a virtual wallet in the browser used to manage your Ethereum account address, as it makes this transaction signing super easy for the end-user. + +If you want to understand more about how transactions on Ethereum work, check out [this page](/developers/docs/transactions/) from the Ethereum foundation. + +#### Download MetaMask + +You can download and create a MetaMask account for free [here](https://metamask.io/download). When you are creating an account, or if you already have an account, make sure to switch over to the “Goerli Test Network” in the upper right \(so that we’re not dealing with real money\). + +#### Add ether from a Faucet + +To sign a transaction on the Ethereum blockchain, we’ll need some fake Eth. To get Eth you can go to the [FaucETH](https://fauceth.komputing.org) and enter your Goerli account address, click “Request funds”, then select “Ethereum Testnet Goerli” in the dropdown and finally click “Request funds” button again. You should see Eth in your MetaMask account soon after! + +#### Check your Balance + +To double check our balance is there, let’s make an [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) request using [Alchemy’s composer tool](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). This will return the amount of Eth in our wallet. After you input your MetaMask account address and click “Send Request”, you should see a response like this: + +```text + +``` + +**NOTE:** This result is in wei not eth. Wei is used as the smallest denomination of ether. The conversion from wei to eth is: 1 eth = 10¹⁸ wei. So if we convert 0xde0b6b3a7640000 to decimal we get 1\*10¹⁸ which equals 1 eth. + +Phew! Our fake money is all there! 🤑 + +### Step 5: Connect MetaMask to your UI + +Now that our MetaMask wallet is set up, let's connect our dapp to it! + +#### The `connectWallet` function + +In our `interact.js`file, let's implement the `connectWallet` function, which we can then call in our `HelloWorld.js` component. + +Let's modify `connectWallet` to the following: + +```javascript +// interact.js + +export const connectWallet = async () => ) + const obj = + return obj + } catch (err) + } + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your + browser. + + + + ), + } + } +} +``` + +So what does this giant block of code do exactly? + +Well, first, it checks if it `window.ethereum` is enabled in your browser. + +`window.ethereum` is a global API injected by MetaMask and other wallet providers that allows websites to request users' Ethereum accounts. If approved, it can read data from the blockchains the user is connected to, and suggest that the user sign messages and transactions . Check out the [MetaMask docs](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents) for more info! + +If `window.ethereum` _is not_ present, then that means MetaMask is not installed. This results in a JSON object being returned, where `address` returned is an empty string, and the `status` JSX object relays that the user must install MetaMask. + +Now if `window.ethereum` _is_ present, then that's when things get interesting. + +Using a try/catch loop, we'll try to connect to MetaMask by calling [`window.ethereum.request();`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts). Calling this function will open up MetaMask in the browser, whereby the user will be prompted to connect their wallet to your dapp. + +- If the user chooses to connect, `method: "eth_requestAccounts"` will return an array that contains all of the user's account addresses that connected to the dapp. Altogether, our `connectWallet` function will return a JSON object that contains the _first_ `address` in this array \(see line 9\) and a `status` message that prompts the user to write a message to the smart contract. +- If the user rejects the connection, then the JSON object will contain an empty string for the `address` returned and a `status` message that reflects that the user rejected the connection. + +Now that we've written this `connectWallet` function, the next step is to call it to our `HelloWorld.js`component. + +#### Add the `connectWallet` function to your `HelloWorld.js` UI Component + +Navigate to the `connectWalletPressed` function in `HelloWorld.js`, and update it to the following: + +```javascript +// HelloWorld.js + +const connectWalletPressed = async () => +``` + +Notice how most of our functionality is abstracted away from our `HelloWorld.js` component from the `interact.js` file? This is so we comply with the M-V-C paradigm! + +In `connectWalletPressed`, we simply make an await call to our imported `connectWallet` function, and using its response, we update our `status` and `walletAddress` variables via their state hooks. + +Now, let's save both files \(`HelloWorld.js` and `interact.js`\) and test out our UI so far. + +Open your browser on the [http://localhost:3000/](http://localhost:3000/) page, and press the "Connect Wallet" button on the top right of the page. + +If you have MetaMask installed, you should be prompted to connect your wallet to your dapp. Accept the invitation to connect. + +You should see that the wallet button now reflects that your address is connected! Yasssss 🔥 + +Next, try refreshing the page... this is strange. Our wallet button is prompting us to connect MetaMask, even though it is already connected... + +However, have no fear! We easily can address that (get it?) by implementing `getCurrentWalletConnected`, which will check if an address is already connected to our dapp and update our UI accordingly! + +#### The `getCurrentWalletConnected` function + +Update your `getCurrentWalletConnected` function in the `interact.js` file to the following: + +```javascript +// interact.js + +export const getCurrentWalletConnected = async () => ) + if (addressArray.length > 0) + } else + } + } catch (err) + } + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your + browser. + + + + ), + } + } +} +``` + +This code is _very_ similar to the `connectWallet` function we just wrote in the previous step. + +The main difference is that instead of calling the method `eth_requestAccounts`, which opens MetaMask for the user to connect their wallet, here we call the method `eth_accounts`, which simply returns an array containing the MetaMask addresses currently connected to our dapp. + +To see this function in action, let's call it in our `useEffect` function of our `HelloWorld.js` component: + +```javascript +// HelloWorld.js + +useEffect(async () => = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) +}, []) +``` + +Notice, we use the response of our call to `getCurrentWalletConnected` to update our `walletAddress` and `status` state variables. + +Now that you've added this code, let's try refreshing our browser window. + +Niceeeee! The button should say that you're connected, and show a preview of your connected wallet's address - even after you refresh! + +#### Implement `addWalletListener` + +The final step in our dapp wallet setup is implementing the wallet listener so our UI updates when our wallet's state changes, such as when the user disconnects or switches accounts. + +In your `HelloWorld.js` file, modify your `addWalletListener` function as the following: + +```javascript +// HelloWorld.js + +function addWalletListener() else + }) + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your browser. + + + ) + } +} +``` + +I bet you don't even need our help to understand what's going on here at this point, but for thoroughness purposes, let's quickly break it down: + +- First, our function checks if `window.ethereum` is enabled \(i.e. MetaMask is installed\). + - If it's not, we simply set our `status` state variable to a JSX string that prompts the user to install MetaMask. + - If it is enabled, we set up the listener `window.ethereum.on("accountsChanged")` on line 3 that listens for state changes in the MetaMask wallet, which include when the user connects an additional account to the dapp, switches accounts, or disconnects an account. If there is at least one account connected, the `walletAddress` state variable is updated as the first account in the `accounts` array returned by the listener. Otherwise, `walletAddress` is set as an empty string. + +Last but not least, we must call it in our `useEffect` function: + +```javascript +// HelloWorld.js + +useEffect(async () => = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) + + addWalletListener() +}, []) +``` + +And that's it! We've successfully completed programming all of our wallet functionality! Now onto our last task: updating the message stored in our smart contract! + +### Step 6: Implement the `updateMessage` function + +Alrighty fam, we've arrived at the home stretch! In the `updateMessage` of your `interact.js` file, we're going to do the following: + +1. Make sure the message we wish to publish in our smart contact is valid +2. Sign our transaction using MetaMask +3. Call this function from our `HelloWorld.js` frontend component + +This won't take very long; let's finish this dapp! + +#### Input error handling + +Naturally, it makes sense to have some sort of input error handling at the start of the function. + +We'll want our function to return early if there is no MetaMask extension installed, there is no wallet connected \(i.e. the `address` passed in is an empty string\), or the `message` is an empty string. Let's add the following error handling to `updateMessage`: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => + } + + if (message.trim() === "") + } +} +``` + +Now that it have proper input error handling, it's time to sign the transaction via MetaMask! + +#### Signing our transaction + +If you're already comfortable with traditional web3 Ethereum transactions, the code we write next will be very familiar. Below your input error handling code, add the following to `updateMessage`: + +```javascript +// interact.js + +//set up transaction parameters +const transactionParameters = + +//sign the transaction +try ) + return + + View the status of your transaction on Etherscan! + + + ℹ️ Once the transaction is verified by the network, the message will be + updated automatically. + + ), + } +} catch (error) +} +``` + +Let's breakdown what's happening. First, we set up our transactions parameters, where: + +- `to` specifies the recipient address \(our smart contract\) +- `from` specifies the signer of the transaction, the `address` variable we passed into our function +- `data` contains the call to our Hello World smart contract's `update` method, receiving our `message` string variable as input + +Then, we make an await call, `window.ethereum.request`, where we ask MetaMask to sign the transaction. Notice, on lines 11 and 12, we're specifying our eth method, `eth_sendTransaction`and passing in our `transactionParameters`. + +At this point, MetaMask will open up in the browser, and prompt the user to sign or reject the transaction. + +- If the transaction is successful, the function will return a JSON object where the `status` JSX string prompts the user to check out Etherscan for more information about their transaction. +- If the transaction fails, the function will return a JSON object where the `status` string relays the error message. + +Altogether, our `updateMessage` function should look like this: + +```javascript +// interact.js + +export const updateMessage = async (address, message) => + } + + if (message.trim() === "") + } + + //set up transaction parameters + const transactionParameters = + + //sign the transaction + try ) + return + + View the status of your transaction on Etherscan! + + + ℹ️ Once the transaction is verified by the network, the message will + be updated automatically. + + ), + } + } catch (error) + } +} +``` + +Last but not least, we need to connect our `updateMessage` function to our `HelloWorld.js` component. + +#### Connect `updateMessage` to the `HelloWorld.js` frontend + +Our `onUpdatePressed` function should make an await call to the imported `updateMessage` function and modify the `status` state variable to reflect whether our transaction succeeded or failed: + +```javascript +// HelloWorld.js + +const onUpdatePressed = async () => = await updateMessage(walletAddress, newMessage) + setStatus(status) +} +``` + +It's super clean and simple. And guess what... YOUR DAPP IS COMPLETE!!! + +Go ahead and test out the **Update** button! + +### Make your own custom dapp + +Wooooo, you made it to the end of the tutorial! To recap, you learned how to: + +- Connect a MetaMask wallet to your dapp project +- Read data from your smart contract using the [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API +- Sign Ethereum transactions using MetaMask + +Now you're fully equipped to apply the skills from this tutorial to build out your own custom dapp project! As always, if you have any questions, don't hesitate to reach out to us for help in the [Alchemy Discord](https://discord.gg/gWuC7zB). 🧙‍♂️ + +Once you complete this tutorial, let us know how your experience was or if you have any feedback by tagging us on Twitter [@alchemyplatform](https://twitter.com/AlchemyPlatform)! + +--- + +## Developers > Tutorials > Hello World Smart Contract + +If you are new to blockchain development and don’t know where to start, or if you just want to understand how to deploy and interact with smart contracts, this guide is for you. We will walk through creating and deploying a simple smart contract on the Goerli test network using a virtual wallet [MetaMask](https://metamask.io/), [Solidity](https://docs.soliditylang.org/en/v0.8.0/), [Hardhat](https://hardhat.org/), and [Alchemy](https://alchemyapi.io/eth) (don’t worry if you don’t understand what any of this means yet, we will explain it). + +> **Warning** +> +> 🚧 Deprecation Notice +> +> For the entirety of this guide, the Goerli test network is being used for creating and deploying a smart contract. However, please note that the Ethereum Foundation has announced that [Goerli will soon be deprecated](https://www.alchemy.com/blog/goerli-faucet-deprecation). +> +> We recommend you to use the [Sepolia](https://www.alchemy.com/overviews/sepolia-testnet) and [Sepolia faucet](https://sepoliafaucet.com/) for this tutorial. + +In [part 2](https://docs.alchemy.com/docs/interacting-with-a-smart-contract) of this tutorial we’ll go through how we can interact with our smart contract once it’s deployed here, and in [part 3](https://docs.alchemy.com/docs/submitting-your-smart-contract-to-etherscan) we’ll cover how to publish it on Etherscan. + +If you have questions at any point feel free to reach out in the [Alchemy Discord](https://discord.gg/gWuC7zB)! + +## Step 1: Connect to the Ethereum network + +There are many ways to make requests to the Ethereum chain. For simplicity, we’ll use a free account on Alchemy, a blockchain developer platform and API that allows us to communicate with the Ethereum chain without having to run our own nodes. The platform also has developer tools for monitoring and analytics that we’ll take advantage of in this tutorial to understand what’s going on under the hood in our smart contract deployment. If you don’t already have an Alchemy account, [you can sign up for free here](https://dashboard.alchemyapi.io/signup). + +## Step 2: Create your app (and API key) + +Once you’ve created an Alchemy account, you can generate an API key by creating an app. This will allow us to make requests to the Goerli test network. If you’re not familiar with testnets, check out [this page](/developers/docs/networks/). + +1. Navigate to the “Create App” page in your Alchemy Dashboard by hovering over “Apps” in the nav bar and clicking “Create App” + +![Hello world create app](./hello-world-create-app.png) + +2. Name your app “Hello World”, offer a short description, select “Staging” for the Environment (used for your app bookkeeping), and choose “Goerli” for your network. + +![create app view hello world](./create-app-view-hello-world.png) + +3. Click “Create app” and that’s it! Your app should appear in the table below. + +## Step 3: Create an Ethereum account (address) + +We need an Ethereum account to send and receive transactions. For this tutorial, we’ll use MetaMask, a virtual wallet in the browser used to manage your Ethereum account address. More on [transactions](/developers/docs/transactions/). + +You can download and create a MetaMask account for free [here](https://metamask.io/download). When you are creating an account, or if you already have an account, make sure to switch over to the “Goerli Test Network” in the upper right (so that we’re not dealing with real money). + +![metamask ropsten example](./metamask-ropsten-example.png) + +## Step 4: Add ether from a Faucet + +In order to deploy our smart contract to the test network, we’ll need some fake Eth. To get Eth you can go to the [Goerli faucet](https://goerlifaucet.com/) and log into your Alchemy account and enter your wallet address, then click “Send Me Eth.” It may take some time to receive your fake Eth due to network traffic. (At the time of writing this, it took around 30 minutes.) You should see Eth in your Metamask account soon after! + +## Step 5: Check your Balance + +To double check our balance is there, let’s make an [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) request using [Alchemy’s composer tool](https://composer.alchemyapi.io?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). This will return the amount of ETH in our wallet. After you input your MetaMask account address and click “Send Request”, you should see a response like this: + +```json + +``` + +> **NOTE:** This result is in wei not ETH. Wei is used as the smallest denomination of ether. The conversion from wei to ETH is: 1 eth = 1018 wei. So if we convert 0x2B5E3AF16B1880000 to decimal we get 5\*10¹⁸ which equals 5 ETH. +> +> Phew! Our fake money is all there . + +## Step 6: Initialize our project + +First, we’ll need to create a folder for our project. Navigate to your command line and type: + +``` +mkdir hello-world +cd hello-world +``` + +Now that we’re inside our project folder, we’ll use `npm init` to initialize the project. If you don’t already have npm installed, follow [these instructions](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm) (we’ll also need Node.js so download that too!). + +``` +npm init +``` + +It doesn’t really matter how you answer the installation questions, here is how we did it for reference: + +``` +package name: (hello-world) +version: (1.0.0) +description: hello world smart contract +entry point: (index.js) +test command: +git repository: +keywords: +author: +license: (ISC) +About to write to /Users/.../.../.../hello-world/package.json: + +, + "author": "", + "license": "ISC" +} +``` + +Approve the package.json and we’re good to go! + +## Step 7: Download [Hardhat](https://hardhat.org/getting-started/#overview) + +Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. It helps developers when building smart contracts and dapps locally before deploying to the live chain. + +Inside our `hello-world` project run: + +``` +npm install --save-dev hardhat +``` + +Check out this page for more details on [installation instructions](https://hardhat.org/getting-started/#overview). + +## Step 8: Create Hardhat project + +Inside our project folder run: + +``` +npx hardhat +``` + +You should then see a welcome message and option to select what you want to do. Select “create an empty hardhat.config.js”: + +``` +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 Welcome to Hardhat v2.0.11 👷‍? + +What do you want to do? … +Create a sample project +❯ Create an empty hardhat.config.js +Quit +``` + +This will generate a `hardhat.config.js` file for us which is where we’ll specify all of the set up for our project (on step 13). + +## Step 9: Add project folders + +To keep our project organized we’ll create two new folders. Navigate to the root directory of your project in your command line and type: + +``` +mkdir contracts +mkdir scripts +``` + +- `contracts/` is where we’ll keep our hello world smart contract code file +- `scripts/` is where we’ll keep scripts to deploy and interact with our contract + +## Step 10: Write our contract + +You might be asking yourself, when the heck are we going to write code?? Well, here we are, on step 10. + +Open up the hello-world project in your favorite editor (we like [VSCode](https://code.visualstudio.com/)). Smart contracts are written in a language called Solidity which is what we will use to write our HelloWorld.sol smart contract.‌ + +1. Navigate to the “contracts” folder and create a new file called HelloWorld.sol +2. Below is a sample Hello World smart contract from the Ethereum Foundation that we will be using for this tutorial. Copy and paste in the contents below into your HelloWorld.sol file, and be sure to read the comments to understand what this contract does: + +```solidity +// Specifies the version of Solidity, using semantic versioning. +// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +pragma solidity ^0.7.0; + +// Defines a contract named `HelloWorld`. +// A contract is a collection of functions and data (its state). Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +contract HelloWorld + + // A public function that accepts a string argument and updates the `message` storage variable. + function update(string memory newMessage) public +} +``` + +This is a super simple smart contract that stores a message upon creation and can be updated by calling the `update` function. + +## Step 11: Connect MetaMask & Alchemy to your project + +We’ve created a MetaMask wallet, Alchemy account, and written our smart contract, now it’s time to connect the three. + +Every transaction sent from your virtual wallet requires a signature using your unique private key. To provide our program with this permission, we can safely store our private key (and Alchemy API key) in an environment file. + +> To learn more about sending transactions, check out [this tutorial](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) on sending transactions using web3. + +First, install the dotenv package in your project directory: + +``` +npm install dotenv --save +``` + +Then, create a `.env` file in the root directory of our project, and add your MetaMask private key and HTTP Alchemy API URL to it. + +- Follow [these instructions](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key) to export your private key +- See below to get HTTP Alchemy API URL + +![get alchemy api key](./get-alchemy-api-key.gif) + +Copy Alchemy API URL + +Your `.env` should look like this: + +``` +API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" +PRIVATE_KEY = "your-metamask-private-key" +``` + +To actually connect these to our code, we’ll reference these variables in our `hardhat.config.js` file on step 13. + + +Don't commit .env! Please make sure never to share or expose your .env file with anyone, as you are compromising your secrets in doing so. If you are using version control, add your .env to a gitignore file. + + +## Step 12: Install Ethers.js + +Ethers.js is a library that makes it easier to interact and make requests to Ethereum by wrapping [standard JSON-RPC methods](/developers/docs/apis/json-rpc/) with more user friendly methods. + +Hardhat makes it super easy to integrate [Plugins](https://hardhat.org/plugins/) for additional tooling and extended functionality. We’ll be taking advantage of the [Ethers plugin](https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html) for contract deployment ([Ethers.js](https://github.com/ethers-io/ethers.js/) has some super clean contract deployment methods). + +In your project directory type: + +``` +npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" +``` + +We’ll also require ethers in our `hardhat.config.js` in the next step. + +## Step 13: Update hardhat.config.js + +We’ve added several dependencies and plugins so far, now we need to update `hardhat.config.js` so that our project knows about all of them. + +Update your `hardhat.config.js` to look like this: + +``` +require('dotenv').config(); + +require("@nomiclabs/hardhat-ethers"); +const = process.env; + +/** +* @type import('hardhat/config').HardhatUserConfig +*/ +module.exports = , + goerli: `] + } + }, +} +``` + +## Step 14: Compile our contract + +To make sure everything is working so far, let’s compile our contract. The `compile` task is one of the built-in hardhat tasks. + +From the command line run: + +``` +npx hardhat compile +``` + +You might get a warning about `SPDX license identifier not provided in source file` , but no need to worry about that — hopefully everything else looks good! If not, you can always message in the [Alchemy discord](https://discord.gg/u72VCg3). + +## Step 15: Write our deploy script + +Now that our contract is written and our configuration file is good to go, it’s time to write our contract deploy script. + +Navigate to the `scripts/` folder and create a new file called `deploy.js` , adding the following contents to it: + +``` +async function main() + +main() + .then(() => process.exit(0)) + .catch(error => ); +``` + +Hardhat does an amazing job of explaining what each of these lines of code does in their [Contracts tutorial](https://hardhat.org/tutorial/testing-contracts.html#writing-tests), we’ve adopted their explanations here. + +``` +const HelloWorld = await ethers.getContractFactory("HelloWorld"); +``` + +A `ContractFactory` in ethers.js is an abstraction used to deploy new smart contracts, so `HelloWorld` here is a factory for instances of our hello world contract. When using the `hardhat-ethers` plugin `ContractFactory` and `Contract` instances are connected to the first signer by default. + +``` +const hello_world = await HelloWorld.deploy(); +``` + +Calling `deploy()` on a `ContractFactory` will start the deployment, and return a `Promise` that resolves to a `Contract`. This is the object that has a method for each of our smart contract functions. + +## Step 16: Deploy our contract + +We’re finally ready to deploy our smart contract! Navigate to the command line and run: + +``` +npx hardhat run scripts/deploy.js --network goerli +``` + +You should then see something like: + +``` +Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +``` + +If we go to the [Goerli etherscan](https://goerli.etherscan.io/) and search for our contract address we should able to see that it has been deployed successfully. The transaction will look something like this: + +![etherscan contract](./etherscan-contract.png) + +The `From` address should match your MetaMask account address and the To address will say “Contract Creation” but if we click into the transaction we’ll see our contract address in the `To` field: + +![etherscan transaction](./etherscan-transaction.png) + +Congrats! You just deployed a smart contract to the Ethereum chain 🎉 + +To understand what’s going on under the hood, let’s navigate to the Explorer tab in our [Alchemy dashboard](https://dashboard.alchemyapi.io/explorer). If you have multiple Alchemy apps make sure to filter by app and select “Hello World”. +![hello world explorer](./hello-world-explorer.png) + +Here you’ll see a handful of JSON-RPC calls that Hardhat/Ethers made under the hood for us when we called the `.deploy()` function. Two important ones to call out here are [`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction), which is the request to actually write our contract onto the Goerli chain, and [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash) which is a request to read information about our transaction given the hash (a typical pattern when +transactions). To learn more about sending transactions, check out this tutorial on [sending transactions using Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) + +That’s all for part 1 of this tutorial, in part 2 we’ll actually [interact with our smart contract](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#part-2-interact-with-your-smart-contract) by updated our initial message, and in part 3 we’ll [publish our smart contract to Etherscan](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#optional-part-3-publish-your-smart-contract-to-etherscan) so everyone will know how to interact with it. + +**Want to learn more about Alchemy? Check out our [website](https://alchemyapi.io/eth). Never want to miss an update? Subscribe to our newsletter [here](https://www.alchemyapi.io/newsletter)! Be sure to also follow our [Twitter](https://twitter.com/alchemyplatform) and join our [Discord](https://discord.com/invite/u72VCg3)**. + +--- + +## Developers > Tutorials > How To Implement An Erc721 Market + +In this article, I’m going to show you how to code Craigslist for the Ethereum blockchain. + +Before Gumtree, Ebay and Craigslist, classified boards were mostly made of cork or paper. There were classifieds boards in school corridors, newspapers, streetlights, storefronts. + +All that changed with the internet. The number of people that could see a specific classified board multiplied by many orders of magnitude. With that, the markets they represent became much more efficient and scaled to global size. Ebay is a massive business which traces its origins to these physical classifieds boards. + +With blockchain these markets are set to change once more, let me show you how. + +## Monetization + +The business model of a public blockchain classifieds board will need to be different from that of Ebay and company. + +First, there is [the decentralization angle](/developers/docs/web2-vs-web3/). Existing platforms need to maintain their own servers. A decentralized platform is maintained by its users, so the cost of running the core platform drops to zero for the platform owner. + +Then there is the front end, the website or interface that gives access to the platform. Here there are many options. The platform owners can restrict access and force everyone to use their interface, charging a fee. The platform owners can also decide to open access (Power to the People!) and let anyone build interfaces to the platform. Or the owners could decide any approach in the middle of those extremes. + +_Business leaders with more vision than I will know how to monetize this. All I see is that this is different from the status quo and probably profitable._ + +Furthermore, there is the automation and payments angle. Some things can be very [effectively tokenized](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com) and traded in a classifieds board. Tokenized assets are easily transferred in a blockchain. Highly complex payment methods can be easily implemented in a blockchain. + +I’m just smelling a business opportunity here. A classifieds board with no running costs can easily be implemented, with complex payment paths included in each transaction. I’m sure someone will come up with an idea about what to use this for. + +I’m just happy building it. Let’s have a look at the code. + +## Implementation + +Some time ago we started an [open source repository](https://github.com/HQ20/contracts?ref=hackernoon.com) with business case example implementations and other goodies, please have a look. + +The code for this [Ethereum Classifieds Board](https://github.com/HQ20/contracts/tree/master/contracts/classifieds?ref=hackernoon.com) is there, please use it and abuse it. Just be aware that the code hasn’t been audited and you need to do your own due diligence before letting money go into it. + +The basics of the board are not complex. All the adverts in the board will be just a struct with a few fields: + +```solidity +struct Trade +``` + +So there is someone posting the advert. An item for sale. A price for the item. The status of the trade which can be open, executed or cancelled. + +All these trades will be kept in a mapping. Because everything in Solidity seems to be a mapping. Also because it is convenient. + +```solidity +mapping(uint256 => Trade) public trades; +``` + +Using a mapping just means that we have to come up with an id for each advert before posting it, and we will need to know the id of an advert before we can operate on it. There are multiple ways of dealing with this either in the smart contract or in the front-end. Please ask if you need some pointers. + +Next comes the question of what are those items we deal with, and what is this currency that is used to pay for the transaction. + +For the items, we are just going to ask that they implement the [ERC-721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol?ref=hackernoon.com) interface, which really is just a way of representing real world items in a blockchain, although it [works best with digital assets](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com). We are going to specify our own ERC721 contract in the constructor, meaning that any assets in our classifieds board need to have been tokenized beforehand. + +For the payments, we are going to do something similar. Most blockchain projects define their own [ERC-20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol?ref=hackernoon.com) cryptocurrency. Some others prefer to use a mainstream one like DAI. In this classifieds board, you just need to decide on construction what your currency will be. Easy. + +```solidity +constructor ( + address _currencyTokenAddress, address _itemTokenAddress +) public +``` + +We are getting there. We’ve got adverts, items for trade and a currency for payments. To make an advert means to put an item in escrow to show both that you have it and that you haven’t posted it twice, possibly in a different board. + +The code below does exactly that. Puts the item in escrow, creates the advert, does some housekeeping. + +```solidity +function openTrade(uint256 _item, uint256 _price) + public +); + tradeCounter += 1; + emit TradeStatusChange(tradeCounter - 1, "Open"); +} +``` + +To accept the trade means to choose an advert (trade), pay the price, receive the item. The code below retrieves a trade. Checks it’s available. Pays the item. Retrieves the item. Updates the advert. + +```solidity +function executeTrade(uint256 _trade) + public + +``` + +Finally, we have an option for sellers to back out of a trade before a buyer accepts it. In some models, adverts would instead be live for a period of time before they expire. Your choice, depending on the design of your market. + +The code is very similar to that used to execute a trade, only that there is no currency changing hands and the item goes back to the advert poster. + +```solidity +function cancelTrade(uint256 _trade) + public + +``` + +That’s it. You made it to the end of the implementation. It is quite surprising how compact some business concepts are when expressed in code, and this is one of those cases. Check the complete contract [in our repo](https://github.com/HQ20/contracts/blob/master/contracts/classifieds/Classifieds.sol). + +## Conclusion + +Classifieds boards are a common market configuration that scaled massively with the internet, becoming a hugely popular business model with a few monopolistic winners. + +Classifieds boards also happen to be an easy tool to replicate in a blockchain environment, with very specific features that will make a challenge to the existing giants possible. + +In this article, I made an attempt to bridge the business reality of a classifieds board business with the technological implementation. This knowledge should help you to create a vision and a roadmap for implementation if you have the right skills. + +As always, if you are out to build anything fun and would welcome some advice, please [drop me a line](https://albertocuesta.es/)! I’m always happy to help. + +--- + +## Developers > Tutorials > How To Mint An Nft + +[Beeple](https://www.nytimes.com/2021/03/11/arts/design/nft-auction-christies-beeple.html): $69 Million +[3LAU](https://www.forbes.com/sites/abrambrown/2021/03/03/3lau-nft-nonfungible-tokens-justin-blau/?sh=5f72ef64643b): $11 Million +[Grimes](https://www.theguardian.com/music/2021/mar/02/grimes-sells-digital-art-collection-non-fungible-tokens): $6 Million + +All of them minted their NFTs using Alchemy’s powerful API. In this tutorial, we’ll teach you how to do the same in \ _Interplanetary File System (IPFS) is a decentralized protocol and peer-to-peer network for storing and sharing data in a distributed file system._ + +We will use Pinata, a convenient IPFS API and toolkit, to store our NFT asset and metadata to ensure our NFT is truly decentralized. If you don’t have a Pinata account, sign up for a free account [here](https://app.pinata.cloud) and complete the steps to verify your email. + +Once you’ve created an account: + +- Navigate to the “Files” page and click the blue "Upload" button at the top-left of the page. + +- Upload an image to Pinata — this will be the image asset for your NFT. Feel free to name the asset whatever you wish + +- After you upload, you'll see the file info in the table on the "Files" page. You'll also see a CID column. You can copy the CID by clicking the copy button next to it. You can view your upload at: `https://gateway.pinata.cloud/ipfs/`. You can find the image we used on IPFS [here](https://gateway.pinata.cloud/ipfs/QmZdd5KYdCFApWn7eTZJ1qgJu18urJrP9Yh1TZcZrZxxB5), for example. + +For the more visual learners, the steps above are summarized here: + +![How to upload your image to Pinata](./instructionsPinata.gif) + +Now, we’re going to want to upload one more document to Pinata. But before we do that, we need to create it! + +In your root directory, make a new file called `nft-metadata.json` and add the following json code: + +```json +, + + ], + "description": "The world's most adorable and sensitive pup.", + "image": "ipfs://QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb", + "name": "Ramses" +} +``` + +Feel free to change the data in the json. You can remove or add to the attributes section. Most importantly, make sure image field points to the location of your IPFS image — otherwise, your NFT will include a photo of a (very cute!) dog. + +Once you’re done editing the JSON file, save it and upload it to Pinata, following the same steps we did for uploading the image. + +![How to upload your nft-metadata.json to Pinata](./uploadPinata.gif) + +## Step 5: Create an instance of your contract + +Now, to interact with our contract, we need to create an instance of it in our code. To do so we’ll need our contract address which we can get from the deployment or [Etherscan](https://sepolia.etherscan.io/) by looking up the address you used to deploy the contract. + +![View your contract address on Etherscan](./view-contract-etherscan.png) + +In the above example, our contract address is 0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778. + +Next we will use the Web3 [contract method](https://docs.web3js.org/api/web3-eth-contract/class/Contract) to create our contract using the ABI and address. In your `mint-nft.js` file, add the following: + +```js +const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" + +const nftContract = new web3.eth.Contract(contract.abi, contractAddress) +``` + +## Step 6: Update the `.env` file + +Now, in order to create and send transactions to the Ethereum chain, we’ll use your public ethereum account address to get the account nonce (will explain below). + +Add your public key to your `.env` file — if you completed part 1 of the tutorial, our `.env` file should now look like this: + +```js +API_URL = "https://eth-sepolia.g.alchemy.com/v2/your-api-key" +PRIVATE_KEY = "your-private-account-address" +PUBLIC_KEY = "your-public-account-address" +``` + +## Step 7: Create your transaction + +First, let’s define a function named `mintNFT(tokenData)` and create our transaction by doing the following: + +1. Grab your _PRIVATE_KEY_ and _PUBLIC_KEY_ from the `.env` file. + +1. Next, we’ll need to figure out the account nonce. The nonce specification is used to keep track of the number of transactions sent from your address — which we need for security purposes and to prevent [replay attacks](https://docs.alchemyapi.io/resources/blockchain-glossary#account-nonce). To get the number of transactions sent from your address, we use [getTransactionCount](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_gettransactioncount). + +1. Finally we’ll set up our transaction with the following info: + +- `'from': PUBLIC_KEY` — The origin of our transaction is our public address + +- `'to': contractAddress` — The contract we wish to interact with and send the transaction + +- `'nonce': nonce` — The account nonce with the number of transactions sent from our address + +- `'gas': estimatedGas` — The estimated gas needed to complete the transaction + +- `'data': nftContract.methods.mintNFT(PUBLIC_KEY, md).encodeABI()` — The computation we wish to perform in this transaction — which in this case is minting a NFT + +Your `mint-nft.js` file should look like this now: + +```js + require('dotenv').config(); + const API_URL = process.env.API_URL; + const PUBLIC_KEY = process.env.PUBLIC_KEY; + const PRIVATE_KEY = process.env.PRIVATE_KEY; + + const = require("@alch/alchemy-web3"); + const web3 = createAlchemyWeb3(API_URL); + + const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json"); + const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"; + const nftContract = new web3.eth.Contract(contract.abi, contractAddress); + + async function mintNFT(tokenURI) ; + }​ +``` + +## Step 8: Sign the transaction + +Now that we’ve created our transaction, we need to sign it in order to send it off. Here is where we’ll use our private key. + +`web3.eth.sendSignedTransaction` will give us the transaction hash, which we can use to make sure our transaction was mined and didn't get dropped by the network. You'll notice in the transaction signing section, we've added some error checking so we know if our transaction successfully went through. + +```js +require("dotenv").config() +const API_URL = process.env.API_URL +const PUBLIC_KEY = process.env.PUBLIC_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY + +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(API_URL) + +const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json") +const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" +const nftContract = new web3.eth.Contract(contract.abi, contractAddress) + +async function mintNFT(tokenURI) + + const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY) + signPromise + .then((signedTx) => else + } + ) + }) + .catch((err) => ) +} +``` + +## Step 9: Call `mintNFT` and run node `mint-nft.js` + +Remember the `metadata.json` you uploaded to Pinata? Get its hashcode from Pinata and pass the following as parameter to the function `mintNFT` `https://gateway.pinata.cloud/ipfs/` + +Here’s how to get the hashcode: + +![How to get your nft metadata hashcode on Pinata](./metadataPinata.gif)_How to get your nft metadata hashcode on Pinata_ + +> Double check that the hashcode you copied links to your **metadata.json** by loading `https://gateway.pinata.cloud/ipfs/` into a separate window. The page should look similar to the screenshot below: + +![Your page should display the json metadata](./metadataJSON.png)_Your page should display the json metadata_ + +Altogether, your code should look something like this: + +```js +require("dotenv").config() +const API_URL = process.env.API_URL +const PUBLIC_KEY = process.env.PUBLIC_KEY +const PRIVATE_KEY = process.env.PRIVATE_KEY + +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(API_URL) + +const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json") +const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" +const nftContract = new web3.eth.Contract(contract.abi, contractAddress) + +async function mintNFT(tokenURI) + + const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY) + signPromise + .then((signedTx) => else + } + ) + }) + .catch((err) => ) +} + +mintNFT("ipfs://QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP") +``` + +Now, run `node scripts/mint-nft.js` to deploy your NFT. After a couple of seconds, you should see a response like this in your terminal: + + The hash of your transaction is: 0x301791fdf492001fcd9d5e5b12f3aa1bbbea9a88ed24993a8ab2cdae2d06e1e8 + + Check Alchemy's Mempool to view the status of your transaction! + +Next, visit your [Alchemy mempool](https://dashboard.alchemyapi.io/mempool) to see the status of your transaction (whether it’s pending, mined, or got dropped by the network). If your transaction got dropped, it’s also helpful to check [Sepolia Etherscan](https://sepolia.etherscan.io/) and search for your transaction hash. + +![View your NFT transaction hash on Etherscan](./view-nft-etherscan.png)_View your NFT transaction hash on Etherscan_ + +And that’s it! You’ve now deployed AND minted with a NFT on the Ethereum blockchain + +Using the `mint-nft.js` you can mint as many NFTs as your heart (and wallet) desires! Just be sure to pass in a new tokenURI describing the NFT's metadata (otherwise, you'll just end up making a bunch of identical ones with different IDs). + +Presumably, you’d like to be able to show off your NFT in your wallet — so be sure to check out [Part 3: How to View Your NFT in Your Wallet](/developers/tutorials/how-to-view-nft-in-metamask/)! + +--- + +## Developers > Tutorials > How To Mock Solidity Contracts For Testing + +[Mock objects](https://wikipedia.org/wiki/Mock_object) are a common design pattern in object-oriented programming. Coming from the old French word 'mocquer' with the meaning of 'making fun of', it evolved to 'imitating something real' which is actually what we are doing in programming. Please only make fun of your smart contracts if you want to, but mock them whenever you can. It makes your life easier. + +## Unit-testing contracts with mocks + +Mocking a contract essentially means creating a second version of that contract which behaves very similar to the original one, but in a way that can be easily controlled by the developer. You often end up with complex contracts where you only want to [unit-test small parts of the contract](/developers/docs/smart-contracts/testing/). The problem is what if testing this small part requires a very specific contract state that is difficult to end up in? + +You could write complex test setup logic every time that brings in the contract in the required state or you write a mock. Mocking a contract is easy with inheritance. Simply create a second mock contract that inherits from the original one. Now you can override functions to your mock. Let us see it with an example. + +## Example: Private ERC20 + +We use an example ERC-20 contract that has an initial private time. The owner can manage private users and only those will be allowed to receive tokens at the beginning. Once a certain time has passed, everyone will be allowed to use the tokens. If you are curious, we are using the [`_beforeTokenTransfer`](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) hook from the new OpenZeppelin contracts v3. + +```solidity +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract PrivateERC20 is ERC20, Ownable + + function addUser(address user) external onlyOwner + + function isPublic() public view returns (bool) + + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override + + function _validRecipient(address to) private view returns (bool) + + return isPrivateUser[to]; + } +} +``` + +And now let's mock it. + +```solidity +pragma solidity ^0.6.0; +import "../PrivateERC20.sol"; + +contract PrivateERC20Mock is PrivateERC20 + + function setIsPublic(bool isPublic) external + + function isPublic() public view returns (bool) +} +``` + +You will get one of the following error messages: + +- `PrivateERC20Mock.sol: TypeError: Overriding function is missing "override" specifier.` +- `PrivateERC20.sol: TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?.` + +Since we are using the new 0.6 Solidity version, we have to add the `virtual` keyword for functions that can be overridden and override for the overriding function. So let us add those to both `isPublic` functions. + +Now in your unit tests, you can use `PrivateERC20Mock` instead. When you want to test the behavior during the private usage time, use `setIsPublic(false)` and likewise `setIsPublic(true)` for testing the public usage time. Of course in our example, we could just use [time helpers](https://docs.openzeppelin.com/test-helpers/0.5/api#increase) to change the times accordingly as well. But the idea of mocking should be clear now and you can imagine scenarios where it is not as easy as simply advancing the time. + +## Mocking many contracts + +It can become messy if you have to create another contract for every single mock. If this bothers you, you can take a look at the [MockContract](https://github.com/gnosis/mock-contract) library. It allows you to override and change behaviors of contracts on-the-fly. However, it works only for mocking calls to another contract, so it would not work for our example. + +## Mocking can be even more powerful + +The powers of mocking do not end there. + +- Adding functions: Not only overriding a specific function is useful, but also just adding additional functions. A good example for tokens is just having an additional `mint` function to allow any user to get new tokens for free. +- Usage in testnets: When you deploy and test your contracts on testnets together with your dapp, consider using a mocked version. Avoid overriding functions unless you really have to. You want to test the real logic after all. But adding for example a reset function can be useful that simply resets the contract state to the beginning, no new deployment required. Obviously you would not want to have that in a Mainnet contract. + +--- + +## Developers > Tutorials > How To Use Echidna To Test Smart Contracts + +## Installation + +Echidna can be installed through docker or using the pre-compiled binary. + +### Echidna through docker + +```bash +docker pull trailofbits/eth-security-toolbox +docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox +``` + +_The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker_ + +Inside docker, run : + +```bash +solc-select 0.5.11 +cd /home/training +``` + +### Binary + +[https://github.com/crytic/echidna/releases/tag/v1.4.0.0](https://github.com/crytic/echidna/releases/tag/v1.4.0.0) + +## Introduction to property-based fuzzing + +Echidna is a property-based fuzzer, we described in our previous blogposts ([1](https://blog.trailofbits.com/2018/03/09/echidna-a-smart-fuzzer-for-ethereum/), [2](https://blog.trailofbits.com/2018/05/03/state-machine-testing-with-echidna/), [3](https://blog.trailofbits.com/2020/03/30/an-echidna-for-all-seasons/)). + +### Fuzzing + +[Fuzzing](https://wikipedia.org/wiki/Fuzzing) is a well-known technique in the security community. It consists of generating inputs that are more or less random to find bugs in the program. Fuzzers for traditional software (such as [AFL](http://lcamtuf.coredump.cx/afl/) or [LibFuzzer](https://llvm.org/docs/LibFuzzer.html)) are known to be efficient tools to find bugs. + +Beyond the purely random generation of inputs, there are many techniques and strategies to generate good inputs, including: + +- Obtain feedback from each execution and guide generation using it. For example, if a newly generated input leads to the discovery of a new path, it can make sense to generate new inputs closes to it. +- Generating the input respecting a structural constraint. For example, if your input contains a header with a checksum, it will make sense to let the fuzzer generates input validating the checksum. +- Using known inputs to generate new inputs: if you have access to a large dataset of valid input, your fuzzer can generate new inputs from them, rather than starting from scratch its generation. These are usually called _seeds_. + +### Property-based fuzzing + +Echidna belongs to a specific family of fuzzer: property-based fuzzing heavily inspired by [QuickCheck](https://wikipedia.org/wiki/QuickCheck). In contrast to classic fuzzer that will try to find crashes, Echidna will try to break user-defined invariants. + +In smart contracts, invariants are Solidity functions, that can represent any incorrect or invalid state that the contract can reach, including: + +- Incorrect access control: the attacker became the owner of the contract. +- Incorrect state machine: the tokens can be transferred while the contract is paused. +- Incorrect arithmetic: the user can underflow its balance and get unlimited free tokens. + +### Testing a property with Echidna + +We will see how to test a smart contract with Echidna. The target is the following smart contract [`token.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/token.sol): + +```solidity +contract Token + function consume() public + function backdoor() public +} +``` + +We will make the assumption that this token must have the following properties: + +- Anyone can have at maximum 1000 tokens +- The token cannot be transferred (it is not an ERC20 token) + +### Write a property + +Echidna properties are Solidity functions. A property must: + +- Have no argument +- Return `true` if it is successful +- Have its name starting with `echidna` + +Echidna will: + +- Automatically generate arbitrary transactions to test the property. +- Report any transactions leading a property to return `false` or throw an error. +- Discard side-effect when calling a property (i.e. if the property changes a state variable, it is discarded after the test) + +The following property checks that the caller has no more than 1000 tokens: + +```solidity +function echidna_balance_under_1000() public view returns(bool) + +The following summarizes the run of echidna on our example: + +```solidity +contract Incrementor +} +``` + +```bash +echidna-test assert.sol --config config.yaml +Analyzing contract: assert.sol:Incrementor +assertion in inc: failed!💥 + Call sequence, shrinking (2596/5000): + inc(21711016731996786641919559689128982722488122124807605757398297001483711807488) + inc(7237005577332262213973186563042994240829374041602535252466099000494570602496) + inc(86844066927987146567678238756515930889952488499230423029593188005934847229952) + +Seed: 1806480648350826486 +``` + +Echidna found that the assertion in `inc` can fail if this function is called multiple times with large arguments. + +## Collecting and modifying an Echidna corpus + +We will see how to collect and use a corpus of transactions with Echidna. The target is the following smart contract [`magic.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/magic.sol): + +```solidity +contract C + + function echidna_magic_values() public returns (bool) + +} +``` + +This small example forces Echidna to find certain values to change a state variable. This is hard for a fuzzer +(it is recommended to use a symbolic execution tool like [Manticore](https://github.com/trailofbits/manticore)). +We can run Echidna to verify this: + +```bash +echidna-test magic.sol +... + +echidna_magic_values: passed! 🎉 + +Seed: 2221503356319272685 +``` + +However, we can still use Echidna to collect corpus when running this fuzzing campaign. + +### Collecting a corpus + +To enable the corpus collection, create a corpus directory: + +```bash +mkdir corpus-magic +``` + +And an [Echidna configuration file](https://github.com/crytic/echidna/wiki/Config) `config.yaml`: + +```yaml +coverage: true +corpusDir: "corpus-magic" +``` + +Now we can run our tool and check the collected corpus: + +```bash +echidna-test magic.sol --config config.yaml +``` + +Echidna still cannot find the correct magic values, but we can take look to the corpus it collected. +For instance, one of these files was: + +```json +[ + , + , + , + + ] + ] + }, + "_gasprice'": "0xa904461f1" + } +] +``` + +Clearly, this input will not trigger the failure in our property. However, in the next step, we will see how to modify it for that. + +### Seeding a corpus + +Echidna needs some help in order to deal with the `magic` function. We are going to copy and modify the input to use suitable +parameters for it: + +```bash +cp corpus/2712688662897926208.txt corpus/new.txt +``` + +We will modify `new.txt` to call `magic(42,129,333,0)`. Now, we can re-run Echidna: + +```bash +echidna-test magic.sol --config config.yaml +... +echidna_magic_values: failed!💥 + Call sequence: + magic(42,129,333,0) + + +Unique instructions: 142 +Unique codehashes: 1 +Seed: -7293830866560616537 + +``` + +This time, it found that the property is violated immediately. + +## Finding transactions with high gas consumption + +We will see how to find the transactions with high gas consumption with Echidna. The target is the following smart contract: + +```solidity +contract C + + function f(uint x, uint y, uint8 times) public + + function echidna_test() public returns (bool) + +} +``` + +Here `expensive` can have a large gas consumption. + +Currently, Echidna always need a property to test: here `echidna_test` always returns `true`. +We can run Echidna to verify this: + +``` +echidna-test gas.sol +... +echidna_test: passed! 🎉 + +Seed: 2320549945714142710 +``` + +### Measuring Gas Consumption + +To enable the gas consumption with Echidna, create a configuration file `config.yaml`: + +```yaml +estimateGas: true +``` + +In this example, we will also reduce the size of the transaction sequence to make the results easier to understand: + +```yaml +seqLen: 2 +estimateGas: true +``` + +### Run Echidna + +Once we have the configuration file created, we can run Echidna like this: + +```bash +echidna-test gas.sol --config config.yaml +... +echidna_test: passed! 🎉 + +f used a maximum of 1333608 gas + Call sequence: + f(42,123,249) Gas price: 0x10d5733f0a Time delay: 0x495e5 Block delay: 0x88b2 + +Unique instructions: 157 +Unique codehashes: 1 +Seed: -325611019680165325 + +``` + +- The gas shown is an estimation provided by [HEVM](https://github.com/dapphub/dapptools/tree/master/src/hevm#hevm-). + +### Filtering Out Gas-Reducing Calls + +The tutorial on **filtering functions to call during a fuzzing campaign** above shows how to +remove some functions from your testing. +This can be critical for getting an accurate gas estimate. +Consider the following example: + +```solidity +contract C + function pop() public + function clear() public + function check() public + function echidna_test() public returns (bool) +} +``` + +If Echidna can call all the functions, it won't easily find transactions with high gas cost: + +``` +echidna-test pushpop.sol --config config.yaml +... +pop used a maximum of 10746 gas +... +check used a maximum of 23730 gas +... +clear used a maximum of 35916 gas +... +push used a maximum of 40839 gas +``` + +That's because the cost depends on the size of `addrs` and random calls tend to leave the array almost empty. +Blacklisting `pop` and `clear`, however, gives us much better results: + +```yaml +filterBlacklist: true +filterFunctions: ["pop", "clear"] +``` + +``` +echidna-test pushpop.sol --config config.yaml +... +push used a maximum of 40839 gas +... +check used a maximum of 1484472 gas +``` + +### Summary: Finding transactions with high gas consumption + +Echidna can find transactions with high gas consumption using the `estimateGas` configuration option: + +```yaml +estimateGas: true +``` + +```bash +echidna-test contract.sol --config config.yaml +... +``` + +Echidna will report a sequence with the maximum gas consumption for every function, once the fuzzing campaign is over. + +--- + +## Developers > Tutorials > How To Use Manticore To Find Smart Contract Bugs + +The aim of this tutorial is to show how to use Manticore to automatically find bugs in smart contracts. + +## Installation + +Manticore requires >= python 3.6. It can be installed through pip or using docker. + +### Manticore through docker + +```bash +docker pull trailofbits/eth-security-toolbox +docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox +``` + +_The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker_ + +Inside docker, run: + +```bash +solc-select 0.5.11 +cd /home/trufflecon/ +``` + +### Manticore through pip + +```bash +pip3 install --user manticore +``` + +solc 0.5.11 is recommended. + +### Running a script + +To run a python script with python 3: + +```bash +python3 script.py +``` + +## Introduction to dynamic symbolic execution + +### Dynamic Symbolic Execution in a Nutshell + +Dynamic symbolic execution (DSE) is a program analysis technique that explores a state space with a high degree of semantic awareness. This technique is based on the discovery of "program paths", represented as mathematical formulas called `path predicates`. Conceptually, this technique operates on path predicates in two steps: + +1. They are constructed using constraints on the program's input. +2. They are used to generate program inputs that will cause the associated paths to execute. + +This approach produces no false positives in the sense that all identified program states can be triggered during concrete execution. For example, if the analysis finds an integer overflow, it is guaranteed to be reproducible. + +### Path Predicate Example + +To get an insight of how DSE works, consider the following example: + +```solidity +function f(uint a) + +} +``` + +As `f()` contains two paths, a DSE will construct two different path predicates: + +- Path 1: `a == 65` +- Path 2: `Not (a == 65)` + +Each path predicate is a mathematical formula that can be given to a so-called [SMT solver](https://wikipedia.org/wiki/Satisfiability_modulo_theories), which will try to solve the equation. For `Path 1`, the solver will say that the path can be explored with `a = 65`. For `Path 2`, the solver can give `a` any value other than 65, for example `a = 0`. + +### Verifying properties + +Manticore allows a full control over all the execution of each path. As a result, it allows you to add arbitrary constraints to almost anything. This control allows for the creation of properties on the contract. + +Consider the following example: + +```solidity +function unsafe_add(uint a, uint b) returns(uint c) +``` + +Here there is only one path to explore in the function: + +- Path 1: `c = a + b` + +Using Manticore, you can check for overflow, and add constraints to the path predicate: + +- `c = a + b AND (c =a); + require(c>=b); + return c; +} +``` + +The associated formula with overflow check would be: + +- `c = a + b AND (c >= a) AND (c=>b) AND (c =0.4.24 =0.4.24 =0.4.24 =0.4.24 <0.6.0; +contract Simple + } +} +``` + +### Operators + +The [Operators](https://github.com/trailofbits/manticore/blob/master/manticore/core/smtlib/operators.py) module facilitates the manipulation of constraints, among other it provides: + +- Operators.AND, +- Operators.OR, +- Operators.UGT (unsigned greater than), +- Operators.UGE (unsigned greater than or equal to), +- Operators.ULT (unsigned lower than), +- Operators.ULE (unsigned lower than or equal to). + +To import the module use the following: + +```python +from manticore.core.smtlib import Operators +``` + +`Operators.CONCAT` is used to concatenate an array to a value. For example, the return_data of a transaction needs to be changed to a value to be checked against another value: + +```python +last_return = Operators.CONCAT(256, *last_return) +``` + +### Constraints + +You can use constraints globally or for a specific state. + +#### Global constraint + +Use `m.constrain(constraint)` to add a global constraint. +For example, you can call a contract from a symbolic address, and restraint this address to be specific values: + +```python +symbolic_address = m.make_symbolic_value() +m.constraint(Operators.OR(symbolic == 0x41, symbolic_address == 0x42)) +m.transaction(caller=user_account, + address=contract_account, + data=m.make_symbolic_buffer(320), + value=0) +``` + +#### State constraint + +Use [state.constrain(constraint)](https://manticore.readthedocs.io/en/latest/states.html?highlight=StateBase#manticore.core.state.StateBase.constrain) to add a constraint to a specific state. +It can be used to constrain the state after its exploration to check some property on it. + +### Checking Constraint + +Use `solver.check(state.constraints)` to know if a constraint is still feasible. +For example, the following will constraint symbolic_value to be different from 65 and check if the state is still feasible: + +```python +state.constrain(symbolic_var != 65) +if solver.check(state.constraints): + # state is feasible +``` + +### Summary: Adding Constraints + +Adding constraint to the previous code, we obtain: + +```python +from manticore.ethereum import ManticoreEVM +from manticore.core.smtlib.solver import Z3Solver + +solver = Z3Solver.instance() + +m = ManticoreEVM() + +with open("example.sol") as f: + source_code = f.read() + +user_account = m.create_account(balance=1000) +contract_account = m.solidity_create_contract(source_code, owner=user_account) + +symbolic_var = m.make_symbolic_value() +contract_account.f(symbolic_var) + +no_bug_found = True + +## Check if an execution ends with a REVERT or INVALID +for state in m.terminated_states: + last_tx = state.platform.transactions[-1] + if last_tx.result in ['REVERT', 'INVALID']: + # we do not consider the path were a == 65 + condition = symbolic_var != 65 + if m.generate_testcase(state, name="BugFound", only_if=condition): + print(f'Bug found, results are in ') + no_bug_found = False + +if no_bug_found: + print(f'No bug found') +``` + +All the code above you can find into the [`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py) + +--- + +## Developers > Tutorials > How To Use Slither To Find Smart Contract Bugs + +## How to use Slither + +The aim of this tutorial is to show how to use Slither to automatically find bugs in smart contracts. + +- [Installation](#installation) +- [Command line usage](#command-line) +- [Introduction to static analysis](#static-analysis): Brief introduction to static analysis +- [API](#api-basics): Python API description + +## Installation + +Slither requires Python >= 3.6. It can be installed through pip or using docker. + +Slither through pip: + +```bash +pip3 install --user slither-analyzer +``` + +Slither through docker: + +```bash +docker pull trailofbits/eth-security-toolbox +docker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolbox +``` + +_The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker_ + +Inside docker, run: + +```bash +solc-select 0.5.11 +cd /home/trufflecon/ +``` + +### Running a script + +To run a python script with python 3: + +```bash +python3 script.py +``` + +### Command line + +**Command line versus user-defined scripts.** Slither comes with a set of predefined detectors that find many common bugs. Calling Slither from the command line will run all the detectors, no detailed knowledge of static analysis needed: + +```bash +slither project_paths +``` + +In addition to detectors, Slither has code review capabilities through its [printers](https://github.com/crytic/slither#printers) and [tools](https://github.com/crytic/slither#tools). + +Use [crytic.io](https://github.com/crytic) to get access to private detectors and GitHub integration. + +## Static analysis + +The capabilities and design of the Slither static analysis framework has been described in blog posts ([1](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/), [2](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/)) and an [academic paper](https://github.com/trailofbits/publications/blob/master/papers/wetseb19.pdf). + +Static analysis exists in different flavors. You most likely realize that compilers like [clang](https://clang-analyzer.llvm.org/) and [gcc](https://lwn.net/Articles/806099/) depend on these research techniques, but it also underpins ([Infer](https://fbinfer.com/), [CodeClimate](https://codeclimate.com/), [FindBugs](http://findbugs.sourceforge.net/) and tools based on formal methods like [Frama-C](https://frama-c.com/) and [Polyspace](https://www.mathworks.com/products/polyspace.html). + +We won't be exhaustively reviewing static analysis techniques and researcher here. Instead, we'll focus on what is needed to understand how Slither works so you can more effectively use it to find bugs and understand code. + +- [Code representation](#code-representation) +- [Code analysis](#analysis) +- [Intermediate representation](#intermediate-representation) + +### Code representation + +In contrast to a dynamic analysis, which reasons about a single execution path, static analysis reasons about all the paths at once. To do so, it relies on a different code representation. The two most common ones are the abstract syntax tree (AST) and the control flow graph (CFG). + +### Abstract Syntax Trees (AST) + +AST are used every time the compiler parses code. It is probably the most basic structure upon which static analysis can be performed. + +In a nutshell, an AST is a structured tree where, usually, each leaf contains a variable or a constant and internal nodes are operands or control flow operations. Consider the following code: + +```solidity +function safeAdd(uint a, uint b) pure internal returns(uint) + +If your analysis navigates through the CFG and follows the edges, you are likely to see already visited nodes. For example, if a loop is presented as shown below: + +```solidity +for(uint i; i < range; ++) +``` + +Your analysis will need to know when to stop. There are two main strategies here: (1) iterate on each node a finite number of times, (2) compute a so-called _fixpoint_. A fixpoint basically means that analyzing this node does not provide any meaningful information. + +An example of fixpoint used can be found in the reentrancy detectors: Slither explores the nodes, and look for externals calls, write and read to storage. Once it has reached a fixpoint ([reentrancy.py#L125-L131](https://github.com/crytic/slither/blob/master/slither/detectors/reentrancy/reentrancy.py#L125-L131)), it stops the exploration, and analyze the results to see if a reentrancy is present, through different reentrancy patterns ([reentrancy_benign.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_benign.py), [reentrancy_read_before_write.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_read_before_write.py), [reentrancy_eth.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_eth.py)). + +Writing analyses using efficient fixed point computation requires a good understanding of how the analysis propagates its information. + +### Intermediate representation + +An intermediate representation (IR) is a language meant to be more amenable to static analysis than the original one. Slither translates Solidity to its own IR: [SlithIR](https://github.com/crytic/slither/wiki/SlithIR). + +Understanding SlithIR is not necessary if you only want to write basic checks. However, it will come in handy if you plan to write advanced semantic analyses. The [SlithIR](https://github.com/crytic/slither/wiki/Printer-documentation#slithir) and [SSA](https://github.com/crytic/slither/wiki/Printer-documentation#slithir-ssa) printers will help you to understand how the code is translated. + +## API Basics + +Slither has an API that lets you explore basic attributes of the contract and its functions. + +To load a codebase: + +```python +from slither import Slither +slither = Slither('/path/to/project') + +``` + +### Exploring contracts and functions + +A `Slither` object has: + +- `contracts (list(Contract)`: list of contracts +- `contracts_derived (list(Contract)`: list of contracts that are not inherited by another contract (subset of contracts) +- `get_contract_from_name (str)`: Return a contract from its name + +A `Contract` object has: + +- `name (str)`: Name of the contract +- `functions (list(Function))`: List of functions +- `modifiers (list(Modifier))`: List of functions +- `all_functions_called (list(Function/Modifier))`: List of all the internal functions reachable by the contract +- `inheritance (list(Contract))`: List of inherited contracts +- `get_function_from_signature (str)`: Return a Function from its signature +- `get_modifier_from_signature (str)`: Return a Modifier from its signature +- `get_state_variable_from_name (str)`: Return a StateVariable from its name + +A `Function` or a `Modifier` object has: + +- `name (str)`: Name of the function +- `contract (contract)`: the contract where the function is declared +- `nodes (list(Node))`: List of the nodes composing the CFG of the function/modifier +- `entry_point (Node)`: Entry point of the CFG +- `variables_read (list(Variable))`: List of variables read +- `variables_written (list(Variable))`: List of variables written +- `state_variables_read (list(StateVariable))`: List of state variables read (subset of variables`read) +- `state_variables_written (list(StateVariable))`: List of state variables written (subset of variables`written) + +--- + +## Developers > Tutorials > How To Use Tellor As Your Oracle + +Pop Quiz: Your protocol is just about finished, but it needs an oracle to get access to offchain data...What do you do? + +## (Soft) Prerequisites + +This post aims to make accessing an oracle feed as simple and straightforward as possible. That said, we're assuming the following about your coding skill-level to focus on the oracle aspect. + +Assumptions: + +- you can navigate a terminal +- you have npm installed +- you know how to use npm to manage dependencies + +Tellor is a live and open-sourced oracle ready for implementation. This beginner's guide is here to showcase the ease with which one can get up and running with Tellor, providing your project with a fully decentralized and censorship-resistant oracle. + +## Overview + +Tellor is an oracle system where parties can request the value of an offchain data point (e.g. BTC/USD) and reporters compete to add this value to an onchain data-bank, accessible by all Ethereum smart contracts. The inputs to this data-bank are secured by a network of staked reporters. Tellor utilizes crypto-economic incentive mechanisms, rewarding honest data submissions by reporters and punishing bad actors through the issuance of Tellor’s token, Tributes (TRB), and a dispute mechanism. + +In this tutorial we'll go over: + +- Setting up the initial toolkit you'll need to get up and running. +- Walk through a simple example. +- List out testnet addresses of networks you currently can test Tellor on. + +## UsingTellor + +The first thing you'll want to do is install the basic tools necessary for using Tellor as your oracle. Use [this package](https://github.com/tellor-io/usingtellor) to install the Tellor User Contracts: + +`npm install usingtellor` + +Once installed this will allow your contracts to inherit the functions from the contract 'UsingTellor'. + +Great! Now that you've got the tools ready, let's go through a simple exercise where we retrieve the bitcoin price: + +### BTC/USD Example + +Inherit the UsingTellor contract, passing the Tellor address as a constructor argument: + +Here's an example: + +```solidity +import "usingtellor/contracts/UsingTellor.sol"; + +contract PriceContract is UsingTellor + +function setBtcPrice() public +} +``` + +For a complete list of contract addresses refer [here](https://docs.tellor.io/tellor/the-basics/contracts-reference). + +For ease of use, the UsingTellor repo comes with a version of the [Tellor Playground](https://github.com/tellor-io/TellorPlayground) contract for easier integration. See [here](https://github.com/tellor-io/sampleUsingTellor#tellor-playground) for a list of helpful functions. + +For a more robust implementation of the Tellor oracle, check out the full list of available functions [here](https://github.com/tellor-io/usingtellor/blob/master/README.md). + +--- + +## Developers > Tutorials > How To View Nft In Metamask + +This tutorial is Part 3/3 in the NFT Tutorial series, where we view our newly minted NFT. However, you can use the general tutorial for any ERC-721 token using MetaMask, including on Mainnet or any testnet. If you’d like to learn how to mint your own NFT on Ethereum, you should check out [Part 1 on How to Write & Deploy an NFT smart contract](/developers/tutorials/how-to-write-and-deploy-an-nft)! + +Congrats! You’ve made it to the shortest and simplest part of our NFT tutorial series — how to view your freshly minted NFT on a virtual wallet. We’ll be using MetaMask for this example since it is what we used in the previous two parts. + +As a prerequisite, you should already have MetaMask on mobile installed, and it should include the account to which you minted your NFT — you can get the app for free on [iOS](https://apps.apple.com/us/app/metamask-blockchain-wallet/id1438144202) or [Android](https://play.google.com/store/apps/details?id=io.metamask&hl=en_US&gl=US). + +## Step 1: Set your network to Sepolia + +At the top of the app, press the “Wallet” button, after which you’ll be prompted to select a network. As our NFT was minted on the Sepolia network, you’ll want to select Sepolia as your network. + +![How to set Sepolia as your network on MetaMask Mobile](./goerliMetamask.gif) + +## Step 2: Add your collectable to MetaMask + +Once you’re on the Sepolia network, select the “Collectibles” tab on the right and add the NFT smart contract address and the ERC-721 token ID of your NFT — which you should be able to find on Etherscan based on the transaction hash from your NFT deployed in Part II of our tutorial. + +![How to find your transaction hash and ERC-721 token ID](./findNFTEtherscan.png) + +You may need to refresh a couple times to view your NFT — but it will be there ! + +![How to upload your NFT to MetaMask](./findNFTMetamask.gif) + +Congrats! You have successfully minted an NFT, and you can now view it! We can’t wait to see how you’ll take the NFT world by storm! + +--- + +## Developers > Tutorials > How To Write And Deploy An Nft + +With NFTs bringing blockchain into the public eye, now is an excellent opportunity to understand the hype yourself by publishing your own NFT contract (ERC-721 Token) on the Ethereum blockchain! + +Alchemy is extremely proud to be powering the biggest names in the NFT space, including Makersplace (recently set a record digital artwork sale at Christie’s for $69 Million), Dapper Labs (creators of NBA Top Shot & Crypto Kitties), OpenSea (the world’s largest NFT marketplace), Zora, Super Rare, NFTfi, Foundation, Enjin, Origin Protocol, Immutable, and more. + +In this tutorial, we will walk through creating and deploying an ERC-721 smart contract on the Sepolia test network using [MetaMask](https://metamask.io/), [Solidity](https://docs.soliditylang.org/en/v0.8.0/), [Hardhat](https://hardhat.org/), [Pinata](https://pinata.cloud/) and [Alchemy](https://alchemy.com/signup/eth) (don’t fret if you don’t understand what any of this means yet — we will explain it!). + +In Part 2 of this tutorial we’ll go through how we can use our smart contract to mint an NFT, and in Part 3 we’ll explain how to view your NFT on MetaMask. + +And of course, if you have questions at any point, don’t hesitate to reach out in the [Alchemy Discord](https://discord.gg/gWuC7zB) or visit [Alchemy's NFT API docs](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api)! + +## Step 1: Connect to the Ethereum network + +There are a bunch of ways to make requests to the Ethereum blockchain, but to make things easy, we’ll use a free account on [Alchemy](https://alchemy.com/signup/eth), a blockchain developer platform and API that allows us to communicate with the Ethereum chain without having to run our own nodes. + +In this tutorial, we’ll also take advantage of Alchemy’s developer tools for monitoring and analytics to understand what’s going on under the hood in our smart contract deployment. If you don’t already have an Alchemy account, you can sign up for free [here](https://alchemy.com/signup/eth). + +## Step 2: Create your app (and API key) + +Once you’ve created an Alchemy account, you can generate an API key by creating an app. This will allow us to make requests to the Sepolia test network. Check out [this guide](https://docs.alchemyapi.io/guides/choosing-a-network) if you’re curious to learn more about test networks. + +1. Navigate to the “Create App” page in your Alchemy Dashboard by hovering over “Apps” in the nav bar and clicking “Create App” + +![Create your app](./create-your-app.png) + +2. Name your app (we chose “My First NFT!”), offer a short description, select “Ethereum” for the Chain, and choose “Sepolia” for your network. Since the merge the other testnets have been deprecated. + +![Configure and publish your app](./alchemy-explorer-sepolia.png) + +3. Click “Create app” and that’s it! Your app should appear in the table below. + +## Step 3: Create an Ethereum account (address) + +We need an Ethereum account to send and receive transactions. For this tutorial, we’ll use MetaMask, a virtual wallet in the browser used to manage your Ethereum account address. If you want to understand more about how transactions on Ethereum work, check out [this page](/developers/docs/transactions/) from the Ethereum foundation. + +You can download and create a MetaMask account for free [here](https://metamask.io/download). When you are creating an account, or if you already have an account, make sure to switch over to the “Sepolia Test Network” in the upper right (so that we’re not dealing with real money). + +![Set Sepolia as your network](./metamask-goerli.png) + +## Step 4: Add ether from a Faucet + +In order to deploy our smart contract to the test network, we’ll need some fake ETH. To get ETH you can go to the [Sepolia Faucet](https://sepoliafaucet.com/) hosted by Alchemy, log in and enter your account address, click “Send Me ETH”. You should see ETH in your MetaMask account soon after! + +## Step 5: Check your Balance + +To double check our balance is there, let’s make an [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) request using [Alchemy’s composer tool](https://composer.alchemyapi.io?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). This will return the amount of ETH in our wallet. After you input your MetaMask account address and click “Send Request”, you should see a response like this: + + `` + +> **Note** This result is in wei, not ETH. Wei is used as the smallest denomination of ether. The conversion from wei to ETH is 1 eth = 1018 wei. So if we convert 0xde0b6b3a7640000 to decimal we get 1\*1018 wei, which equals 1 ETH. + +Phew! Our fake money is all there. + +## Step 6: Initialize our project + +First, we’ll need to create a folder for our project. Navigate to your command line and type: + + mkdir my-nft + cd my-nft + +Now that we’re inside our project folder, we’ll use npm init to initialize the project. If you don’t already have npm installed, follow [these instructions](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm) (we’ll also need [Node.js](https://nodejs.org/en/download/), so download that too!). + + npm init + +It doesn’t really matter how you answer the installation questions; here is how we did it for reference: + +```json + package name: (my-nft) + version: (1.0.0) + description: My first NFT! + entry point: (index.js) + test command: + git repository: + keywords: + author: + license: (ISC) + About to write to /Users/thesuperb1/Desktop/my-nft/package.json: + + , + "author": "", + "license": "ISC" + } +``` + +Approve the package.json, and we’re good to go! + +## Step 7: Install [Hardhat](https://hardhat.org/getting-started/#overview) + +Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. It helps developers when building smart contracts and dapps locally before deploying to the live chain. + +Inside our my-nft project run: + + npm install --save-dev hardhat + +Check out this page for more details on [installation instructions](https://hardhat.org/getting-started/#overview). + +## Step 8: Create Hardhat project + +Inside our project folder run: + + npx hardhat + +You should then see a welcome message and option to select what you want to do. Select “create an empty hardhat.config.js”: + + 888 888 888 888 888 + 888 888 888 888 888 + 888 888 888 888 888 + 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 + 888 888 "88b 888P" d88" 888 888 "88b "88b 888 + 888 888 .d888888 888 888 888 888 888 .d888888 888 + 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. + 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + 👷 Welcome to Hardhat v2.0.11 👷‍ + ? What do you want to do? … + Create a sample project + ❯ Create an empty hardhat.config.js + Quit + +This will generate a hardhat.config.js file for us which is where we’ll specify all of the set up for our project (on step 13). + +## Step 9: Add project folders + +To keep our project organized, we’ll create two new folders. Navigate to the root directory of your project in your command line and type: + + mkdir contracts + mkdir scripts + +- contracts/ is where we’ll keep our NFT smart contract code + +- scripts/ is where we’ll keep scripts to deploy and interact with our smart contract + +## Step 10: Write our contract + +Now that our environment is set up, on to more exciting stuff: _writing our smart contract code!_ + +Open up the my-nft project in your favorite editor (we like [VSCode](https://code.visualstudio.com/)). Smart contracts are written in a language called Solidity which is what we will use to write our MyNFT.sol smart contract.‌ + +1. Navigate to the `contracts` folder and create a new file called MyNFT.sol + +2. Below is our NFT smart contract code, which we based on the [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc721) library’s ERC-721 implementation. Copy and paste the contents below into your MyNFT.sol file. + + ```solidity + //Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721) + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0; + + import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + import "@openzeppelin/contracts/utils/Counters.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; + + contract MyNFT is ERC721URIStorage, Ownable + + function mintNFT(address recipient, string memory tokenURI) + public onlyOwner + returns (uint256) + + } + ``` + +3. Because we are inheriting classes from the OpenZeppelin contracts library, in your command line run `npm install @openzeppelin/contracts` to install the library into our folder. + +So, what does this code _do_ exactly? Let’s break it down, line-by-line. + +At the top of our smart contract, we import three [OpenZeppelin](https://openzeppelin.com/) smart contract classes: + +- @openzeppelin/contracts/token/ERC721/ERC721.sol contains the implementation of the ERC-721 standard, which our NFT smart contract will inherit. (To be a valid NFT, your smart contract must implement all the methods of the ERC-721 standard.) To learn more about the inherited ERC-721 functions, check out the interface definition [here](https://eips.ethereum.org/EIPS/eip-721). + +- @openzeppelin/contracts/utils/Counters.sol provides counters that can only be incremented or decremented by one. Our smart contract uses a counter to keep track of the total number of NFTs minted and set the unique ID on our new NFT. (Each NFT minted using a smart contract must be assigned a unique ID—here our unique ID is just determined by the total number of NFTs in existence. For example, the first NFT we mint with our smart contract has an ID of "1," our second NFT has an ID of "2," etc.) + +- @openzeppelin/contracts/access/Ownable.sol sets up [access control](https://docs.openzeppelin.com/contracts/3.x/access-control) on our smart contract, so only the owner of the smart contract (you) can mint NFTs. (Note, including access control is entirely a preference. If you'd like anyone to be able to mint an NFT using your smart contract, remove the word Ownable on line 10 and onlyOwner on line 17.) + +After our import statements, we have our custom NFT smart contract, which is surprisingly short — it only contains a counter, a constructor, and single function! This is thanks to our inherited OpenZeppelin contracts, which implement most of the methods we need to create an NFT, such as `ownerOf` which returns the owner of the NFT, and `transferFrom`, which transfers ownership of the NFT from one account to another. + +In our ERC-721 constructor, you’ll notice we pass 2 strings, “MyNFT” and “NFT.” The first variable is the smart contract’s name, and the second is its symbol. You can name each of these variables whatever you wish! + +Finally, we have our function `mintNFT(address recipient, string memory tokenURI)` that allows us to mint an NFT! You'll notice this function takes in two variables: + +- `address recipient` specifies the address that will receive your freshly minted NFT + +- `string memory tokenURI` is a string that should resolve to a JSON document that describes the NFT's metadata. An NFT's metadata is really what brings it to life, allowing it to have configurable properties, such as a name, description, image, and other attributes. In part 2 of this tutorial, we will describe how to configure this metadata. + +`mintNFT` calls some methods from the inherited ERC-721 library, and ultimately returns a number that represents the ID of the freshly minted NFT. + +## Step 11: Connect MetaMask & Alchemy to your project + +Now that we’ve created a MetaMask wallet, Alchemy account, and written our smart contract, it’s time to connect the three. + +Every transaction sent from your virtual wallet requires a signature using your unique private key. To provide our program with this permission, we can safely store our private key (and Alchemy API key) in an environment file. + +To learn more about sending transactions, check out [this tutorial](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) on sending transactions using web3. + +First, install the dotenv package in your project directory: + + npm install dotenv --save + +Then, create a `.env` file in the root directory of our project, and add your MetaMask private key and HTTP Alchemy API URL to it. + +- Follow [these instructions](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key) to export your private key from MetaMask + +- See below to get HTTP Alchemy API URL and copy it to your clipboard + +![Copy your Alchemy API URL](./copy-alchemy-api-url.gif) + +Your `.env` should now look like this: + + API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key" + PRIVATE_KEY="your-metamask-private-key" + +To actually connect these to our code, we’ll reference these variables in our hardhat.config.js file in step 13. + + + +## Step 12: Install Ethers.js + +Ethers.js is a library that makes it easier to interact and make requests to Ethereum by wrapping [standard JSON-RPC methods](/developers/docs/apis/json-rpc/) with more user friendly methods. + +Hardhat makes it super easy to integrate [Plugins](https://hardhat.org/plugins/) for additional tooling and extended functionality. We’ll be taking advantage of the [Ethers plugin](https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html) for contract deployment ([Ethers.js](https://github.com/ethers-io/ethers.js/) has some super clean contract deployment methods). + +In your project directory type: + + npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.0.0 + +We’ll also require ethers in our hardhat.config.js in the next step. + +## Step 13: Update hardhat.config.js + +We’ve added several dependencies and plugins so far, now we need to update hardhat.config.js so that our project knows about all of them. + +Update your hardhat.config.js to look like this: + +```js + /** + * @type import('hardhat/config').HardhatUserConfig + */ + require('dotenv').config(); + require("@nomiclabs/hardhat-ethers"); + const = process.env; + module.exports = , + sepolia: `] + } + }, + } +``` + +## Step 14: Compile our contract + +To make sure everything is working so far, let’s compile our contract. The compile task is one of the built-in hardhat tasks. + +From the command line run: + + npx hardhat compile + +You might get a warning about SPDX license identifier not provided in source file , but no need to worry about that — hopefully everything else looks good! If not, you can always message in the [Alchemy discord](https://discord.gg/u72VCg3). + +## Step 15: Write our deploy script + +Now that our contract is written and our configuration file is good to go, it’s time to write our contract deploy script. + +Navigate to the `scripts/` folder and create a new file called `deploy.js`, adding the following contents to it: + +```js +async function main() + +main() + .then(() => process.exit(0)) + .catch((error) => ) +``` + +Hardhat does an amazing job of explaining what each of these lines of code does in their [Contracts tutorial](https://hardhat.org/tutorial/testing-contracts.html#writing-tests), we’ve adopted their explanations here. + + const MyNFT = await ethers.getContractFactory("MyNFT"); + +A ContractFactory in ethers.js is an abstraction used to deploy new smart contracts, so MyNFT here is a factory for instances of our NFT contract. When using the hardhat-ethers plugin ContractFactory and Contract instances are connected to the first signer by default. + + const myNFT = await MyNFT.deploy(); + +Calling deploy() on a ContractFactory will start the deployment, and return a Promise that resolves to a Contract. This is the object that has a method for each of our smart contract functions. + +## Step 16: Deploy our contract + +We’re finally ready to deploy our smart contract! Navigate back to the root of your project directory, and in the command line run: + + npx hardhat --network sepolia run scripts/deploy.js + +You should then see something like: + + Contract deployed to address: 0x4C5266cCc4b3F426965d2f51b6D910325a0E7650 + +If we go to the [Sepolia etherscan](https://sepolia.etherscan.io/) and search for our contract address we should be able to see that it has been deployed successfully. If you can't see it immediately, please wait a while as it can take some time. The transaction will look something like this: + +![View your transaction address on Etherscan](./etherscan-sepoila-contract-creation.png) + +The From address should match your MetaMask account address and the To address will say “Contract Creation”. If we click into the transaction, we’ll see our contract address in the To field: + +![View your contract address on Etherscan](./etherscan-sepolia-tx-details.png) + +Yasssss! You just deployed your NFT smart contract to the Ethereum (testnet) chain! + +To understand what’s going on under the hood, let’s navigate to the Explorer tab in our [Alchemy dashboard](https://dashboard.alchemyapi.io/explorer). If you have multiple Alchemy apps make sure to filter by app and select “MyNFT”. + +![View calls made “under the hood” with Alchemy’s Explorer Dashboard](./alchemy-explorer-goerli.png) + +Here you’ll see a handful of JSON-RPC calls that Hardhat/Ethers made under the hood for us when we called the .deploy() function. Two important ones to call out here are [eth_sendRawTransaction](/developers/docs/apis/json-rpc/#eth_sendrawtransaction), which is the request to actually write our smart contract onto the Sepolia chain, and [eth_getTransactionByHash](/developers/docs/apis/json-rpc/#eth_gettransactionbyhash) which is a request to read information about our transaction given the hash (a typical pattern when sending transactions). To learn more about sending transactions, check out this tutorial on [sending transactions using Web3](/developers/tutorials/sending-transactions-using-web3-and-alchemy/). + +That’s all for Part 1 of this tutorial. In [Part 2, we’ll actually interact with our smart contract by minting an NFT](/developers/tutorials/how-to-mint-an-nft/), and in [Part 3 we’ll show you how to view your NFT in your Ethereum wallet](/developers/tutorials/how-to-view-nft-in-metamask/)! + +--- + +## Developers > Tutorials > Interact With Other Contracts From Solidity + +In the previous tutorials we learnt a lot [how to deploy your first smart contract](/developers/tutorials/deploying-your-first-smart-contract/) and add some features to it like [control access with modifiers](https://ethereumdev.io/organize-your-code-and-control-access-to-your-smart-contract-with-modifiers/) or [error handling in Solidity](https://ethereumdev.io/handle-errors-in-solidity-with-require-and-revert/). In this tutorial we’ll learn how to deploy a smart contract from an existing contract and interact with it. + +We’ll make a contract that enables anyone to have his own `Counter` smart contract by creating a factory for it, its name will be `CounterFactory`. First here is the code of our initial `Counter` smart contract: + +```solidity +pragma solidity 0.5.17; + +contract Counter + + modifier onlyFactory() + + constructor(address owner) public + + function getCount() public view returns (uint256) + + function increment(address caller) public onlyFactory onlyOwner(caller) + +} +``` + +Note that we slightly modified the contract code to keep a track of the address of the factory and the address of the contract owner. When you call a contract code from another contract, the msg.sender will refer to the address of our contract factory. This is **a really important point to understand** as using a contract to interact with other contracts is a common practice. You should therefore take care of who is the sender in complex cases. + +For this we also added an `onlyFactory` modifier that make sure that the state changing function can only be called by the factory that will pass the original caller as a parameter. + +Inside of our new `CounterFactory` that will manage all the other Counters, we’ll add a mapping that will associate an owner to the address of his counter contract: + +```solidity +mapping(address => Counter) _counters; +``` + +In Ethereum, mapping are equivalent of objects in javascript, they enable to map a key of type A to a value of type B. In this case we map the address of an owner with the instance of its Counter. + +Instantiating a new Counter for someone will look like this: + +```solidity + function createCounter() public +``` + +We first check if the person already owns a counter. If he does not own a counter we instantiate a new counter by passing his address to the `Counter` constructor and assign the newly created instance to the mapping. + +To get the count of a specific Counter it will look like this: + +```solidity +function getCount(address account) public view returns (uint256) + +function getMyCount() public view returns (uint256) +``` + +The first function check if the Counter contract exists for a given address and then calls the `getCount` method from the instance. The second function: `getMyCount` is just a short end to pass the msg.sender directly to the `getCount` function. + +The `increment` function is quite similar but pass the original transaction sender to the `Counter` contract: + +```solidity +function increment() public +``` + +Note that if called to many times, our counter could possibly victim of an overflow. You should use the [SafeMath library](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/) as much as possible to protect from this possible case. + +To deploy our contract, you will need to provide both the code of the `CounterFactory` and the `Counter`. When deploying for example in Remix you’ll need to select CounterFactory. + +Here is the full code: + +```solidity +pragma solidity 0.5.17; + +contract Counter + + modifier onlyFactory() + + constructor(address owner) public + + function getCount() public view returns (uint256) + + function increment(address caller) public onlyFactory onlyOwner(caller) + +} + +contract CounterFactory + + function increment() public + + function getCount(address account) public view returns (uint256) + + function getMyCount() public view returns (uint256) + +} +``` + +After compiling, in the Remix deploy section you’ll select the factory to be deployed: + +![Selecting the factory to be deployed in Remix](./counterfactory-deploy.png) + +Then you can play with your contract factory and check the value changing. If you’d like to call the smart contract from a different address you’ll need to change the address in the Account select of Remix. + +--- + +## Developers > Tutorials > Ipfs Decentralized Ui + +You wrote an incredible new dapp. You've even written a [user interface](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/) for it. But now you're afraid that somebody will attempt to censor it by bringing down your user interface, which is just one server off in the cloud. In this tutorial you learn how to avoid censorship by putting your user interface up on **[interplanetary file system (IPFS)](https://ipfs.tech/developers/)** so anybody interested will be able to pin it on a server for future access. + +You could use a third-party service such as [Fleek](https://docs.fleek.xyz/docs) to do all the work. This tutorial is for people who want to do enough to understand what they are doing even if it is more work. + +## Getting started locally + +There are multiple [third-party IPFS providers](https://docs.ipfs.tech/how-to/work-with-pinning-services/#use-a-third-party-pinning-service), but it is best to start with running IPFS locally for testing. + +1. Install the [IPFS user interface](https://docs.ipfs.tech/install/ipfs-desktop/#install-instructions). + +2. Create a directory with your web site. If you are using [Vite](https://vitejs.dev/), use this command: + + ```sh + pnpm vite build + ``` + +3. In IPFS Desktop, click **Import > Folder** and select the directory you created in the previous step. + +4. Select the folder you just uploaded and click **Rename**. Give it a more meaningful name. + +5. Select it again and click **Share link**. Copy the URL to the clipboard. The link would be similar to `https://ipfs.io/ipfs/QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`. + +6. Click **Status**. Expand the **Advanced** tab to see the gateway address. For example, on my system the address is `http://127.0.0.1:8080`. + +7. Combine the path from the link step with the gateway address to find your address. For example, for the example above, the URL is `http://127.0.0.1:8080/ipfs/QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`. Open that URL in a browser to see your site. + +## Uploading + +So now you can use IPFS to serve files locally, which is not very exciting. The next step is to make them available for the world when you're offline. + +There are a number of well known [pinning services](https://docs.ipfs.tech/concepts/persistence/#pinning-services). Choose one of them. Whichever service you use, you need to create an account and provide it with the **content identifier (CID)** in your IPFS desktop. + +Personally, I found [4EVERLAND](https://docs.4everland.org/storage/4ever-pin/guides) to be the easiest to use. Here are the directions for it: + +1. Browse to [the dashboard](https://dashboard.4everland.org/overview) and login with your wallet. + +2. In the left sidebar click **Storage > 4EVER Pin**. + +3. Click **Upload > Selected CID**. Give your content a name and provide the CID from IPFS desktop. At present a CID is a string that starts with `Qm` followed by 44 letters and digits that represent a [base-58 encoded](https://medium.com/bootdotdev/base64-vs-base58-encoding-c25553ff4524) hash, such as `QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`, but [that is likely to change](https://docs.ipfs.tech/concepts/content-addressing/#version-1-v1). + +4. The initial status is **Queued**. Reload until it changes to **Pinned**. + +5. Click your CID to get the link. You can see my application [here](https://bafybeifqka2odrne5b6l5guthqvbxu4pujko2i6rx2zslvr3qxs6u5o7im.ipfs.dweb.link/). + +6. You might need to activate your account to have it pinned for more than a month. Account activation costs about $1. If you closed it, log out and log back in to be asked to activate again. + +## Using from IPFS + +At this point you have a link to a centralized gateway that serves your IPFS content. In short, your user interface may be a bit safer but it's still not censorship resistant. For real censorship resistance, users need to use IPFS [directly from a browser](https://docs.ipfs.tech/install/ipfs-companion/#prerequisites). + +Once you have that installed (and the desktop IPFS working), you can go to [/ipfs/``](https://any.site/ipfs/bafybeifqka2odrne5b6l5guthqvbxu4pujko2i6rx2zslvr3qxs6u5o7im) on any site and you'll get that content, served in a decentralized manner. + +## Drawbacks + +You cannot reliably delete IPFS files, so as long as you're modifying your user interface, it is probably best to either leave it centralized, or use [interplanetary name system (IPNS)](https://docs.ipfs.tech/concepts/ipns/#mutability-in-ipfs), a system that provides mutability on top of IPFS. Of course, anything that is mutable can be censored, in the case of IPNS by pressuing the person with the private key to which it corresponds. + +Additionally, some packages have a problem with IPFS, so if your web site is very complicated that may not be a good solution. And of course, anything that relies on server integration cannot be decentralized just by having the client side on IPFS. + +## Conclusion + +Just as Ethereum lets you decentralize the database and business logic aspects of your dapp, IPFS lets you decentralize the user interface. This lets you shut off one more attack vector against your dapp. + +--- + +## Developers > Tutorials > Kickstart Your Dapp Frontend Development With Create Eth App + +Last time we looked at [the big picture of Solidity](https://soliditydeveloper.com/solidity-overview-2020) and already mentioned the [create-eth-app](https://github.com/PaulRBerg/create-eth-app). Now you will find out how to use it, what features are integrated and additional ideas on how to expand on it. Started by Paul Razvan Berg, the founder of [Sablier](http://sablier.com/), this app will kickstart your frontend development and comes with several optional integrations to choose from. + +## Installation + +The installation requires Yarn 0.25 or higher (`npm install yarn --global`). It is as simple as running: + +```bash +yarn create eth-app my-eth-app +cd my-eth-app +yarn react-app:start +``` + +It is using [create-react-app](https://github.com/facebook/create-react-app) under the hood. To see your app, open `http://localhost:3000/`. When you’re ready to deploy to production, create a minified bundle with yarn build. One easy way to host this would be [Netlify](https://www.netlify.com/). You can create a GitHub repo, add it to Netlify, setup the build command and you are finished! Your app will be hosted and usable for everyone. And all of it free of charge. + +## Features + +### React & create-react-app + +First of all the heart of the app: React and all the additional features coming with _create-react-app_. Only using this is a great option if you do not want to integrate Ethereum. [React](https://reactjs.org/) itself makes building interactive UI's really easy. It may not be as beginner-friendly as [Vue](https://vuejs.org/), but it is still mostly used, has more features and most importantly thousands of additional libraries to choose from. The _create-react-app_ makes it really easy to start with it as well and includes: + +- React, JSX, ES6, TypeScript, Flow syntax support. +- Language extras beyond ES6 like the object spread operator. +- Autoprefixed CSS, so you don’t need -webkit- or other prefixes. +- A fast interactive unit test runner with built-in support for coverage reporting. +- A live development server that warns about common mistakes. +- A build script to bundle JS, CSS, and images for production, with hashes and sourcemaps. + +The _create-eth-app_ in particular is making use of the new [hooks effects](https://reactjs.org/docs/hooks-effect.html). A method to write powerful, yet very small so-called functional components. See below section about Apollo for how they are used in _create-eth-app_. + +### Yarn Workspaces + +[Yarn Workspaces](https://classic.yarnpkg.com/en/docs/workspaces/) allow you to have multiple packages, but being able to manage them all from the root folder and installing dependencies for all at once using `yarn install`. This especially makes sense for smaller additional packages like smart contracts addresses/ABI management (the information about where you deployed which smart contracts and how to communicate with them) or the graph integration, both part of `create-eth-app`. + +### ethers.js + +While [Web3](https://docs.web3js.org/) is still mostly used, [ethers.js](https://docs.ethers.io/) has been getting a lot more traction as an alternative in the last year and is the one integrated into _create-eth-app_. You can work with this one, change it to Web3 or consider upgrading to [ethers.js v5](https://docs-beta.ethers.io/) which is almost out of beta. + +### The Graph + +[GraphQL](https://graphql.org/) is an alternative way for handling data compared to a [Restful API](https://restfulapi.net/). They have several advantages over Restful Apis, especially for decentralized blockchain data. If you are interested in the reasoning behind this, have a look at [GraphQL Will Power the Decentralized Web](https://medium.com/graphprotocol/graphql-will-power-the-decentralized-web-d7443a69c69a). + +Usually you would fetch data from your smart contract directly. Want to read the time of the latest trade? Just call `MyContract.methods.latestTradeTime().call()` which fetches the data from an Ethereum node into your dapp. But what if you need hundreds of different data points? That would result in hundreds of data fetches to the node, each time requiring an [RTT](https://wikipedia.org/wiki/Round-trip_delay_time) making your dapp slow and inefficient. One workaround might be a fetcher call function inside your contract that returns multiple data at once. This is not always ideal though. + +And then you might be interested in historical data as well. You want to know not only the last trade time, but the times for all trades that you ever did yourself. Use the _create-eth-app_ subgraph package, read the [documentation](https://thegraph.com/docs/en/subgraphs/developing/creating/starting-your-subgraph) and adapt it to your own contracts. If you are looking for popular smart contracts, there may even already be a subgraph. Check out the [subgraph explorer](https://thegraph.com/explorer/). + +Once you have a subgraph, it allows you to write one simple query in your dapp that retrieves all the important blockchain data including historical ones that you need, only one fetch required. + +### Apollo + +Thanks to the [Apollo Boost](https://www.apollographql.com/docs/react/get-started/) integration you can easily integrate the graph in your React dapp. Especially when using [React hooks and Apollo](https://www.apollographql.com/blog/apollo-client-now-with-react-hooks), fetching data is as simple as writing a single GraphQl query in your component: + +```js +const = useQuery(myGraphQlQuery) + +React.useEffect(() => ) + } +}, [loading, error, data]) +``` + +## Templates + +On top you can choose from several different templates. So far you can use an Aave, Compound, UniSwap or sablier integration. They all add important service smart contract addresses along with pre-made subgraph integrations. Just add the template to the creation command like `yarn create eth-app my-eth-app --with-template aave`. + +### Aave + +[Aave](https://aave.com/) is a decentralized money lending market. Depositors provide liquidity to the market to earn a passive income, while borrowers are able to borrow using collaterals. One unique feature of Aave are those [flash loans](https://docs.aave.com/developers/guides/flash-loans) which allow you to borrow money without any collateral, as long as you return the loan within one transaction. This can be useful for example for giving you extra cash on arbitrage trading. + +Traded tokens that earn you interests are called _aTokens_. + +When you choose to integrate Aave with _create-eth-app_, you will get a [subgraph integration](https://docs.aave.com/developers/getting-started/using-graphql). Aave uses The Graph and already provides you with several ready-to-use subgraphs on [Ropsten](https://thegraph.com/explorer/subgraph/aave/protocol-ropsten) and [Mainnet](https://thegraph.com/explorer/subgraph/aave/protocol) in [raw](https://thegraph.com/explorer/subgraph/aave/protocol-raw) or [formatted](https://thegraph.com/explorer/subgraph/aave/protocol) form. + +![Aave Flash Loan meme – "Yeahhh, if I could keep my flash loan longer than 1 transaction, that would be great"](./flashloan-meme.png) + +### Compound + +[Compound](https://compound.finance/) is similar to Aave. The integration already includes the new [Compound v2 Subgraph](https://medium.com/graphprotocol/https-medium-com-graphprotocol-compound-v2-subgraph-highlight-a5f38f094195). The interests earning tokens here are surprisingly called _cTokens_. + +### Uniswap + +[Uniswap](https://uniswap.exchange/) is a decentralized exchange (DEX). Liquidity providers can earn fees by providing the required tokens or ether for both sides of a trade. It is widely used and therefore has one of the highest liquidities for a very wide range of tokens. You can easily integrate it in your dapp to, for example, allow users to swap their ETH for DAI. + +Unfortunately, at the time of this writing the integration is only for Uniswap v1 and not the [just released v2](https://uniswap.org/blog/uniswap-v2/). + +### Sablier + +[Sablier](https://sablier.com/) allows users streaming money payments. Instead of a single payday, you actually get your money constantly without further administration after the initial setup. The integration includes its [own subgraph](https://thegraph.com/explorer/subgraph/sablierhq/sablier). + +## What's next? + +If you have questions about _create-eth-app_, go to the [Sablier community server](https://discord.gg/bsS8T47), where you can get in touch with the authors of _create-eth-app_. As some first next steps you might want to integrate a UI framework like [Material UI](https://material-ui.com/), write GraphQL queries for the data that you actually need and setup the deployment. + +--- + +## Developers > Tutorials > Learn Foundational Ethereum Topics With Sql + +Many Ethereum tutorials target developers, but there’s a lack of educational resources for data analysts or for people who wish to see onchain data without running a client or node. + +This tutorial helps readers understand fundamental Ethereum concepts including transactions, blocks and gas by querying onchain data with structured query language (SQL) through an interface provided by [Dune Analytics](https://dune.xyz/home). + +Onchain data can help us understand Ethereum, the network, and as an economy for computing power and should serve as a base for understanding challenges facing Ethereum today (i.e., rising gas prices) and, more importantly, discussions around scaling solutions. + +### Transactions + +A user’s journey on Ethereum starts with initializing a user-controlled account or an entity with an ETH balance. There are two account types - user-controlled or a smart contract (see [ethereum.org](/developers/docs/accounts/)). + +Any account can be viewed on a block explorer like [Etherscan](https://etherscan.io/). Block explorers are a portal to Ethereum’s data. They display, in real-time, data on blocks, transactions, miners, accounts and other onchain activity (see [here](/developers/docs/data-and-analytics/block-explorers/)). + +However, a user may wish to query the data directly to reconcile the information provided by external block explorers. [Dune Analytics](https://duneanalytics.com/) provides this capability to anyone with some knowledge of SQL. + +For reference, the smart contract account for the Ethereum Foundation (EF) can be viewed on [Etherscan](https://etherscan.io/address/0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae). + +One thing to note is that all accounts, including the EF’s, have a public address that can be used to send and receive transactions. + +The account balance on Etherscan comprises regular transactions and internal transactions. Internal transactions, despite the name, are not _actual_ transactions that change the state of the chain. They are value transfers initiated by executing a contract ([source](https://ethereum.stackexchange.com/questions/3417/how-to-get-contract-internal-transactions)). Since internal transactions have no signature, they are **not** included on the blockchain and cannot be queried with Dune Analytics. + +Therefore, this tutorial will focus on regular transactions. This can be queried as such: + +```sql +WITH temp_table AS ( +SELECT + hash, + block_number, + block_time, + "from", + "to", + value / 1e18 AS ether, + gas_used, + gas_price / 1e9 AS gas_price_gwei +FROM ethereum."transactions" +WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' +ORDER BY block_time DESC +) +SELECT + hash, + block_number, + block_time, + "from", + "to", + ether, + (gas_used * gas_price_gwei) / 1e9 AS txn_fee +FROM temp_table +``` + +This will yield the same information as provided on Etherscan's transaction page. For comparison, here are the two sources: + +#### Etherscan + +![](./etherscan_view.png) + +[EF's contract page on Etherscan.](https://etherscan.io/address/0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe) + +#### Dune Analytics + +![](./dune_view.png) + +You can find dashboard [here](https://duneanalytics.com/paulapivat/Learn-Ethereum). Click on the table to see the query (also see above). + +### Breaking Down Transactions + +A submitted transaction includes several pieces of information including ([source](/developers/docs/transactions/)): + +- **Recipient**: The receiving address (queried as "to") +- **Signature**: While a sender's private keys signs a transaction, what we can query with SQL is a sender's public address ("from"). +- **Value**: This is the amount of ETH transferred (see `ether` column). +- **Data**: This is arbitrary data that's been hashed (see `data` column) +- **gasLimit** – the maximum amount of gas units that can be consumed by the transaction. Units of gas represent computational steps +- **maxPriorityFeePerGas** - the maximum amount of gas to be included as a tip to the miner +- **maxFeePerGas** - the maximum amount of gas willing to be paid for the transaction (inclusive of baseFeePerGas and maxPriorityFeePerGas) + +We can query these specific pieces of information for transactions to the Ethereum Foundation public address: + +```sql +SELECT + "to", + "from", + value / 1e18 AS ether, + data, + gas_limit, + gas_price / 1e9 AS gas_price_gwei, + gas_used, + ROUND(((gas_used / gas_limit) * 100),2) AS gas_used_pct +FROM ethereum."transactions" +WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' +ORDER BY block_time DESC +``` + +### Blocks + +Each transaction will change the state of the Ethereum virtual machine ([EVM](/developers/docs/evm/)) ([source](/developers/docs/transactions/)). Transactions are broadcasted to the network to be verified and included in a block. Each transaction is associated with a block number. To see the data, we could query a specific block number: 12396854 (the most recent block among Ethereum Foundation transactions as of this writing, 11/5/21). + +Moreover, when we query the next two blocks, we can see that each block contains the hash of the previous block (i.e., parent hash), illustrating how the blockchain is formed. + +Each block contains a reference to it parent block. This is shown below between the `hash` and `parent_hash` columns ([source](/developers/docs/blocks/)): + +![parent_hash](./parent_hash.png) + +Here is the [query](https://duneanalytics.com/queries/44856/88292) on Dune Analytics: + +```sql +SELECT + time, + number, + hash, + parent_hash, + nonce +FROM ethereum."blocks" +WHERE "number" = 12396854 OR "number" = 12396855 OR "number" = 12396856 +LIMIT 10 +``` + +We can examine a block by querying time, block number, difficulty, hash, parent hash, and nonce. + +The only thing this query does not cover is _list of transaction_ which requires a separate query below and _state root_. A full or archival node will store all transactions and state transitions, allowing for clients to query the state of the chain at any time. Because this requires large storage space, we can separate chain data from state data: + +- Chain data (list of blocks, transactions) +- State data (result of each transaction’s state transition) + +State root falls in the latter and is _implicit_ data (not stored onchain), while chain data is explicit and stored on the chain itself ([source](https://ethereum.stackexchange.com/questions/359/where-is-the-state-data-stored)). + +For this tutorial, we'll be focusing on onchain data that _can_ be queried with SQL via Dune Analytics. + +As stated above, each block contains a list of transactions, we can query this by filtering for a specific block. We'll try the most recent block, 12396854: + +```sql +SELECT * FROM ethereum."transactions" +WHERE block_number = 12396854 +ORDER BY block_time DESC` +``` + +Here's the SQL output on Dune: + +![](./list_of_txn.png) + +This single block being added to the chain changes the state of the Ethereum virtual machine ([EVM](/developers/docs/evm/)). Dozens sometimes, hundreds of transactions are verified at once. In this specific case, 222 transactions were included. + +To see how many were actually successful, we would add another filter to count successful transactions: + +```sql +WITH temp_table AS ( + SELECT * FROM ethereum."transactions" + WHERE block_number = 12396854 AND success = true + ORDER BY block_time DESC +) +SELECT + COUNT(success) AS num_successful_txn +FROM temp_table +``` + +For block 12396854, out of 222 total transactions, 204 were successfully verified: + +![](./successful_txn.png) + +Transactions requests occur dozens of times per second, but blocks are committed approximately once every 15 seconds ([source](/developers/docs/blocks/)). + +To see that there is one block produced approximately every 15 seconds, we could take the number of seconds in a day (86400) divided by 15 to get an estimated average number of blocks per day (~ 5760). + +The chart for Ethereum blocks produced per day (2016 - present) is: + +![](./daily_blocks.png) + +The average number of blocks produced daily over this time period is ~5,874: + +![](./avg_daily_blocks.png) + +The queries are: + +```sql +# query to visualize number of blocks produced daily since 2016 + +SELECT + DATE_TRUNC('day', time) AS dt, + COUNT(*) AS block_count +FROM ethereum."blocks" +GROUP BY dt +OFFSET 1 + +# average number of blocks produced per day + +WITH temp_table AS ( +SELECT + DATE_TRUNC('day', time) AS dt, + COUNT(*) AS block_count +FROM ethereum."blocks" +GROUP BY dt +OFFSET 1 +) +SELECT + AVG(block_count) AS avg_block_count +FROM temp_table +``` + +The average number of blocks produced per day since 2016 is slightly above that number at 5,874. Alternatively, dividing 86400 seconds by 5874 average blocks comes out to 14.7 seconds or approximately one block every 15 seconds. + +### Gas + +Blocks are bounded in size. The maximum block size is dynamic and varies according to network demand between 12,500,000 and 25,000,000 units. Limits are required to prevent arbitrarily large block sizes putting strain on full nodes in terms of disk space and speed requirements ([source](/developers/docs/blocks/)). + +One way to conceptualize block gas limit is to think of it as the **supply** of available block space in which to batch transactions. The block gas limit can be queried and visualized from 2016 to present day: + +![](./avg_gas_limit.png) + +```sql +SELECT + DATE_TRUNC('day', time) AS dt, + AVG(gas_limit) AS avg_block_gas_limit +FROM ethereum."blocks" +GROUP BY dt +OFFSET 1 +``` + +Then there is the actual gas used daily to pay for computing done on the Ethereum chain (i.e., sending transaction, calling a smart contract, minting an NFT). This is the **demand** for available Ethereum block space: + +![](./daily_gas_used.png) + +```sql +SELECT + DATE_TRUNC('day', time) AS dt, + AVG(gas_used) AS avg_block_gas_used +FROM ethereum."blocks" +GROUP BY dt +OFFSET 1 +``` + +We can also juxtapose these two charts together to see how **demand and supply** line up: + +![gas_demand_supply](./gas_demand_supply.png) + +Therefore we can understand gas prices as a function of demand for Ethereum block space, given available supply. + +Finally, we may want to query average daily gas prices for the Ethereum chain, however, doing so will result in an especially long query time, so we’ll filter our query to the average amount of gas paid per transaction by the Ethereum Foundation. + +![](./ef_daily_gas.png) + +We can see gas prices paid for all transactions made to the Ethereum Foundation address over the years. Here is the query: + +```sql +SELECT + block_time, + gas_price / 1e9 AS gas_price_gwei, + value / 1e18 AS eth_sent +FROM ethereum."transactions" +WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' +ORDER BY block_time DESC +``` + +### Summary + +With this tutorial, we understand foundational Ethereum concepts and how the Ethereum blockchain works by querying and getting a feel for onchain data. + +The dashboard that holds all code used in this tutorial can be found [here](https://duneanalytics.com/paulapivat/Learn-Ethereum). + +For more use of data to explore web3 [find me on Twitter](https://twitter.com/paulapivat). + +--- + +## Developers > Tutorials > Logging Events Smart Contracts + +In Solidity, [events](/developers/docs/smart-contracts/anatomy/#events-and-logs) are dispatched signals the smart contracts can fire. Dapps, or anything connected to Ethereum JSON-RPC API, can listen to these events and act accordingly. An event can also be indexed so that the event history is searchable later. + +## Events + +The most common event on the Ethereum blockchain at the time of writing this article is the Transfer event that is emitted by ERC20 tokens when someone transfers tokens. + +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +``` + +The event signature is declared inside of the contract code and can be emitted with the emit keyword. For example, the transfer event logs who sent the transfer (_from_), to who (_to_) and how much tokens were transferred (_value_). + +If we get back to our Counter smart contract and decide to log every time the value is changed. As this contract is not meant to be deployed but serve as a base for building another contract by extending it: it’s called an abstract contract. In the case of our counter example, it would look like this: + +```solidity +pragma solidity 0.5.17; + +contract Counter + + // Getter to get the count value + function getCount() public view returns (uint256) + +} +``` + +Notice that: + +- **Line 5**: we declare our event and what it contains, the old value and the new value. + +- **Line 13**: When we increment our count variable, we emit the event. + +If we now deploy the contract and call the increment function, we’ll see that Remix will automatically display it if you click on the new transaction inside an array named logs. + +![Remix screenshot](./remix-screenshot.png) + +Logs are really useful for debugging your smart contracts but they are also important if you build applications used by different people and make it easier to make analytics to track and understand how your smart contract is used. The logs generated by transactions are displayed in popular block explorers and you can also for example use them to create offchain scripts for listening to specific events and taking action when they occur. + +--- + +## Developers > Tutorials > Merkle Proofs For Offline Data Integrity + +## Introduction + +Ideally we'd like to store everything in Ethereum storage, which is stored across thousands of computers and has +extremely high availability (the data cannot be censored) and integrity (the data cannot be modified in an +unauthorized manner), but storing a 32-byte word typically costs 20,000 gas. As I'm writing this, that cost is +equivalent to $6.60. At 21 cents per byte this is too expensive for many uses. + +To solve this problem the Ethereum ecosystem developed [many alternative ways to store data in a decentralized +fashion](/developers/docs/storage/). Usually they involve a tradeoff between availability +and price. However, integrity is usually assured. + +In this article you learn **how** to ensure data integrity without storing the data on the blockchain, using +[Merkle proofs](https://computersciencewiki.org/index.php/Merkle_proof). + +## How does it work? + +In theory we could just store the hash of the data onchain, and send all the data in transactions that require it. However, this is still too expensive. A byte of data to a transaction costs about 16 gas, currently about half a cent, or about $5 per kilobyte. At $5000 per megabyte, this is still too expensive for many uses, even without the added cost of hashing the data. + +The solution is to repeatedly hash different subsets of the data, so for the data that you don't need to send you can just send a hash. You do this using a Merkle tree, a tree data structure where each node is a hash of the nodes below it: + +![Merkle Tree](tree.png) + +The root hash is the only part that needs to be stored onchain. To prove a certain value, you provide all the hashes that need to be combined with it to obtain the root. For example, to prove `C` you provide `D`, `H(A-B)`, and `H(E-H)`. + +![Proof of the value of C](proof-c.png) + +## Implementation + +[The sample code is provided here](https://github.com/qbzzt/merkle-proofs-for-offline-data-integrity). + +### Offchain code + +In this article we use JavaScript for the offchain computations. Most decentralized applications have their offchain component in JavaScript. + +#### Creating the Merkle root + +First we need to provide the Merkle root to the chain. + +```javascript +const ethers = require("ethers") +``` + +[We use the hash function from the ethers package](https://docs.ethers.io/v5/api/utils/hashing/#utils-keccak256). + +```javascript +// The raw data whose integrity we have to verify. The first two bytes a +// are a user identifier, and the last two bytes the amount of tokens the +// user owns at present. +const dataArray = [ + 0x0bad0010, 0x60a70020, 0xbeef0030, 0xdead0040, 0xca110050, 0x0e660060, + 0xface0070, 0xbad00080, 0x060d0091, +] +``` + +Encoding each entry into a single 256-bit integer results in less readable code than using JSON, for example. However, this means significantly less processing to retrieve the data in the contract, so much lower gas costs. [You can read JSON onchain](https://github.com/chrisdotn/jsmnSol), it's just a bad idea if avoidable. + +```javascript +// The array of hash values, as BigInts +const hashArray = dataArray +``` + +In this case our data is 256-bit values to begin with, so no processing is needed. If we use a more complicated data structure, such as strings, we need to make sure we hash the data first to get an array of hashes. Note that this is also because we don't care if users know other users' information. Otherwise we would have had to hash so user 1 won't know the value for user 0, user 2 won't know the value for user 3, etc. + +```javascript +// Convert between the string the hash function expects and the +// BigInt we use everywhere else. +const hash = (x) => + BigInt(ethers.utils.keccak256("0x" + x.toString(16).padStart(64, 0))) +``` + +The ethers hash function expects to get a JavaScript string with a hexadecimal number, such as `0x60A7`, and responds with another string with the same structure. However, for the rest of the code it's easier to use `BigInt`, so we convert to a hexadecimal string and back again. + +```javascript +// Symmetrical hash of a pair so we won't care if the order is reversed. +const pairHash = (a, b) => hash(hash(a) ^ hash(b)) +``` + +This function is symmetrical (hash of a [xor](https://en.wikipedia.org/wiki/Exclusive_or) b). This means that when we check the Merkle proof we don't need to worry about whether to put the value from the proof before or after the calculated value. Merkle proof checking is done onchain, so the less we need to do there the better. + +Warning: +Cryptography is harder than it looks. +The initial version of this article had the hash function `hash(a^b)`. +That was a **bad** idea because it meant that if you knew the legitimate values of `a` and `b` you could use `b' = a^b^a'` to prove any desired `a'` value. +With this function you'd have to calculate `b'` such that `hash(a') ^ hash(b')` is equal to a known value (the next branch on the way to root), which is a lot harder. + +```javascript +// The value to denote that a certain branch is empty, doesn't +// have a value +const empty = 0n +``` + +When the number of values is not an integer power of two we need to handle empty branches. The way this program does it is to put zero as a place holder. + +![Merkle tree with branches missing](merkle-empty-hash.png) + +```javascript +// Calculate one level up the tree of a hash array by taking the hash of +// each pair in sequence +const oneLevelUp = (inputArray) => +``` + +To get the root, climb until there is only one value left. + +#### Creating a Merkle proof + +A Merkle proof is the values to hash together with the value being proved to get back the Merkle root. The value to prove is often available from other data, so I prefer to provide it separately rather than as part of the code. + +```javascript +// A merkle proof consists of the value of the list of entries to +// hash with. Because we use a symmetrical hash function, we don't +// need the item's location to verify the proof, only to create it +const getMerkleProof = (inputArray, n) =>   // while currentLayer.length > 1 + +    return result +}   // getMerkleProof +``` + +### Onchain code + +Finally we have the code that checks the proof. The onchain code is written in [Solidity](https://docs.soliditylang.org/en/v0.8.11/). Optimization is a lot more important here because gas is relatively expensive. + +```solidity +//SPDX-License-Identifier: Public Domain +pragma solidity ^0.8.0; + +import "hardhat/console.sol"; +``` + +I wrote this using the [Hardhat development environment](https://hardhat.org/), which allows us to have [console output from Solidity](https://hardhat.org/tutorial/debugging-with-hardhat-network.html) while developing. + +```solidity + +contract MerkleProof + +    // Extremely insecure, in production code access to +    // this function MUST BE strictly limited, probably to an +    // owner +    function setRoot(uint _merkleRoot) external   // setRoot +``` + +Set and get functions for the Merkle root. Letting everybody update the Merkle root is an _extremely bad idea_ in a production system. I do it here for the sake of simplicity for sample code. **Don't do it on a system where data integrity actually matters**. + +```solidity +    function hash(uint _a) internal pure returns(uint) + +    function pairHash(uint _a, uint _b) internal pure returns(uint) +``` + +This function generates a pair hash. It is just the Solidity translation of the JavaScript code for `hash` and `pairHash`. + +**Note:** This is another case of optimization for readability. Based on [the function definition](https://www.tutorialspoint.com/solidity/solidity_cryptographic_functions.htm), it might be possible to store the data as a [`bytes32`](https://docs.soliditylang.org/en/v0.5.3/types.html#fixed-size-byte-arrays) value and avoid the conversions. + +```solidity +    // Verify a Merkle proof +    function verifyProof(uint _value, uint[] calldata _proof) +        public view returns (bool) + +      return temp == merkleRoot; +    } + +}  // MarkleProof +``` + +In mathematical notation Merkle proof verification looks like this: `H(proof_n, H(proof_n-1, H(proof_n-2, ... H(proof_1, H(proof_0, value))...)))`. This code implements it. + +## Merkle proofs and rollups don't mix + +Merkle proofs don't work well with [rollups](/developers/docs/scaling/#rollups). The reason is that rollups write all the transaction data on L1, but process on L2. The cost to send a Merkle proof with a transaction averages to 638 gas per layer (currently a byte in call data costs 16 gas if it isn't zero, and 4 if it is zero). If we have 1024 words of data, a Merkle proof requires ten layers, or a total of 6380 gas. + +Looking for example at [Optimism](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m), writing L1 gas costs about 100 gwei and L2 gas costs 0.001 gwei (that is the normal price, it can rise with congestion). So for the cost of one L1 gas we can spend a hundred thousand gas on L2 processing. Assuming we don't overwrite storage, this means that we can write about five words to storage on L2 for the price of one L1 gas. For a single Merkle proof we can write the entire 1024 words to storage (assuming they can be calculated onchain to begin with, rather than provided in a transaction) and still have most of the gas left over. + +## Conclusion + +In real life you might never implement Merkle trees on your own. There are well known and audited libraries you can use and generally speaking it is best not to implement cryptographic primitives on your own. But I hope that now you understand Merkle proofs better and can decide when they are worth using. + +Note that while Merkle proofs preserve _integrity_, they do not preserve _availability_. Knowing that nobody else can take your assets is small consolation if the data storage decides to disallow access and you can't construct a Merkle tree to access them either. So Merkle trees are best used with some kind of decentralized storage, such as IPFS. + +--- + +## Developers > Tutorials > Monitoring Geth With Influxdb And Grafana + +This tutorial will help you set up monitoring for your Geth node so you can better understand its performance and identify potential problems. + +## Prerequisites + +- You should already be running an instance of Geth. +- Most of the steps and examples are for linux environment, basic terminal knowledge will be helpful. +- Check out this video overview of Geth's suite of metrics: [Monitoring an Ethereum infrastructure by Péter Szilágyi](https://www.youtube.com/watch?v=cOBab8IJMYI). + +## Monitoring stack + +An Ethereum client collects lots of data which can be read in the form of a chronological database. To make monitoring easier, you can feed this into data visualisation software. There are multiple options available: + +- [Prometheus](https://prometheus.io/) (pull model) +- [InfluxDB](https://www.influxdata.com/get-influxdb/) (push model) +- [Telegraf](https://www.influxdata.com/get-influxdb/) +- [Grafana](https://www.grafana.com/) +- [Datadog](https://www.datadoghq.com/) +- [Chronograf](https://www.influxdata.com/time-series-platform/chronograf/) + +There's also [Geth Prometheus Exporter](https://github.com/hunterlong/gethexporter), an option preconfigured with InfluxDB and Grafana. You can set it up easily using docker and [Ethbian OS](https://ethbian.org/index.html) for RPi 4. + +In this tutorial, we'll set up your Geth client to push data to InfluxDB to create a database and Grafana to create a graph visualisation of the data. Doing it manually will help you understand the process better, alter it, and deploy in different environments. + +## Setting up InfluxDB + +First, let's download and install InfluxDB. Various download options can be found at [Influxdata release page](https://portal.influxdata.com/downloads/). Pick the one that suits your environment. +You can also install it from a [repository](https://repos.influxdata.com/). For example in Debian based distribution: + +``` +curl -tlsv1.3 --proto =https -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add +source /etc/lsb-release +echo "deb https://repos.influxdata.com/$ $ stable" | sudo tee /etc/apt/sources.list.d/influxdb.list +sudo apt update +sudo apt install influxdb -y +sudo systemctl enable influxdb +sudo systemctl start influxdb +sudo apt install influxdb-client +``` + +After successfully installing InfluxDB, make sure it's running on background. By default, it is reachable at `localhost:8086`. +Before using `influx` client, you have to create new user with admin privileges. This user will serve for high level management, creating databases and users. + +``` +curl -XPOST "http://localhost:8086/query" --data-urlencode "q=CREATE USER username WITH PASSWORD 'password' WITH ALL PRIVILEGES" +``` + +Now you can use influx client to enter [InfluxDB shell](https://docs.influxdata.com/influxdb/v1.8/tools/shell/) with this user. + +``` +influx -username 'username' -password 'password' +``` + +Directly communicating with InfluxDB in its shell, you can create database and user for geth metrics. + +``` +create database geth +create user geth with password choosepassword +``` + +Verify created entries with: + +``` +show databases +show users +``` + +Leave InfluxDB shell. + +``` +exit +``` + +InfluxDB is running and configured to store metrics from Geth. + +## Preparing Geth + +After setting up database, we need to enable metrics collection in Geth. Pay attention to `METRICS AND STATS OPTIONS` in `geth --help`. Multiple options can be found there, in this case we want Geth to push data into InfluxDB. +Basic setup specifies endpoint where InfluxDB is reachable and authentication for the database. + +``` +geth --metrics --metrics.influxdb --metrics.influxdb.endpoint "http://0.0.0.0:8086" --metrics.influxdb.username "geth" --metrics.influxdb.password "chosenpassword" +``` + +This flags can be appended to a command starting the client or saved to the configuration file. + +You can verify that Geth is successfully pushing data, for instance by listing metrics in database. In InfluxDB shell: + +``` +use geth +show measurements +``` + +## Setting up Grafana + +Next step is installing Grafana which will interpret data graphically. Follow installation process for your environment in Grafana documentation. Make sure to install OSS version if you don't want otherwise. +Example installation steps for Debian distributions using repository: + +``` +curl -tlsv1.3 --proto =https -sL https://packages.grafana.com/gpg.key | sudo apt-key add - +echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list +sudo apt update +sudo apt install grafana +sudo systemctl enable grafana-server +sudo systemctl start grafana-server +``` + +When you've got Grafana running, it should be reachable at `localhost:3000`. +Use your preferred browser to access this path, then login with the default credentials (user: `admin` and password: `admin`). When prompted, change the default password and save. + +![](./grafana1.png) + +You will be redirected to the Grafana home page. First, set up your source data. Click on the configuration icon in the left bar and select "Data sources". + +![](./grafana2.png) + +There aren't any data sources created yet, click on "Add data source" to define one. + +![](./grafana3.png) + +For this setup, select "InfluxDB" and proceed. + +![](./grafana4.png) + +Data source configuration is pretty straight forward if you are running tools on the same machine. You need to set the InfluxDB address and details for accessing the database. Refer to the picture below. + +![](./grafana5.png) + +If everything is complete and InfluxDB is reachable, click on "Save and test" and wait for the confirmation to pop up. + +![](./grafana6.png) + +Grafana is now set up to read data from InfluxDB. Now you need to create a dashboard which will interpret and display it. Dashboards properties are encoded in JSON files which can be created by anybody and easily imported. On the left bar, click on "Create and Import". + +![](./grafana7.png) + +For a Geth monitoring dashboard, copy the ID of [this dashboard](https://grafana.com/grafana/dashboards/13877/) and paste it in the "Import page" in Grafana. After saving the dashboard, it should look like this: + +![](./grafana8.png) + +You can modify your dashboards. Each panel can be edited, moved, removed or added. You can change your configurations. It's up to you! To learn more about how dashboards work, refer to [Grafana's documentation](https://grafana.com/docs/grafana/latest/dashboards/). +You might also be interested in [Alerting](https://grafana.com/docs/grafana/latest/alerting/). This lets you set up alert notifications for when metrics reach certain values. Various communication channels are supported. + +--- + +## Developers > Tutorials > Nft Minter + +One of the greatest challenges for developers coming from a Web2 background is figuring out how to connect your smart contract to a frontend project and interact with it. + +By building an NFT minter — a simple UI where you can input a link to your digital asset, a title, and a description — you'll learn how to: + +- Connect to MetaMask via your frontend project +- Call smart contract methods from your frontend +- Sign transactions using MetaMask + +In this tutorial, we will be using [React](https://reactjs.org/) as our frontend framework. Because this tutorial is primarily focused on Web3 development, we won't be spending much time breaking down React fundamentals. Instead, we'll be focusing on bringing functionality to our project. + +As a prerequisite, you should have a beginner-level understanding of React—know how components, props, useState/useEffect, and basic function calling works. If you've never heard of any of those terms before, you may want to check out this [Intro to React tutorial](https://reactjs.org/tutorial/tutorial.html). For the more visual learners, we highly recommend this excellent [Full Modern React Tutorial](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d) video series by Net Ninja. + +And if you haven't already, you'll definitely need an Alchemy account to complete this tutorial as well as build anything on the blockchain. Sign up for a free account [here](https://alchemy.com/). + +Without further ado, let's get started! + +## Making NFTs 101 + +Before we even start looking at any code, it's important to understand how making an NFT works. It involves two steps: + +### Publish an NFT smart contract on the Ethereum blockchain + +The biggest difference between the two NFT smart contract standards is that ERC-1155 is a multi-token standard and includes batch functionality, whereas with the ERC-721 is a single-token standard and therefore only supports transferring one token at a time. + +### Call the minting function + +Usually, this minting function requires you to pass in two variables as parameters, first the `recipient`, which specifies the address that will receive your freshly minted NFT, and second the NFT's `tokenURI`, a string that resolves to a JSON document describing the NFT's metadata. + +An NFT's metadata is really what brings it to life, allowing it to have properties, such as a name, description, image (or different digital asset), and other attributes. Here's [an example of a tokenURI](https://gateway.pinata.cloud/ipfs/QmSvBcb4tjdFpajGJhbFAWeK3JAxCdNQLQtr6ZdiSi42V2), which contains an NFT's metadata. + +In this tutorial, we're going to focus on part 2, calling an existing NFT's smart contract minting function using our React UI. + +[Here's a link](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE) to the ERC-721 NFT smart contract we will be calling in this tutorial. If you'd like to learn how we made it, we highly recommend that you check out our other tutorial, ["How to Create an NFT"](https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft). + +Cool, now that we understand how making an NFT works, let's clone our starter files! + +## Clone the starter files + +First, go to the [nft-minter-tutorial GitHub repository](https://github.com/alchemyplatform/nft-minter-tutorial) to get the starter files for this project. Clone this repository into your local environment. + +When you open this cloned `nft-minter-tutorial` repository, you'll notice that it contains two folders: `minter-starter-files` and `nft-minter`. + +- `minter-starter-files` contains the starter files (essentially the React UI) for this project. In this tutorial, **we will be working in this directory**, as you learn how to bring this UI to life by connecting it to your Ethereum wallet and an NFT smart contract. +- `nft-minter` contains the entire completed tutorial and is there for you as a **reference** **if you get stuck.** + +Next, open your copy of `minter-starter-files` in your code editor, and then navigate into your `src` folder. + +All of the code we'll write will live under the `src` folder. We'll be editing the `Minter.js` component and writing additional javascript files to give our project Web3 functionality. + +## Step 2: Check out our starter files + +Before we start coding, it's important to check out what's already provided for us in the starter files. + +### Get your react project running + +Let's start by running the React project in our browser. The beauty of React is that once we have our project running in our browser, any changes we save will be updated live in our browser. + +To get the project running, navigate to the root directory of the `minter-starter-files` folder, and the run `npm install` in your terminal to install the dependencies of the project: + +```bash +cd minter-starter-files +npm install +``` + +Once those have finished installing, run `npm start` in your terminal: + +```bash +npm start +``` + +Doing so should open http://localhost:3000/ in your browser, where you'll see the frontend for our project. It should consist of 3 fields: a place to input a link to your NFT's asset, enter the name of your NFT, and provide a description. + +If you try clicking "Connect Wallet" or "Mint NFT" buttons, you'll notice they don't work—that's because we still need to program their functionality! :\) + +### The Minter.js component + +**NOTE:** Make sure you're in the `minter-starter-files` folder and not the `nft-minter` folder! + +Let's go back into the `src` folder in our editor and open the `Minter.js` file. It's super important that we understand everything in this file, as it is the primary React component we will be working on. + +At the top of our this file, we have our state variables that we will update after specific events. + +```javascript +//State variables +const [walletAddress, setWallet] = useState("") +const [status, setStatus] = useState("") +const [name, setName] = useState("") +const [description, setDescription] = useState("") +const [url, setURL] = useState("") +``` + +Never heard of React state variables or state hooks? Check out [these](https://reactjs.org/docs/hooks-state.html) docs. + +Here's what each of the variables represent: + +- `walletAddress` - a string that stores the user's wallet address +- `status` - a string that contains a message to display at the bottom of the UI +- `name` - a string that stores the NFT's name +- `description` - a string that stores the NFT's description +- `url` - a string that is a link to the NFT's digital asset + +After the state variables, you'll see three un-implemented functions: `useEffect`, `connectWalletPressed`, and `onMintPressed`. You'll notice that all of these functions are `async`, that's because we will be making asynchronous API calls in them! Their names are eponymous with their functionalities: + +```javascript +useEffect(async () => , []) + +const connectWalletPressed = async () => + +const onMintPressed = async () => +``` + +- [`useEffect`](https://reactjs.org/docs/hooks-effect.html) - this is a React hook that is called after your component is rendered. Because it has an empty array `[]` prop passed into it (see line 3), it will only be called on the component's _first_ render. Here we'll call our wallet listener and another wallet function to update our UI to reflect whether a wallet is already connected. +- `connectWalletPressed` - this function will be called to connect the user's MetaMask wallet to our dapp. +- `onMintPressed` - this function will be called to mint the user's NFT. + +Near the end of this file, we have the UI of our component. If you scan this code carefully, you'll notice that we update our `url`, `name`, and `description` state variables when the input in their corresponding text fields change. + +You'll also see that `connectWalletPressed` and `onMintPressed` are called when the buttons with IDs `mintButton` and `walletButton` are clicked respectively. + +```javascript +//the UI of our component +return ( + + + + + + + 🧙‍♂️ Alchemy NFT Minter + + Simply add your asset's link, name, and description, then press "Mint." + + + 🖼 Link to asset: + " + onChange= + /> + 🤔 Name: + setName(event.target.value)} + /> + ✍️ Description: + setDescription(event.target.value)} + /> + + + Mint NFT + + + +) +``` + +Finally, let's address where is this Minter component added. + +If you go to the `App.js` file, which is the main component in React that acts as a container for all other components, you'll see that our Minter component is injected on line 7. + +**In this tutorial, we'll only be editing the `Minter.js file` and adding files in our `src` folder.** + +Now that we understand what we're working with, let's set up our Ethereum wallet! + +## Set up your Ethereum wallet + +For users to be able to interact with your smart contract they will need to connect their Ethereum wallet to your dapp. + +### Download MetaMask + +For this tutorial, we’ll use MetaMask, a virtual wallet in the browser used to manage your Ethereum account address. If you want to understand more about how transactions on Ethereum work, check out [this page](/developers/docs/transactions/). + +You can download and create a MetaMask account for free [here](https://metamask.io/download). When you are creating an account, or if you already have an account, make sure to switch over to the “Ropsten Test Network” in the upper right \(so that we’re not dealing with real money\). + +### Add ether from a Faucet + +In order to mint our NFTs (or sign any transactions on the Ethereum blockchain), we’ll need some fake Eth. To get Eth you can go to the [Ropsten faucet](https://faucet.ropsten.be/) and enter your Ropsten account address, then click “Send Ropsten Eth.” You should see Eth in your MetaMask account soon after! + +### Check your balance + +To double check our balance is there, let’s make an [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) request using [Alchemy’s composer tool](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D). This will return the amount of Eth in our wallet. After you input your MetaMask account address and click “Send Request”, you should see a response like this: + +```text + +``` + +**NOTE:** This result is in wei not eth. Wei is used as the smallest denomination of ether. The conversion from wei to eth is: 1 eth = 10¹⁸ wei. So if we convert 0xde0b6b3a7640000 to decimal we get 1\*10¹⁸ which equals 1 eth. + +Phew! Our fake money is all there! + +## Connect MetaMask to your UI + +Now that our MetaMask wallet is set up, let's connect our dapp to it! + +Because we want to prescribe to the [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) paradigm, we're going to create a separate file that contains our functions to manage the logic, data, and rules of our dapp, and then pass those functions to our frontend (our Minter.js component). + +### The `connectWallet` function + +To do so, let's create a new folder called `utils` in your `src` directory and add a file called `interact.js` inside it, which will contain all of our wallet and smart contract interaction functions. + +In our `interact.js` file, we will write a `connectWallet` function, which we will then import and call in our `Minter.js` component. + +In your `interact.js` file, add the following + +```javascript +export const connectWallet = async () => ) + const obj = + return obj + } catch (err) + } + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your + browser. + + + + ), + } + } +} +``` + +Let's breakdown what this code does: + +First, our function checks if it `window.ethereum` is enabled in your browser. + +`window.ethereum` is a global API injected by MetaMask and other wallet providers that allows websites to request users' Ethereum accounts. If approved, it can read data from the blockchains the user is connected to, and suggest that the user sign messages and transactions. Check out the [MetaMask docs](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents) for more info! + +If `window.ethereum` _is not_ present, then that means MetaMask is not installed. This results in a JSON object being returned, where `address` returned is an empty string, and the `status` JSX object relays that the user must install MetaMask. + +**Most of the functions we write will be returning JSON objects that we can use to update our state variables and UI.** + +Now if `window.ethereum` _is_ present, then that's when things get interesting. + +Using a try/catch loop, we'll try to connect to MetaMask by calling [`window.ethereum.request();`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts). Calling this function will open up MetaMask in the browser, whereby the user will be prompted to connect their wallet to your dapp. + +- If the user chooses to connect, `method: "eth_requestAccounts"` will return an array that contains all of the user's account addresses that are connected to the dapp. Altogether, our `connectWallet` function will return a JSON object that contains the _first_ `address` in this array \(see line 9\) and a `status` message that prompts the user to write a message to the smart contract. +- If the user rejects the connection, then the JSON object will contain an empty string for the `address` returned and a `status` message that reflects that the user rejected the connection. + +### Add connectWallet function to your Minter.js UI Component + +Now that we've written this `connectWallet` function, let's connect it to our `Minter.js.` component. + +First, we'll have to import our function into our `Minter.js` file by adding `import from "./utils/interact.js";` to the top of the `Minter.js` file. Your first 11 lines of `Minter.js` should now look like this: + +```javascript + +const Minter = (props) => +``` + +Notice how most of our functionality is abstracted away from our `Minter.js` component from the `interact.js` file? This is so we comply with the M-V-C paradigm! + +In `connectWalletPressed`, we simply make an await call to our imported `connectWallet` function, and using its response, we update our `status` and `walletAddress` variables via their state hooks. + +Now, let's save both files `Minter.js` and `interact.js` and test out our UI so far. + +Open your browser on localhost:3000, and press the "Connect Wallet" button on the top right of the page. + +If you have MetaMask installed, you should be prompted to connect your wallet to your dapp. Accept the invitation to connect. + +You should see that the wallet button now reflects that your address is connected. + +Next, try refreshing the page... this is strange. Our wallet button is prompting us to connect MetaMask, even though it is already connected... + +Don't worry though! We easily can fix that by implementing a function called `getCurrentWalletConnected`, which will check if an address is already connected to our dapp and update our UI accordingly! + +### The getCurrentWalletConnected function + +In your `interact.js` file, add the following `getCurrentWalletConnected` function: + +```javascript +export const getCurrentWalletConnected = async () => ) + if (addressArray.length > 0) + } else + } + } catch (err) + } + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your + browser. + + + + ), + } + } +} +``` + +This code is _very_ similar to the `connectWallet` function we just wrote earlier. + +The main difference is that instead of calling the method `eth_requestAccounts`, which opens MetaMask for the user to connect their wallet, here we call the method `eth_accounts`, which simply returns an array containing the MetaMask addresses currently connected to our dapp. + +To see this function in action, let's call it in the `useEffect` function of our `Minter.js` component. + +Like we did for `connectWallet`, we must import this function from our `interact.js` file into our `Minter.js` file like so: + +```javascript +import from "./utils/interact.js" +``` + +Now, we simply call it in our `useEffect` function: + +```javascript +useEffect(async () => = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) +}, []) +``` + +Notice, we use the response of our call to `getCurrentWalletConnected` to update our `walletAddress` and `status` state variables. + +Once you've added this code, try refreshing our browser window. The button should say that you're connected, and show a preview of your connected wallet's address - even after you refresh! + +### Implement addWalletListener + +The final step in our dapp wallet setup is implementing the wallet listener so our UI updates when our wallet's state changes, such as when the user disconnects or switches accounts. + +In your `Minter.js` file, add a function `addWalletListener` that looks like the following: + +```javascript +function addWalletListener() else + }) + } else + 🦊 + You must install MetaMask, a virtual Ethereum wallet, in your browser. + + + ) + } +} +``` + +Let's quickly break down what's happening here: + +- First, our function checks if `window.ethereum` is enabled \(i.e. MetaMask is installed\). + - If it's not, we simply set our `status` state variable to a JSX string that prompts the user to install MetaMask. + - If it is enabled, we set up the listener `window.ethereum.on("accountsChanged")` on line 3 that listens for state changes in the MetaMask wallet, which include when the user connects an additional account to the dapp, switches accounts, or disconnects an account. If there is at least one account connected, the `walletAddress` state variable is updated as the first account in the `accounts` array returned by the listener. Otherwise, `walletAddress` is set as an empty string. + +Finally, we must call it in our `useEffect` function: + +```javascript +useEffect(async () => = await getCurrentWalletConnected() + setWallet(address) + setStatus(status) + + addWalletListener() +}, []) +``` + +And voila! We've completed programming all of our wallet functionality! Now that our wallet is set up, let's figure out how to mint our NFT! + +## NFT Metadata 101 + +So remember the NFT metadata we just talked about in Step 0 of this tutorial—it brings an NFT to life, allowing it to have properties, such as a digital asset, name, description, and other attributes. + +We're going to need to configure this metadata as a JSON object and store it, so we can pass it in as the `tokenURI` parameter when calling our smart contract's `mintNFT` function. + +The text in the "Link to Asset", "Name", "Description" fields will comprise the different properties of our NFT's metadata. We'll format this metadata as a JSON object, but there are a couple options for where we can store this JSON object: + +- We could store it on the Ethereum blockchain; however, doing so would be very expensive. +- We could store it on a centralized server, like AWS or Firebase. But that would defeat our decentralization ethos. +- We could use IPFS, a decentralized protocol and peer-to-peer network for storing and sharing data in a distributed file system. As this protocol is decentralized and free, it is our best option! + +To store our metadata on IPFS, we will use [Pinata](https://pinata.cloud/), a convenient IPFS API and toolkit. In the next step, we'll explain exactly how to do this! + +## Use Pinata to pin your metadata to IPFS + +If you don't have a [Pinata](https://pinata.cloud/) account, sign up for a free account [here](https://app.pinata.cloud/auth/signup) and complete the steps to verify your email and account. + +### Create your Pinata API key + +Navigate to the [https://pinata.cloud/keys](https://pinata.cloud/keys) page, then select the "New Key" button at the top, set the Admin widget as enabled, and name your key. + +You'll then be shown a popup with your API info. Make sure to put this somewhere safe. + +Now that our key is set up, let's add it to our project so we can use it. + +### Create a .env file + +We can safely store our Pinata key and secret in an environment file. Let's install the [dotenv package](https://www.npmjs.com/package/dotenv) in your project directory. + +Open up a new tab in your terminal \(separate from the one running local host\) and make sure you are in the `minter-starter-files` folder, then run the following command in your terminal: + +```text +npm install dotenv --save +``` + +Next, create a `.env` file in the root directory of your `minter-starter-files` by entering the following on your command line: + +```javascript +vim.env +``` + +This will pop open your `.env` file in vim \(a text editor\). To save it hit "esc" + ":" + "q" on your keyboard in that order. + +Next, in VSCode, navigate to your `.env` file and add your Pinata API key and API secret to it, like so: + +```text +REACT_APP_PINATA_KEY = +REACT_APP_PINATA_SECRET = +``` + +Save the file, and then you're ready to start writing the function to upload your JSON metadata to IPFS! + +### Implement pinJSONToIPFS + +Fortunately for us, Pinata has an [API specifically for uploading JSON data to IPFS](https://docs.pinata.cloud/api-reference/endpoint/ipfs/pin-json-to-ipfs#pin-json) and a convenient JavaScript with axios example that we can use, with some slight modifications. + +In your `utils` folder, let's create another file called `pinata.js` and then import our Pinata secret and key from the .env file like so: + +```javascript +require("dotenv").config() +const key = process.env.REACT_APP_PINATA_KEY +const secret = process.env.REACT_APP_PINATA_SECRET +``` + +Next, paste the additional code from below into your `pinata.js` file. Don't worry, we'll break down what everything means! + +```javascript +require("dotenv").config() +const key = process.env.REACT_APP_PINATA_KEY +const secret = process.env.REACT_APP_PINATA_SECRET + +const axios = require("axios") + +export const pinJSONToIPFS = async (JSONBody) => , + }) + .then(function (response) + }) + .catch(function (error) + }) +} +``` + +So what does this code do exactly? + +First, it imports [axios](https://www.npmjs.com/package/axios), a promise based HTTP client for the browser and node.js, which we will use to make a request to Pinata. + +Then we have our asynchronous function `pinJSONToIPFS`, which takes a `JSONBody` as its input and the Pinata api key and secret in its header, all to make a POST request to their `pinJSONToIPFS` API. + +- If this POST request is successful, then our function returns a JSON object with the `success` boolean as true and the `pinataUrl` where our metadata was pinned. We will use this `pinataUrl` returned as the `tokenURI` input to our smart contract's mint function. +- If this post request fails, then our function returns a JSON object with the `success` boolean as false and a `message` string that relays our error. + +As with our `connectWallet`function return types, we're returning JSON objects so we can use their parameters to update our state variables and UI. + +## Load your smart contract + +Now that we have a way to upload our NFT metadata to IPFS via our `pinJSONToIPFS` function, we're going to need a way to load an instance of our smart contract so we can call its `mintNFT` function. + +As we mentioned earlier, in this tutorial we will be using [this existing NFT smart contract](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE); however, if you'd like to learn how we made it, or make one yourself, we highly recommend you check out our other tutorial, ["How to Create an NFT."](https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft). + +### The contract ABI + +If you examined our files closely, you'll have noticed that in our `src` directory, there's a `contract-abi.json` file. An ABI is necessary for specifying which function a contract will invoke as well ensuring that the function will return data in the format you're expecting. + +We're also going to need an Alchemy API key and the Alchemy Web3 API to connect to the Ethereum blockchain and load our smart contract. + +### Create your Alchemy API key + +If you don't already have an Alchemy account, [sign up for free here.](https://alchemy.com/?a=eth-org-nft-minter) + +Once you’ve created an Alchemy account, you can generate an API key by creating an app. This will allow us to make requests to the Ropsten test network. + +Navigate to the “Create App” page in your Alchemy Dashboard by hovering over “Apps” in the nav bar and clicking “Create App”. + +Name your app we chose "My First NFT!", offer a short description, select “Staging” for the Environment used for your app bookkeeping, and choose “Ropsten” for your network. + +Click “Create app” and that’s it! Your app should appear in the table below. + +Awesome so now that we've created our HTTP Alchemy API URL, copy it to your clipboard... + +…and then let's add it to our `.env` file. Altogether, your .env file should look like this: + +```text +REACT_APP_PINATA_KEY = +REACT_APP_PINATA_SECRET = +REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/ +``` + +Now that we have our contract ABI and our Alchemy API key, we're ready to load our smart contract using [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3). + +### Set up your Alchemy Web3 endpoint and contract + +First, if you don't have it already, you'll need to install [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) by navigating to the home directory: `nft-minter-tutorial` in the terminal: + +```text +cd .. +npm install @alch/alchemy-web3 +``` + +Next let's go back to our `interact.js` file. At the top of the file, add the following code to import your Alchemy key from your .env file and set up your Alchemy Web3 endpoint: + +```javascript +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) +``` + +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) is a wrapper around [Web3.js](https://docs.web3js.org/), providing enhanced API methods and other crucial benefits to make your life as a web3 developer easier. It is designed to require minimal configuration so you can start using it in your app right away! + +Next, let's add our contract ABI and contract address to our file. + +```javascript +require("dotenv").config() +const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY +const = require("@alch/alchemy-web3") +const web3 = createAlchemyWeb3(alchemyKey) + +const contractABI = require("../contract-abi.json") +const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE" +``` + +Once we have both of those, we're ready to start coding our mint function! + +## Implement the mintNFT function + +Inside your `interact.js` file, let's define our function, `mintNFT`, which eponymously will mint our NFT. + +Because we will be making numerous asynchronous calls \(to Pinata to pin our metadata to IPFS, Alchemy Web3 to load our smart contract, and MetaMask to sign our transactions\), our function will also be asynchronous. + +The three inputs to our function will be the `url` of our digital asset, `name`, and `description`. Add the following function signature below the `connectWallet` function: + +```javascript +export const mintNFT = async (url, name, description) => {} +``` + +### Input error handling + +Naturally, it makes sense to have some sort of input error handling at the start of the function, so we exit this function if our input parameters aren't correct. Inside our function, let's add the following code: + +```javascript +export const mintNFT = async (url, name, description) => + } +} +``` + +Essentially, if any of the input parameters are an empty string, then we return a JSON object where the `success` boolean is false, and the `status` string relays that all fields in our UI must be complete. + +### Upload the metadata to IPFS + +Once we know our metadata is formatted properly, the next step is to wrap it into a JSON object and upload it to IPFS via the `pinJSONToIPFS` we wrote! + +To do so, we first we need to import the `pinJSONToIPFS` function into our `interact.js` file. At the very top of the `interact.js`, let's add: + +```javascript +``` + +Recall that `pinJSONToIPFS` takes in a JSON body. So before we make a call to it, we're going to need to format our `url`, `name`, and `description` parameters into a JSON object. + +Let's update our code to create a JSON object called `metadata` and then make a call to `pinJSONToIPFS` with this `metadata` parameter: + +```javascript +export const mintNFT = async (url, name, description) => + } + + //make metadata + const metadata = new Object() + metadata.name = name + metadata.image = url + metadata.description = description + + //make pinata call + const pinataResponse = await pinJSONToIPFS(metadata) + if (!pinataResponse.success) + } + const tokenURI = pinataResponse.pinataUrl +} +``` + +Notice, we store the response of our call to `pinJSONToIPFS(metadata)` in the `pinataResponse` object. Then, we parse this object for any errors. + +If there's an error, we return a JSON object where the `success` boolean is false and our `status` string relays that our call failed. Otherwise, we extract the `pinataURL` from the `pinataResponse` and store it as our `tokenURI` variable. + +Now it's time to load our smart contract using the Alchemy Web3 API that we initialized at the top of our file. Add the following line of code to the bottom of the `mintNFT` function to set the contract at the `window.contract` global variable: + +```javascript +window.contract = await new web3.eth.Contract(contractABI, contractAddress) +``` + +The last thing to add in our `mintNFT` function is our Ethereum transaction: + +```javascript +//set up your Ethereum transaction +const transactionParameters = + +//sign the transaction via MetaMask +try ) + return +} catch (error) +} +``` + +If you're already familiar with Ethereum transactions, you'll notice that the structure is pretty similar to what you've seen. + +- First, we set up our transactions parameters. + - `to` specifies the recipient address \(our smart contract\) + - `from` specifies the signer of the transaction \(the user's connected address to MetaMask: `window.ethereum.selectedAddress`\) + - `data` contains the call to our smart contract `mintNFT` method, which receives our `tokenURI` and the user's wallet address, `window.ethereum.selectedAddress`, as inputs +- Then, we make an await call, `window.ethereum.request,` where we ask MetaMask to sign the transaction. Notice, in this request, we're specifying our eth method \(eth_SentTransaction\) and passing in our `transactionParameters`. At this point, MetaMask will open up in the browser, and prompt the user to sign or reject the transaction. + - If the transaction is successful, the function will return a JSON object where the boolean `success` is set to true and the `status` string prompts the user to check out Etherscan for more information about their transaction. + - If the transaction fails, the function will return a JSON object where the `success` boolean is set to false, and the `status` string relays the error message. + +Altogether, our `mintNFT` function should look like this: + +```javascript +export const mintNFT = async (url, name, description) => + } + + //make metadata + const metadata = new Object() + metadata.name = name + metadata.image = url + metadata.description = description + + //pinata pin request + const pinataResponse = await pinJSONToIPFS(metadata) + if (!pinataResponse.success) + } + const tokenURI = pinataResponse.pinataUrl + + //load smart contract + window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract(); + + //set up your Ethereum transaction + const transactionParameters = + + //sign transaction via MetaMask + try ) + return + } catch (error) + } +} +``` + +That's one giant function! Now, we just need to connect our `mintNFT` function to our `Minter.js` component... + +## Connect mintNFT to our Minter.js frontend + +Open up your `Minter.js` file and update the `import from "./utils/interact.js";` line at the top to be: + +```javascript +import from "./utils/interact.js" +``` + +Finally, implement the `onMintPressed` function to make await call to your imported `mintNFT`function and update the `status` state variable to reflect whether our transaction succeeded or failed: + +```javascript +const onMintPressed = async () => = await mintNFT(url, name, description) + setStatus(status) +} +``` + +## Deploy your NFT to a live website + +Ready to take your project live for users to interact with? Check out [this tutorial](https://docs.alchemy.com/alchemy/tutorials/nft-minter/how-do-i-deploy-nfts-online) for deploying your Minter to a live website. + +One last step... + +## Take the blockchain world by storm + +Just kidding, you made it to the end of the tutorial! + +To recap, by building an NFT minter, you successfully learned how to: + +- Connect to MetaMask via your frontend project +- Call smart contract methods from your frontend +- Sign transactions using MetaMask + +Presumably, you'd like to be able to show off the NFTs minted via your dapp in your wallet — so be sure to check out our quick tutorial [How to View Your NFT in Your Wallet](https://docs.alchemyapi.io/alchemy/tutorials/how-to-write-and-deploy-a-nft-smart-contract/how-to-view-your-nft-in-your-wallet)! + +And, as always, if you have any questions, we're here to help in the [Alchemy Discord](https://discord.gg/gWuC7zB). We can't wait to see how you apply the concepts from this tutorial to your future projects! + +--- + +## Developers > Tutorials > Optimism Std Bridge Annotated Code + +[Optimism](https://www.optimism.io/) is an [Optimistic Rollup](/developers/docs/scaling/optimistic-rollups/). +Optimistic rollups can process transactions for a much lower price than Ethereum Mainnet (also known as layer 1 or L1) because transactions are only processed by a few nodes, instead of every node on the network. +At the same time, the data is all written to L1 so everything can be proved and reconstructed with all the integrity and availability guarantees of Mainnet. + +To use L1 assets on Optimism (or any other L2), the assets need to be [bridged](/bridges/#prerequisites). +One way to achieve this is for users to lock assets (ETH and [ERC-20 tokens](/developers/docs/standards/tokens/erc-20/) are the most common ones) on L1, and receive equivalent assets to use on L2. +Eventually, whoever ends up with them might want to bridge them back to L1. +When doing this, the assets are burned on L2 and then released back to the user on L1. + +This is the way the [Optimism standard bridge](https://docs.optimism.io/app-developers/bridging/standard-bridge) works. +In this article we go over the source code for that bridge to see how it works and study it as an example of well written Solidity code. + +## Control flows + +The bridge has two main flows: + +- Deposit (from L1 to L2) +- Withdrawal (from L2 to L1) + +### Deposit flow + +#### Layer 1 + +1. If depositing an ERC-20, the depositor gives the bridge an allowance to spend the amount being deposited +2. The depositor calls the L1 bridge (`depositERC20`, `depositERC20To`, `depositETH`, or `depositETHTo`) +3. The L1 bridge takes possession of the bridged asset + - ETH: The asset is transferred by the depositor as part of the call + - ERC-20: The asset is transferred by the bridge to itself using the allowance provided by the depositor +4. The L1 bridge uses the cross-domain message mechanism to call `finalizeDeposit` on the L2 bridge + +#### Layer 2 + +5. The L2 bridge verifies the call to `finalizeDeposit` is legitimate: + - Came from the cross domain message contract + - Was originally from the bridge on L1 +6. The L2 bridge checks if the ERC-20 token contract on L2 is the correct one: + - The L2 contract reports that its L1 counterpart is the same as the one the tokens came from on L1 + - The L2 contract reports that it supports the correct interface ([using ERC-165](https://eips.ethereum.org/EIPS/eip-165)). +7. If the L2 contract is the correct one, call it to mint the appropriate number of tokens to the appropriate address. If not, start a withdrawal process to allow the user to claim the tokens on L1. + +### Withdrawal flow + +#### Layer 2 + +1. The withdrawer calls the L2 bridge (`withdraw` or `withdrawTo`) +2. The L2 bridge burns the appropriate number of tokens belonging to `msg.sender` +3. The L2 bridge uses the cross-domain message mechanism to call `finalizeETHWithdrawal` or `finalizeERC20Withdrawal` on the L1 bridge + +#### Layer 1 + +4. The L1 bridge verifies the call to `finalizeETHWithdrawal` or `finalizeERC20Withdrawal` is legitimate: + - Came from the cross domain message mechanism + - Was originally from the bridge on L2 +5. The L1 bridge transfers the appropriate asset (ETH or ERC-20) to the appropriate address + +## Layer 1 code + +This is the code that runs on L1, the Ethereum Mainnet. + +### IL1ERC20Bridge + +[This interface is defined here](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/IL1ERC20Bridge.sol). +It includes functions and definitions required for bridging ERC-20 tokens. + +```solidity +// SPDX-License-Identifier: MIT +``` + +[Most of Optimism's code is released under the MIT license](https://help.optimism.io/hc/en-us/articles/4411908707995-What-software-license-does-Optimism-use-). + +```solidity +pragma solidity >0.5.0 0.5.0 0.5.0 mapping(address => uint256)) public deposits; +``` + +A double [mapping](https://www.tutorialspoint.com/solidity/solidity_mappings.htm) like this is the way you define a [two-dimensional sparse array](https://en.wikipedia.org/wiki/Sparse_matrix). +Values in this data structure are identified as `deposit[L1 token addr][L2 token addr]`. +The default value is zero. +Only cells that are set to a different value are written to storage. + +```solidity + + /*************** + * Constructor * + ***************/ + + // This contract lives behind a proxy, so the constructor parameters will go unused. + constructor() CrossDomainEnabled(address(0)) {} +``` + +To want to be able to upgrade this contract without having to copy all the variables in the storage. +To do that we use a [`Proxy`](https://docs.openzeppelin.com/contracts/3.x/api/proxy), a contract that uses [`delegatecall`](https://solidity-by-example.org/delegatecall/) to transfer calls to a separate contact whose address is stored by the proxy contract (when you upgrade you tell the proxy to change that address). +When you use `delegatecall` the storage remains the storage of the _calling_ contract, so the values of all the contract state variables are unaffected. + +One effect of this pattern is that the storage of the contract that is the _called_ of `delegatecall` is not used and therefore the constructor values passed to it do not matter. +This is the reason we can provide a nonsensical value to the `CrossDomainEnabled` constructor. +It is also the reason the initialization below is separate from the constructor. + +```solidity + /****************** + * Initialization * + ******************/ + + /** + * @param _l1messenger L1 Messenger address being used for cross-chain communications. + * @param _l2TokenBridge L2 standard bridge address. + */ + // slither-disable-next-line external-function +``` + +This [Slither test](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external) identifies functions that are not called from the contract code and could therefore be declared `external` instead of `public`. +The gas cost of `external` functions can be lower, because they can be provided with parameters in the calldata. +Functions declared `public` have to be accessible from within the contract. +Contracts cannot modify their own calldata, so the parameters have to be in memory. +When such a function is called externally, it is necessary to copy the calldata to memory, which costs gas. +In this case the function is only called once, so the inefficiency does not matter to us. + +```solidity + function initialize(address _l1messenger, address _l2TokenBridge) public +``` + +These are the two parameters that the bridge needs to know. + +```solidity + + /************** + * Depositing * + **************/ + + /** @dev Modifier requiring sender to be EOA. This check could be bypassed by a malicious + * contract via initcode, but it takes care of the user error we want to avoid. + */ + modifier onlyEOA() +``` + +This is the reason we needed OpenZeppelin's `Address` utilities. + +```solidity + /** + * @dev This function can be called with no data + * to deposit an amount of ETH to the caller's balance on L2. + * Since the receive function doesn't take data, a conservative + * default amount is forwarded to L2. + */ + receive() external payable onlyEOA +``` + +This function exists for testing purposes. +Notice that it doesn't appear in the interface definitions - it isn't for normal use. + +```solidity + /** + * @inheritdoc IL1StandardBridge + */ + function depositETH(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA + + /** + * @inheritdoc IL1StandardBridge + */ + function depositETHTo( + address _to, + uint32 _l2Gas, + bytes calldata _data + ) external payable +``` + +These two functions are wrappers around `_initiateETHDeposit`, the function that handles the actual ETH deposit. + +```solidity + /** + * @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of + * the deposit. + * @param _from Account to pull the deposit from on L1. + * @param _to Account to give the deposit to on L2. + * @param _l2Gas Gas limit required to complete the deposit on L2. + * @param _data Optional data to forward to L2. This data is provided + * solely as a convenience for external contracts. Aside from enforcing a maximum + * length, these contracts provide no guarantees about its content. + */ + function _initiateETHDeposit( + address _from, + address _to, + uint32 _l2Gas, + bytes memory _data + ) internal +``` + +Emit an event to inform any decentralized application that listens of this transfer. + +```solidity + /** + * @inheritdoc IL1ERC20Bridge + */ + function depositERC20( + . + . + . + ) external virtual onlyEOA + + /** + * @inheritdoc IL1ERC20Bridge + */ + function depositERC20To( + . + . + . + ) external virtual +``` + +These two functions are wrappers around `_initiateERC20Deposit`, the function that handles the actual ERC-20 deposit. + +```solidity + /** + * @dev Performs the logic for deposits by informing the L2 Deposited Token + * contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom) + * + * @param _l1Token Address of the L1 ERC20 we are depositing + * @param _l2Token Address of the L1 respective L2 ERC20 + * @param _from Account to pull the deposit from on L1 + * @param _to Account to give the deposit to on L2 + * @param _amount Amount of the ERC20 to deposit. + * @param _l2Gas Gas limit required to complete the deposit on L2. + * @param _data Optional data to forward to L2. This data is provided + * solely as a convenience for external contracts. Aside from enforcing a maximum + * length, these contracts provide no guarantees about its content. + */ + function _initiateERC20Deposit( + address _l1Token, + address _l2Token, + address _from, + address _to, + uint256 _amount, + uint32 _l2Gas, + bytes calldata _data + ) internal + + /************************* + * Cross-chain Functions * + *************************/ + + /** + * @inheritdoc IL1StandardBridge + */ + function finalizeETHWithdrawal( + address _from, + address _to, + uint256 _amount, + bytes calldata _data +``` + +The L2 bridge sends a message to the L2 cross domain messenger which causes the L1 cross domain messenger to call this function (once the [transaction that finalizes the message](https://community.optimism.io/docs/developers/bridge/messaging/#fees-for-l2-%E2%87%92-l1-transactions) is submitted on L1, of course). + +```solidity + ) external onlyFromCrossDomainAccount(l2TokenBridge) (new bytes(0)); +``` + +The way to transfer ETH is to call the recipient with the amount of wei in the `msg.value`. + +```solidity + require(success, "TransferHelper::safeTransferETH: ETH transfer failed"); + + // slither-disable-next-line reentrancy-events + emit ETHWithdrawalFinalized(_from, _to, _amount, _data); +``` + +Emit an event about the withdrawal. + +```solidity + } + + /** + * @inheritdoc IL1ERC20Bridge + */ + function finalizeERC20Withdrawal( + address _l1Token, + address _l2Token, + address _from, + address _to, + uint256 _amount, + bytes calldata _data + ) external onlyFromCrossDomainAccount(l2TokenBridge) + + + /***************************** + * Temporary - Migrating ETH * + *****************************/ + + /** + * @dev Adds ETH balance to the account. This is meant to allow for ETH + * to be migrated from an old gateway to a new gateway. + * NOTE: This is left for one upgrade only so we are able to receive the migrated ETH from the + * old contract + */ + function donateETH() external payable {} +} +``` + +There was an earlier implementation of the bridge. +When we moved from the implementation to this one, we had to move all the assets. +ERC-20 tokens can just be moved. +However, to transfer ETH to a contract you need that contract's approval, which is what `donateETH` provides us. + +## ERC-20 Tokens on L2 + +For an ERC-20 token to fit into the standard bridge, it needs to allow the standard bridge, and _only_ the standard bridge, to mint token. +This is necessary because the bridges need to ensure that the number of tokens circulating on Optimism is equal to the number of tokens locked inside the L1 bridge contract. +If there are too many tokens on L2 some users would be unable to bridge their assets back to L1. +Instead of a trusted bridge, we would essentially recreate [fractional reserve banking](https://www.investopedia.com/terms/f/fractionalreservebanking.asp). +If there are too many tokens on L1, some of those tokens would stay locked inside the bridge contract forever because there is no way to release them without burning L2 tokens. + +### IL2StandardERC20 + +Every ERC-20 token on L2 that uses the standard bridge needs to provide [this interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/IL2StandardERC20.sol), which has the functions and events that the standard bridge needs. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +``` + +[The standard ERC-20 interface](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) does not include the `mint` and `burn` functions. +Those methods are not required by [the ERC-20 standard](https://eips.ethereum.org/EIPS/eip-20), which leaves unspecified the mechanisms to create and destroy tokens. + +```solidity +``` + +[The ERC-165 interface](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol) is used to specify what functions a contract provides. +[You can read the standard here](https://eips.ethereum.org/EIPS/eip-165). + +```solidity +interface IL2StandardERC20 is IERC20, IERC165 +``` + +Functions and events to mint (create) and burn (destroy) tokens. +The bridge should be the only entity that can run these functions to ensure the number of tokens is correct (equal to the number of tokens locked on L1). + +### L2StandardERC20 + +[This is our implementation of the `IL2StandardERC20` interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/L2StandardERC20.sol). +Unless you need some kind of custom logic, you should use this one. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +``` + +[The OpenZeppelin ERC-20 contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol). +Optimism does not believe in reinventing the wheel, especially when the wheel is well audited and needs to be trustworthy enough to hold assets. + +```solidity +import "./IL2StandardERC20.sol"; + +contract L2StandardERC20 is IL2StandardERC20, ERC20 +``` + +First call the constructor for the contract we inherit from (`ERC20(_name, _symbol)`) and then set our own variables. + +```solidity + + modifier onlyL2Bridge() + + + // slither-disable-next-line external-function + function supportsInterface(bytes4 _interfaceId) public pure returns (bool) +``` + +This is the way [ERC-165](https://eips.ethereum.org/EIPS/eip-165) works. +Every interface is a number of supported functions, and is identified as the [exclusive or](https://en.wikipedia.org/wiki/Exclusive_or) of the [ABI function selectors](https://docs.soliditylang.org/en/v0.8.12/abi-spec.html#function-selector) of those functions. + +The L2 bridge uses ERC-165 as a sanity check to make sure that the ERC-20 contract to which it sends assets is an `IL2StandardERC20`. + +**Note:** There is nothing to prevent rogue contract from providing false answers to `supportsInterface`, so this is a sanity check mechanism, _not_ a security mechanism. + +```solidity + // slither-disable-next-line external-function + function mint(address _to, uint256 _amount) public virtual onlyL2Bridge + + // slither-disable-next-line external-function + function burn(address _from, uint256 _amount) public virtual onlyL2Bridge +} +``` + +Only the L2 bridge is allowed to mint and burn assets. + +`_mint` and `_burn` are actually defined in the [OpenZeppelin ERC-20 contract](/developers/tutorials/erc20-annotated-code/#the-_mint-and-_burn-functions-_mint-and-_burn). +That contract just doesn't expose them externally, because the conditions to mint and burn tokens are as varied as the number of ways to use ERC-20. + +## L2 Bridge Code + +This is code that runs the bridge on Optimism. +[The source for this contract is here](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2StandardBridge.sol). + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +/* Interface Imports */ +``` + +The [IL2ERC20Bridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/IL2ERC20Bridge.sol) interface is very similar to the [L1 equivalent](#IL1ERC20Bridge) we saw above. +There are two significant differences: + +1. On L1 you initiate deposits and finalize withdrawals. + Here you initiate withdrawals and finalize deposits. +2. On L1 it is necessary to distinguish between ETH and ERC-20 tokens. + On L2 we can use the same functions for both because internally ETH balances on Optimism are handled as an ERC-20 token with the address [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://optimistic.etherscan.io/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000). + +```solidity +/* Library Imports */ + +/* Contract Imports */ + +/** + * @title L2StandardBridge + * @dev The L2 Standard bridge is a contract which works together with the L1 Standard bridge to + * enable ETH and ERC20 transitions between L1 and L2. + * This contract acts as a minter for new tokens when it hears about deposits into the L1 Standard + * bridge. + * This contract also acts as a burner of the tokens intended for withdrawal, informing the L1 + * bridge to release L1 funds. + */ +contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled + + /*************** + * Withdrawing * + ***************/ + + /** + * @inheritdoc IL2ERC20Bridge + */ + function withdraw( + address _l2Token, + uint256 _amount, + uint32 _l1Gas, + bytes calldata _data + ) external virtual + + /** + * @inheritdoc IL2ERC20Bridge + */ + function withdrawTo( + address _l2Token, + address _to, + uint256 _amount, + uint32 _l1Gas, + bytes calldata _data + ) external virtual +``` + +These two functions initiate withdrawals. +Note that there is no needs to specify the L1 token address. +L2 tokens are expected to tell us the L1 equivalent's address. + +```solidity + + /** + * @dev Performs the logic for withdrawals by burning the token and informing + * the L1 token Gateway of the withdrawal. + * @param _l2Token Address of L2 token where withdrawal is initiated. + * @param _from Account to pull the withdrawal from on L2. + * @param _to Account to give the withdrawal to on L1. + * @param _amount Amount of the token to withdraw. + * @param _l1Gas Unused, but included for potential forward compatibility considerations. + * @param _data Optional data to forward to L1. This data is provided + * solely as a convenience for external contracts. Aside from enforcing a maximum + * length, these contracts provide no guarantees about its content. + */ + function _initiateWithdrawal( + address _l2Token, + address _from, + address _to, + uint256 _amount, + uint32 _l1Gas, + bytes calldata _data + ) internal else + + // Send message up to L1 bridge + // slither-disable-next-line reentrancy-events + sendCrossDomainMessage(l1TokenBridge, _l1Gas, message); + + // slither-disable-next-line reentrancy-events + emit WithdrawalInitiated(l1Token, _l2Token, msg.sender, _to, _amount, _data); + } + + /************************************ + * Cross-chain Function: Depositing * + ************************************/ + + /** + * @inheritdoc IL2ERC20Bridge + */ + function finalizeDeposit( + address _l1Token, + address _l2Token, + address _from, + address _to, + uint256 _amount, + bytes calldata _data +``` + +This function is called by `L1StandardBridge`. + +```solidity + ) external virtual onlyFromCrossDomainAccount(l1TokenBridge) else + } +} +``` + +## Conclusion + +The standard bridge is the most flexible mechanism for asset transfers. +However, because it is so generic it is not always the easiest mechanism to use. +Especially for withdrawals, most users prefer to use [third party bridges](https://optimism.io/apps#bridge) that do not wait the challenge period and do not require a Merkle proof to finalize the withdrawal. + +These bridges typically work by having assets on L1, which they provide immediately for a small fee (often less than the cost of gas for a standard bridge withdrawal). +When the bridge (or the people running it) anticipates being short on L1 assets it transfers sufficient assets from L2. As these are very big withdrawals, the withdrawal cost is amortized over a large amount and is a much smaller percentage. + +Hopefully this article helped you understand more about how layer 2 works, and how to write Solidity code that is clear and secure. + +--- + +## Developers > Tutorials > Reverse Engineering A Contract + +## Introduction + +_There are no secrets on the blockchain_, everything that happens is consistent, verifiable, and publicly available. Ideally, [contracts should have their source code published and verified on Etherscan](https://etherscan.io/address/0xb8901acb165ed027e32754e0ffe830802919727f#code). However, [that is not always the case](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#code). In this article you learn how to reverse engineer contracts by looking at a contract without source code, [`0x2510c039cc3b061d79e564b38836da87e31b342f`](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f). + +There are reverse compilers, but they don't always produce [usable results](https://etherscan.io/bytecode-decompiler?a=0x2510c039cc3b061d79e564b38836da87e31b342f). In this article you learn how to manually reverse engineer and understand a contract from [the opcodes](https://github.com/wolflo/evm-opcodes), as well as how to interpret the results of a decompiler. + +To be able to understand this article you should already know the basics of the EVM, and be at least somewhat familiar with EVM assembler. [You can read about these topics here](https://medium.com/mycrypto/the-ethereum-virtual-machine-how-does-it-work-9abac2b7c9e). + +## Prepare the Executable Code + +You can get the opcodes by going to Etherscan for the contract, clicking the **Contract** tab and then **Switch to Opcodes View**. You get a view that is one opcode per line. + +![Opcode View from Etherscan](opcode-view.png) + +To be able to understand jumps, however, you need to know where in the code each opcode is located. To do that, one way is to open a Google Spreadsheet and paste the opcodes in column C. [You can skip the following steps by making a copy of this already prepared spreadsheet](https://docs.google.com/spreadsheets/d/1tKmTJiNjUwHbW64wCKOSJxHjmh0bAUapt6btUYE7kDA/edit?usp=sharing). + +The next step is to get the correct code locations so we'll be able to understand jumps. We'll put the opcode size in column B, and the location (in hexadecimal) in column A. Type this function in cell `B1` and then copy and paste it for the rest of column B, until the end of the code. After you do this you can hide column B. + +``` +=1+IF(REGEXMATCH(C1,"PUSH"),REGEXEXTRACT(C1,"PUSH(\d+)"),0) +``` + +First this function adds one byte for the opcode itself, and then looks for `PUSH`. Push opcodes are special because they need to have additional bytes for the value being pushed. If the opcode is a `PUSH`, we extract the number of bytes and add that. + +In `A1` put the first offset, zero. Then, in `A2`, put this function and again copy and paste it for the rest of column A: + +``` +=dec2hex(hex2dec(A1)+B1) +``` + +We need this function to give us the hexadecimal value because the values that are pushed prior to jumps (`JUMP` and `JUMPI`) are given to us in hexadecimal. + +## The Entry Point (0x00) + +Contracts are always executed from the first byte. This is the initial part of the code: + +| Offset | Opcode | Stack (after the opcode) | +| -----: | ------------ | ------------------------ | +| 0 | PUSH1 0x80 | 0x80 | +| 2 | PUSH1 0x40 | 0x40, 0x80 | +| 4 | MSTORE | Empty | +| 5 | PUSH1 0x04 | 0x04 | +| 7 | CALLDATASIZE | CALLDATASIZE 0x04 | +| 8 | LT | CALLDATASIZE\2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AE | ISZERO | Value\*\first-32-bits-of-the-call-data (((first 32 bits (4 bytes) of the call data))) | +| 1A | PUSH2 0x0043 | 0x43 0x3CD8045E>first-32-bits-of-the-call-data (((first 32 bits (4 bytes) of the call data))) | +| 1D | JUMPI | (((first 32 bits (4 bytes) of the call data))) | + +By dividing the method signature matching tests in two like this saves half the tests on average. The code that immediately follows this and the code in 0x43 follow the same pattern: `DUP1` the first 32 bits of the call data, `PUSH4 (((method signature>`, run `EQ` to check for equality, and then `JUMPI` if the method signature matches. Here are the method signatures, their addresses, and if known [the corresponding method definition](https://www.4byte.directory/): + +| Method | Method signature | Offset to jump into | +| -------------------------------------------------------------------------------------- | ---------------- | ------------------- | +| [splitter()](https://www.4byte.directory/signatures/?bytes4_signature=0x3cd8045e) | 0x3cd8045e | 0x0103 | +| ??? | 0x81e580d3 | 0x0138 | +| [currentWindow()](https://www.4byte.directory/signatures/?bytes4_signature=0xba0bafb4) | 0xba0bafb4 | 0x0158 | +| ??? | 0x1f135823 | 0x00C4 | +| [merkleRoot()](https://www.4byte.directory/signatures/?bytes4_signature=0x2eb4a7ab) | 0x2eb4a7ab | 0x00ED | + +If no match is found, the code jumps to [the proxy handler at 0x7C](#the-handler-at-0x7c), in the hope that the contract to which we are a proxy has a match. + +![ABI calls flowchart](flowchart-abi.png) + +## splitter() + +| Offset | Opcode | Stack | +| -----: | ------------ | ----------------------------- | +| 103 | JUMPDEST | +| 104 | CALLVALUE | CALLVALUE | +| 105 | DUP1 | CALLVALUE CALLVALUE | +| 106 | ISZERO | CALLVALUE==0 CALLVALUE | +| 107 | PUSH2 0x010f | 0x010F CALLVALUE==0 CALLVALUE | +| 10A | JUMPI | CALLVALUE | +| 10B | PUSH1 0x00 | 0x00 CALLVALUE | +| 10D | DUP1 | 0x00 0x00 CALLVALUE | +| 10E | REVERT | + +The first thing this function does is check that the call did not send any ETH. This function is not [`payable`](https://solidity-by-example.org/payable/). If somebody sent us ETH that must be a mistake and we want to `REVERT` to avoid having that ETH where they can't get it back. + +| Offset | Opcode | Stack | +| -----: | ------------------------------------------------- | --------------------------------------------------------------------------- | +| 10F | JUMPDEST | +| 110 | POP | +| 111 | PUSH1 0x03 | 0x03 | +| 113 | SLOAD | (((Storage[3] a.k.a the contract for which we are a proxy))) | +| 114 | PUSH1 0x40 | 0x40 (((Storage[3] a.k.a the contract for which we are a proxy))) | +| 116 | MLOAD | 0x80 (((Storage[3] a.k.a the contract for which we are a proxy))) | +| 117 | PUSH20 0xffffffffffffffffffffffffffffffffffffffff | 0xFF...FF 0x80 (((Storage[3] a.k.a the contract for which we are a proxy))) | +| 12C | SWAP1 | 0x80 0xFF...FF (((Storage[3] a.k.a the contract for which we are a proxy))) | +| 12D | SWAP2 | (((Storage[3] a.k.a the contract for which we are a proxy))) 0xFF...FF 0x80 | +| 12E | AND | ProxyAddr 0x80 | +| 12F | DUP2 | 0x80 ProxyAddr 0x80 | +| 130 | MSTORE | 0x80 | + +And 0x80 now contains the proxy address + +| Offset | Opcode | Stack | +| -----: | ------------ | --------- | +| 131 | PUSH1 0x20 | 0x20 0x80 | +| 133 | ADD | 0xA0 | +| 134 | PUSH2 0x00e4 | 0xE4 0xA0 | +| 137 | JUMP | 0xA0 | + +### The E4 Code + +This is the first time we see these lines, but they are shared with other methods (see below). So we'll call the value in the stack X, and just remember that in `splitter()` the value of this X is 0xA0. + +| Offset | Opcode | Stack | +| -----: | ---------- | ----------- | +| E4 | JUMPDEST | X | +| E5 | PUSH1 0x40 | 0x40 X | +| E7 | MLOAD | 0x80 X | +| E8 | DUP1 | 0x80 0x80 X | +| E9 | SWAP2 | X 0x80 0x80 | +| EA | SUB | X-0x80 0x80 | +| EB | SWAP1 | 0x80 X-0x80 | +| EC | RETURN | + +So this code receives a memory pointer in the stack (X), and causes the contract to `RETURN` with a buffer that is 0x80 - X. + +In the case of `splitter()`, this returns the address for which we are a proxy. `RETURN` returns the buffer in 0x80-0x9F, which is where we wrote this data (offset 0x130 above). + +## currentWindow() + +The code in offsets 0x158-0x163 is identical to what we saw in 0x103-0x10E in `splitter()` (other than the `JUMPI` destination), so we know `currentWindow()` is also not `payable`. + +| Offset | Opcode | Stack | +| -----: | ------------ | -------------------- | +| 164 | JUMPDEST | +| 165 | POP | +| 166 | PUSH2 0x00da | 0xDA | +| 169 | PUSH1 0x01 | 0x01 0xDA | +| 16B | SLOAD | Storage[1] 0xDA | +| 16C | DUP2 | 0xDA Storage[1] 0xDA | +| 16D | JUMP | Storage[1] 0xDA | + +### The DA code + +This code is also shared with other methods. So we'll call the value in the stack Y, and just remember that in `currentWindow()` the value of this Y is Storage[1]. + +| Offset | Opcode | Stack | +| -----: | ---------- | ---------------- | +| DA | JUMPDEST | Y 0xDA | +| DB | PUSH1 0x40 | 0x40 Y 0xDA | +| DD | MLOAD | 0x80 Y 0xDA | +| DE | SWAP1 | Y 0x80 0xDA | +| DF | DUP2 | 0x80 Y 0x80 0xDA | +| E0 | MSTORE | 0x80 0xDA | + +Write Y to 0x80-0x9F. + +| Offset | Opcode | Stack | +| -----: | ---------- | -------------- | +| E1 | PUSH1 0x20 | 0x20 0x80 0xDA | +| E3 | ADD | 0xA0 0xDA | + +And the rest is already explained [above](#the-e4-code). So jumps to 0xDA write the stack top (Y) to 0x80-0x9F, and return that value. In the case of `currentWindow()`, it returns Storage[1]. + +## merkleRoot() + +The code in offsets 0xED-0xF8 is identical to what we saw in 0x103-0x10E in `splitter()` (other than the `JUMPI` destination), so we know `merkleRoot()` is also not `payable`. + +| Offset | Opcode | Stack | +| -----: | ------------ | -------------------- | +| F9 | JUMPDEST | +| FA | POP | +| FB | PUSH2 0x00da | 0xDA | +| FE | PUSH1 0x00 | 0x00 0xDA | +| 100 | SLOAD | Storage[0] 0xDA | +| 101 | DUP2 | 0xDA Storage[0] 0xDA | +| 102 | JUMP | Storage[0] 0xDA | + +What happens after the jump [we already figured out](#the-da-code). So `merkleRoot()` returns Storage[0]. + +## 0x81e580d3 + +The code in offsets 0x138-0x143 is identical to what we saw in 0x103-0x10E in `splitter()` (other than the `JUMPI` destination), so we know this function is also not `payable`. + +| Offset | Opcode | Stack | +| -----: | ------------ | ------------------------------------------------------------ | +| 144 | JUMPDEST | +| 145 | POP | +| 146 | PUSH2 0x00da | 0xDA | +| 149 | PUSH2 0x0153 | 0x0153 0xDA | +| 14C | CALLDATASIZE | CALLDATASIZE 0x0153 0xDA | +| 14D | PUSH1 0x04 | 0x04 CALLDATASIZE 0x0153 0xDA | +| 14F | PUSH2 0x018f | 0x018F 0x04 CALLDATASIZE 0x0153 0xDA | +| 152 | JUMP | 0x04 CALLDATASIZE 0x0153 0xDA | +| 18F | JUMPDEST | 0x04 CALLDATASIZE 0x0153 0xDA | +| 190 | PUSH1 0x00 | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 192 | PUSH1 0x20 | 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 194 | DUP3 | 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 195 | DUP5 | CALLDATASIZE 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 196 | SUB | CALLDATASIZE-4 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 197 | SLT | CALLDATASIZE-4\=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 199 | PUSH2 0x01a0 | 0x01A0 CALLDATASIZE-4>=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19C | JUMPI | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | + +It looks like this function takes at least 32 bytes (one word) of call data. + +| Offset | Opcode | Stack | +| -----: | ------ | -------------------------------------------- | +| 19D | DUP1 | 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19E | DUP2 | 0x00 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19F | REVERT | + +If it doesn't get the call data the transaction is reverted without any return data. + +Let's see what happens if the function _does_ get the call data it needs. + +| Offset | Opcode | Stack | +| -----: | ------------ | ---------------------------------------- | +| 1A0 | JUMPDEST | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 1A1 | POP | 0x04 CALLDATASIZE 0x0153 0xDA | +| 1A2 | CALLDATALOAD | calldataload(4) CALLDATASIZE 0x0153 0xDA | + +`calldataload(4)` is the first word of the call data _after_ the method signature + +| Offset | Opcode | Stack | +| -----: | ------------ | ---------------------------------------------------------------------------- | +| 1A3 | SWAP2 | 0x0153 CALLDATASIZE calldataload(4) 0xDA | +| 1A4 | SWAP1 | CALLDATASIZE 0x0153 calldataload(4) 0xDA | +| 1A5 | POP | 0x0153 calldataload(4) 0xDA | +| 1A6 | JUMP | calldataload(4) 0xDA | +| 153 | JUMPDEST | calldataload(4) 0xDA | +| 154 | PUSH2 0x016e | 0x016E calldataload(4) 0xDA | +| 157 | JUMP | calldataload(4) 0xDA | +| 16E | JUMPDEST | calldataload(4) 0xDA | +| 16F | PUSH1 0x04 | 0x04 calldataload(4) 0xDA | +| 171 | DUP2 | calldataload(4) 0x04 calldataload(4) 0xDA | +| 172 | DUP2 | 0x04 calldataload(4) 0x04 calldataload(4) 0xDA | +| 173 | SLOAD | Storage[4] calldataload(4) 0x04 calldataload(4) 0xDA | +| 174 | DUP2 | calldataload(4) Storage[4] calldataload(4) 0x04 calldataload(4) 0xDA | +| 175 | LT | calldataload(4)\)`, and another is `isClaimed()`, so it looks like an airdrop contract. Instead of going through the rest opcode by opcode, we can [try the decompiler](https://etherscan.io/bytecode-decompiler?a=0x2f81e57ff4f4d83b40a9f719fd892d8e806e0761), which produces usable results for three functions from this contract. Reverse engineering the other ones is left as an exercise to the reader. + +### scaleAmountByPercentage + +This is what the decompiler gives us for this function: + +```python +def unknown8ffb5c97(uint256 _param1, uint256 _param2) payable: + require calldata.size - 4 >=′ 64 + if _param1 and _param2 > -1 / _param1: + revert with 0, 17 + return (_param1 * _param2 / 100 * 10^6) +``` + +The first `require` tests that the call data has, in addition to the four bytes of the function signature, at least 64 bytes, enough for the two parameters. If not then there is obviously something wrong. + +The `if` statement seems to check that `_param1` is not zero, and that `_param1 * _param2` is not negative. It is probably to prevent cases of wrap around. + +Finally, the function returns a scaled value. + +### claim + +The code the decompiler creates is complex, and not all of it is relevant for us. I am going to skip some of it to focus on the lines that I believe provide useful information + +```python +def unknown2e7ba6ef(uint256 _param1, uint256 _param2, uint256 _param3, array _param4) payable: + ... + require _param2 == addr(_param2) + ... + if currentWindow mem[(32 * idx) + 296]: + mem[mem[64] + 32] = mem[(32 * idx) + 296] + ... + s = sha3(mem[_62 + 32 len mem[_62]]) + continue + ... + s = sha3(mem[_66 + 32 len mem[_66]]) + continue + if unknown2eb4a7ab != s: + revert with 0, 'Invalid proof' +``` + +We know that `unknown2eb4a7ab` is actually the function `merkleRoot()`, so this code looks like it is verifying a [merkle proof](https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5). This means that `_param4` is a merkle proof. + +```python + call addr(_param2) with: + value unknown81e580d3[_param1] * _param3 / 100 * 10^6 wei + gas 30000 wei +``` + +This is how a contract transfers its own ETH to another address (contract or externally owned). It calls it with a value that is the amount to be transferred. So it looks like this is an airdrop of ETH. + +```python + if not return_data.size: + if not ext_call.success: + require ext_code.size(stor2) + call stor2.deposit() with: + value unknown81e580d3[_param1] * _param3 / 100 * 10^6 wei +``` + +The bottom two lines tell us that Storage[2] is also a contract that we call. If we [look at the constructor transaction](https://etherscan.io/tx/0xa1ea0549fb349eb7d3aff90e1d6ce7469fdfdcd59a2fd9b8d1f5e420c0d05b58#statechange) we see that this contract is [0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2), a Wrapped Ether contract [whose source code has been uploaded to Etherscan](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code). + +So it looks like the contracts attempts to send ETH to `_param2`. If it can do it, great. If not, it attempts to send [WETH](https://weth.tkn.eth.limo/). If `_param2` is an externally owned account (EOA) then it can always receive ETH, but contracts can refuse to receive ETH. However, WETH is ERC-20 and contracts can't refuse to accept that. + +```python + ... + log 0xdbd5389f: addr(_param2), unknown81e580d3[_param1] * _param3 / 100 * 10^6, bool(ext_call.success) +``` + +At the end of the function we see a log entry being generated. [Look at the generated log entries](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#events) and filter on the topic that starts with `0xdbd5...`. If we [click one of the transactions that generated such an entry](https://etherscan.io/tx/0xe7d3b7e00f645af17dfbbd010478ef4af235896c65b6548def1fe95b3b7d2274) we see that indeed it looks like a claim - the account sent a message to the contract we're reverse engineering, and in return got ETH. + +![A claim transaction](claim-tx.png) + +### 1e7df9d3 + +This function is very similar to [`claim`](#claim) above. It also checks a merkle proof, attempts to transfer ETH to the first, and produces the same type of log entry. + +```python +def unknown1e7df9d3(uint256 _param1, uint256 _param2, array _param3) payable: + ... + idx = 0 + s = 0 + while idx = mem[96]: + revert with 0, 50 + _55 = mem[(32 * idx) + 128] + if s + sha3(mem[(32 * _param3.length) + 160 len mem[(32 * _param3.length) + 128]]) > mem[(32 * idx) + 128]: + ... + s = sha3(mem[_58 + 32 len mem[_58]]) + continue + mem[mem[64] + 32] = s + sha3(mem[(32 * _param3.length) + 160 len mem[(32 * _param3.length) + 128]]) + ... + if unknown2eb4a7ab != s: + revert with 0, 'Invalid proof' + ... + call addr(_param1) with: + value s wei + gas 30000 wei + if not return_data.size: + if not ext_call.success: + require ext_code.size(stor2) + call stor2.deposit() with: + value s wei + gas gas_remaining wei + ... + log 0xdbd5389f: addr(_param1), s, bool(ext_call.success) +``` + +The main difference is that the first parameter, the window to withdraw, isn't there. Instead, there is a loop over all the windows that could be claimed. + +```python + idx = 0 + s = 0 + while idx = unknown81e580d3.length: + revert with 0, 50 + mem[0] = 4 + if unknown81e580d3[idx] and _param2 > -1 / unknown81e580d3[idx]: + revert with 0, 17 + if s > !(unknown81e580d3[idx] * _param2 / 100 * 10^6): + revert with 0, 17 + if idx == -1: + revert with 0, 17 + idx = idx + 1 + s = s + (unknown81e580d3[idx] * _param2 / 100 * 10^6) + continue +``` + +So it looks like a `claim` variant that claims all the windows. + +## Conclusion + +By now you should know how to understand contracts whose source code is not available, using either the opcodes or (when it works) the decompiler. As is evident from the length of this article, reverse engineering a contract is not trivial, but in a system where security is essential it is an important skill to be able to verify contracts work as promised. + +--- + +## Developers > Tutorials > Run Node Raspberry Pi + +**Ethereum on Arm is a custom Linux image that can turn a Raspberry Pi into an Ethereum node.** + +To use Ethereum on Arm to turn a Raspberry Pi into an Ethereum node, the following hardware is recommended: + +- Raspberry 4 (model B 8GB), Odroid M1 or Rock 5B (8GB/16GB RAM) board +- MicroSD Card (16 GB Class 10 minimum) +- 2 TB SSD minimum USB 3.0 disk or an SSD with a USB to SATA case. +- Power supply +- Ethernet cable +- Port forwarding (see clients for further info) +- A case with heatsink and fan +- USB keyboard, Monitor and HDMI cable (micro-HDMI) (Optional) + +## Why run Ethereum on ARM? + +ARM boards are very affordable, flexible, small computers. They are good choices for running Ethereum nodes because they can be bought cheaply, configured so that all their resources focus just on the node, making them efficient, they consume low amounts of power and are physically small so they can fit unobtrusively in any home. It is also very easy to spin up nodes because the Raspberry Pi's MicroSD can simply be flashed with a prebuilt image, with no downloading or building software required. + +## How does it work? + +The Raspberry Pi's memory card is flashed with a prebuilt image. This image contains everything needed to run an Ethereum node. With a flashed card, all the user needs to do is power-on the Raspberry Pi. All the processes required to run the node are automatically started. This works because the memory card contains a Linux-based operating system (OS) on top of which system-level processes are automatically run that turn the unit into an Ethereum node. + +Ethereum cannot be run using the popular Raspberry Pi Linux OS "Raspbian" because Raspbian still uses a 32-bit architecture which leads Ethereum users to run into memory issues and consensus clients do not support 32-bit binaries. To overcome this, the Ethereum on Arm team migrated to a native 64-bit OS called "Armbian". + +**Images take care of all the necessary steps**, from setting up the environment and formatting the SSD disk to installing and running the Ethereum software as well as starting the blockchain synchronization. + +## Note on execution and consensus clients + +The Ethereum on Arm image includes prebuilt execution and consensus clients as services. An Ethereum node requires both clients to be synced and running. You are only required to download and flash the image and then start the services. The image is preloaded with the following execution clients: + +- Geth +- Nethermind +- Besu + +and the following consensus clients: + +- Lighthouse +- Nimbus +- Prysm +- Teku + +You should choose one of each to run - all execution clients are compatible with all consensus clients. If you do not explicitly select a client, the node will fall back to its defaults - Geth and Lighthouse - and run them automatically when the board is powered up. You must open port 30303 on your router so Geth can find and connect to peers. + +## Downloading the Image + +The Raspberry Pi 4 Ethereum image is a "plug and play" image that automatically installs and sets up both the execution and consensus clients, configuring them to talk to each other and connect to the Ethereum network. All the user needs to do is start their processes using a simple command. + +Download the Raspberry Pi image from [Ethereum on Arm](https://ethereumonarm-my.sharepoint.com/:u:/p/dlosada/Ec_VmUvr80VFjf3RYSU-NzkBmj2JOteDECj8Bibde929Gw?download=1) and verify the SHA256 hash: + +```sh +# From directory containing the downloaded image +shasum -a 256 ethonarm_22.04.00.img.zip +# Hash should output: fb497e8f8a7388b62d6e1efbc406b9558bee7ef46ec7e53083630029c117444f +``` + +Note that images for Rock 5B and Odroid M1 boards are available at the Ethereum-on-Arm [downloads page](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/quick-guide/download-and-install.html). + +## Flashing the MicroSD + +The MicroSD card that will be used for the Raspberry Pi should first be inserted into a desktop or laptop so it can be flashed. Then, the following terminal commands will flash the downloaded image onto the SD card: + +```shell +# check the MicroSD card name +sudo fdisk -l + +>> sdxxx +``` + +It is really important to get the name correct because the next command includes `dd` which completely erases the existing content of the card before pushing the image onto it. To continue, navigate to the directory containing the zipped image: + +```shell +# unzip and flash image +unzip ethonarm_22.04.00.img.zip +sudo dd bs=1M if=ethonarm_22.04.00.img of=/dev/ conv=fdatasync status=progress +``` + +The card is now flashed, so it can be inserted into the Raspberry Pi. + +## Start the node + +With the SD card inserted into the Raspberry Pi, connect the ethernet cable and SSD then switch the power on. The OS will boot up and automatically start performing the preconfigured tasks that turn the Raspberry Pi into an Ethereum node, including installing and building the client software. This will probably take 10-15 minutes. + +Once everything is installed and configured, log in to the device via an ssh connection or using the terminal directly if a monitor and keyboard is attached to the board. Use the `ethereum` account to log in, as this has permissions required to start the node. + +```shell +User: ethereum +Password: ethereum +``` + +The default execution client, Geth, will start automatically. You can confirm this by checking the logs using the following terminal command: + +```sh +sudo journalctl -u geth -f +``` + +The consensus client does need to be started explicitly. To do this, first open port 9000 on your router so that Lighthouse can find and connect to peers. Then enable and start the lighthouse service: + +```sh +sudo systemctl enable lighthouse-beacon +sudo systemctl start lighthouse-beacon +``` + +Check the client using the logs: + +```sh +sudo journalctl -u lighthouse-beacon +``` + +Note that the consensus client will sync in a few minutes because it uses checkpoint sync. The execution client will take longer - potentially several hours, and it will not start until the consensus client is already finished syncing (this is because the execution client needs a target to sync to, which the synced consensus client provides). + +With the Geth and Lighthouse services running and synced, your Raspberry Pi is now an Ethereum node! It is most common to interact with the Ethereum network using Geth's Javascript console, which can be attached to the Geth client on port 8545. It is also possible to submit commands formatted as JSON objects using a request tool such as Curl. See more in the [Geth documentation](https://geth.ethereum.org/). + +Geth is preconfigured to report metrics to a Grafana dashboard which can be viewed in the browser. More advanced users might wish to use this feature to monitor the health of their node by navigating to `ipaddress:3000`, passing `user: admin` and `passwd: ethereum`. + +## Validators + +A validator can also be optionally added to the consensus client. The validator software allows your node to participate actively in consensus and provides the network with cryptoeconomic security. You get rewarded for this work in ETH. To run a validator, you must first have 32 ETH, which must be deposited into the deposit contract. The deposit can be made by following the step-by-step guide on the [Launchpad](https://launchpad.ethereum.org/). Do this on a desktop/laptop, but do not generate keys — this can be done directly on the Raspberry Pi. + +Open a terminal on the Raspberry Pi and run the following command to generate the deposit keys: + +``` +sudo apt-get update +sudo apt-get install staking-deposit-cli +cd && deposit new-mnemonic --num_validators 1 +``` + +(Or download the [staking-deposit-cli](https://github.com/ethereum/staking-deposit-cli) to run on an airgapped machine, and run the `deposit new-mnemnonic` command) + +Keep the mnemonic phrase safe! The command above generated two files in the node's keystore: the validator keys and a deposit data file. The deposit data needs to be uploaded into the launchpad, so it must be copied from the Raspberry Pi to the desktop/laptop. This can be done using an ssh connection or any other copy/paste method. + +Once the deposit data file is available on the computer running the launchpad, it can be dragged and dropped onto the `+` on the launchpad screen. Follow the instructions on the screen to send a transaction to the deposit contract. + +Back on the Raspberry Pi, a validator can be started. This requires importing the validator keys, setting the address to collect rewards, and then starting the preconfigured validator process. The example below is for Lighthouse—instructions for other consensus clients are available on the [Ethereum on Arm docs](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/): + +```shell +# import the validator keys +lighthouse account validator import --directory=/home/ethereum/validator_keys + +# set the reward address +sudo sed -i 's/' /etc/ethereum/lighthouse-validator.conf + +# start the validator +sudo systemctl start lighthouse-validator +``` + +Congratulations, you now have a full Ethereum node and validator running on a Raspberry Pi! + +## More details + +This page gave an overview of how to set up a Geth-Lighthouse node and validator using Raspberry Pi. More detailed instructions are available on the [Ethereum-on-Arm website](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/index.html). + +## Feedback appreciated + +We know the Raspberry Pi has a massive user base that could have a very positive impact on the health of the Ethereum network. +Please dig into the details in this tutorial, try running on testnets, check out the Ethereum on Arm GitHub, give feedback, raise issues and pull requests and help advance the technology and documentation! + +## References + +1. https://ubuntu.com/download/raspberry-pi +2. https://wikipedia.org/wiki/Port_forwarding +3. https://prometheus.io +4. https://grafana.com +5. https://forum.armbian.com/topic/5565-zram-vs-swap/ +6. https://geth.ethereum.org +7. https://nethermind.io +8. https://www.hyperledger.org/projects/besu +9. https://github.com/prysmaticlabs/prysm +10. https://lighthouse.sigmaprime.io +11. https://ethersphere.github.io/swarm-home +12. https://raiden.network +13. https://ipfs.io +14. https://status.im +15. https://vipnode.org + +--- + +## Developers > Tutorials > Scam Token Tricks + +In this tutorial we dissect [a scam token](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code) to see some of the tricks that scammers play and how they implement them. By the end of the tutorial you will have a more comprehensive view of ERC-20 token contracts, their capabilities, and why skepticism is necessary. Then we look at the events emitted by that scam token and see how we can identify that it is not legitimate automatically. + +## Scam tokens - what are they, why do people do them, and how to avoid them + +One of the most common uses for Ethereum is for a group to create a tradable token, in a sense their own currency. However, anywhere there are legitimate use cases that bring value, there are also criminals who try to steal that value for themselves. + +You can read more about this subject [elsewhere on ethereum.org](/guides/how-to-id-scam-tokens/) from a user perspective. This tutorial focuses on dissecting a scam token to see how it's done and how it can be detected. + +### How do I know wARB is a scam? + +The token we dissect is [wARB](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code), which pretends to be equivalent to the legitimate [ARB token](https://etherscan.io/token/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1). + +The easiest way to know which is the legitimate token is looking at the originating organization, [Arbitrum](https://arbitrum.foundation/). The legitimate addresses are specified [in their documentation](https://docs.arbitrum.foundation/deployment-addresses#token). + +### Why is the source code available? + +Normally we'd expect people who try to scam others to be secretive, and indeed many scam tokens do not have their code available (for example, [this one](https://optimistic.etherscan.io/token/0x15992f382d8c46d667b10dc8456dc36651af1452#code) and [this one](https://optimistic.etherscan.io/token/0x026b623eb4aada7de37ef25256854f9235207178#code)). + +However, legitimate tokens usually publish their source code, so to appear legitimate scam tokens' authors' sometimes do the same. [wARB](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code) is one of those tokens with source code available, which makes it easier to understand it. + +While contract deployers can choose whether or not to publish the source code, they _can't_ publish the wrong source code. The block explorer compiles the provided source code independently, and if doesn't get the exact same bytecode, it rejects that source code. [You can read more about this on the Etherscan site](https://etherscan.io/verifyContract). + +## Comparison to legitimate ERC-20 tokens + +We are going to compare this token to legitimate ERC-20 tokens. If you are not familiar with how legitimate ERC-20 tokens are typically written, [see this tutorial](/developers/tutorials/erc20-annotated-code/). + +### Constants for privileged addresses + +Contracts sometimes need privileged addresses. Contracts that are designed for long term use allow some privileged address to change those addresses, for example to enable the use of a new multisig contract. There are several ways to do this. + +The [`HOP` token contract](https://etherscan.io/address/0xc5102fe9359fd9a28f877a67e36b0f050d81a3cc#code) uses the [`Ownable`](https://docs.openzeppelin.com/contracts/2.x/access-control#ownership-and-ownable) pattern. The privileged address is kept in storage, in a field called `_owner` (see the third file, `Ownable.sol`). + +```solidity +abstract contract Ownable is Context +``` + +The [`ARB` token contract](https://etherscan.io/address/0xad0c361ef902a7d9851ca7dcc85535da2d3c6fc7#code) does not have a privileged address directly. However, it does not need one. It sits behind a [`proxy`](https://docs.openzeppelin.com/contracts/4.x/api/proxy) at [address `0xb50721bcf8d664c30412cfbc6cf7a15145234ad1`](https://etherscan.io/address/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1#code). That contract has a privileged address (see the fourth file, `ERC1967Upgrade.sol`) that be used for upgrades. + +```solidity + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private +``` + +In contrast, the `wARB` contract has a hard coded `contract_owner`. + +```solidity +contract WrappedArbitrum is Context, IERC20 +``` + +[This contract owner](https://etherscan.io/address/0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33) is not a contract that could be controlled by different accounts at different times, but an [externally owned account](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs). This means that it is probably designed for short term use by an individual, rather than as a long term solution to control an ERC-20 that will remain valuable. + +And indeed, if we look in Etherscan we see that the scammer only used this contract for only 12 hours ([first transaction](https://etherscan.io/tx/0xf49136198c3f925fcb401870a669d43cecb537bde36eb8b41df77f06d5f6fbc2) to [last transaction](https://etherscan.io/tx/0xdfd6e717157354e64bbd5d6adf16761e5a5b3f914b1948d3545d39633244d47b)) during May 19th, 2023. + +### The fake `_transfer` function + +It is standard to have actual transfers happen using [an internal `_transfer` function](/developers/tutorials/erc20-annotated-code/#the-_transfer-function-_transfer). + +In `wARB` this function looks almost legitimate: + +```solidity + function _transfer(address sender, address recipient, uint256 amount) internal virtual + emit Transfer(sender, recipient, amount); + } +``` + +The suspicious part is: + +```solidity + if (sender == contract_owner) + emit Transfer(sender, recipient, amount); +``` + +If the contract owner sends tokens, why does the `Transfer` event show they come from `deployer`? + +However, there is a more important issue. Who calls this `_transfer` function? It can't be called from the outside, it is marked `internal`. And the code we have doesn't include any calls to `_transfer`. Clearly, it is here as a decoy. + +```solidity + function transfer(address recipient, uint256 amount) public virtual override returns (bool) + + function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) +``` + +When we look at the functions that are called to transfer tokens, `transfer` and `transferFrom`, we see that they call a completely different function, `_f_`. + +### The real `_f_` function + +```solidity + function _f_(address sender, address recipient, uint256 amount) internal _mod_(sender,recipient,amount) virtual + emit Transfer(sender, recipient, amount); + } +``` + +There are two potential red flags in this function. + +- The use of the [function modifier](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm) `_mod_`. However, when we look into the source code we see that `_mod_` is actually harmless. + + ```solidity + modifier _mod_(address sender, address recipient, uint256 amount) + ``` + +- The same issue we saw in `_transfer`, which is when `contract_owner` sends tokens they appear to come from `deployer`. + +### The fake events function `dropNewTokens` + +Now we come to something that looks like an actual scam. I edited the function a bit for readability, but it's functionally equivalent. + +```solidity +function dropNewTokens(address uPool, + address[] memory eReceiver, + uint256[] memory eAmounts) public auth() +``` + +This function has the `auth()` modifier, which means it can only be called by the contract owner. + +```solidity +modifier auth() +``` + +This restriction makes perfect sense, because we wouldn't want random accounts to distribute tokens. However, the rest of the function is suspicious. + +```solidity + +``` + +There are two more suspicious facts, directly related to minting: + +- There is an `account` parameter, which is presumably the account that should receive the minted amount. But the balance that increases is actually `contract_owner`'s. + +- While the balance increased belongs to `contract_owner`, the event emitted shows a transfer to `account`. + +### Why both `auth` and `approver`? Why the `mod` that does nothing? + +This contract contains three modifiers: `_mod_`, `auth`, and `approver`. + +```solidity + modifier _mod_(address sender, address recipient, uint256 amount) +``` + +`_mod_` takes three parameters and doesn't do anything with them. Why have it? + +```solidity + modifier auth() + + modifier approver() +``` + +`auth` and `approver` make more sense, because they check that the contract was called by `contract_owner`. We'd expect certain privileged actions, such as minting, to be limited to that account. However, what is the point of having two separate functions that do _precisely the same thing_? + +## What can we detect automatically? + +We can see that `wARB` is a scam token by looking at Etherscan. However, that is a centralized solution. In theory, Etherscan could be subverted or hacked. It is better to be able to figure out independently if a token is legitimate or not. + +There are some tricks we can use to identify that an ERC-20 token is suspicious (either a scam or very badly written), by looking at the events they emit. + +## Suspicious `Approval` events + +[`Approval` events](https://eips.ethereum.org/EIPS/eip-20#approval) should only happen with a direct request (in contrast to [`Transfer` events](https://eips.ethereum.org/EIPS/eip-20#transfer-1) which can happen as a result of an allowance). [See the Solidity docs](https://docs.soliditylang.org/en/v0.8.20/security-considerations.html#tx-origin) for a detailed explanation of this issue and why the requests need to be direct, rather than mediated by a contract. + +This means that `Approval` events that approve spending from an [externally owned account](/developers/docs/accounts/#types-of-account) have to come from transactions that originate in that account, and whose destination is the ERC-20 contract. Any other kind of approval from an externally owned account is suspicious. + +Here is [a program that identifies this kind of event](https://github.com/qbzzt/20230915-scam-token-detection), using [viem](https://viem.sh/) and [TypeScript](https://www.typescriptlang.org/docs/), a JavaScript variant with type safety. To run it: + +1. Copy `.env.example` to `.env`. +2. Edit `.env` to provide the URL to an Ethereum mainnet node. +3. Run `pnpm install` to install the necessary packages. +4. Run `pnpm susApproval` to look for suspicious approvals. + +Here is a line by line explanation: + +```typescript +import from "viem" +``` + +Import type definitions, functions, and the chain definition from `viem`. + +```typescript +config() +``` + +Read `.env` to get the URL. + +```typescript +const client = createPublicClient() +``` + +Create a Viem client. We only need to read from the blockchain, so this client does not need a private key. + +```typescript +const testedAddress = "0xb047c8032b99841713b8e3872f06cf32beb27b82" +const fromBlock = 16859812n +const toBlock = 16873372n +``` + +The address of the suspicious ERC-20 contract, and the blocks within which we'll look for events. Node providers typically limit our ability to read events because the bandwidth can get expensive. Luckily `wARB` wasn't in use for an eighteen hour period, so we can look for all the events (there were only 13 in total). + +```typescript +const approvalEvents = await client.getLogs() +``` + +This is the way to ask Viem for event information. When we provide it with the exact event signature, including field names, it parses the event for us. + +```typescript +const isContract = async (addr: Address): boolean => + await client.getBytecode() +``` + +Our algorithm is only applicable to externally owned accounts. If there is any bytecode returned by `client.getBytecode` it means that this is a contract and we should just skip it. + +If you haven't used TypeScript before, the function definition might look a bit weird. We don't just tell it the first (and only) parameter is called `addr`, but also that it is of type `Address`. Similarly, the `: boolean` part tells TypeScript that the return value of the function is a boolean. + +```typescript +const getEventTxn = async (ev: Event): TransactionReceipt => + await client.getTransactionReceipt() +``` + +This function gets the transaction receipt from an event. We need the receipt to ensure we know what was the transaction destination. + +```typescript +const suspiciousApprovalEvent = async (ev : Event) : (Event | null) => +``` + +If neither condition is true then the `Approval` event is not suspicious. + +```typescript +const testPromises = approvalEvents.map((ev) => suspiciousApprovalEvent(ev)) +const testResults = (await Promise.all(testPromises)).filter((x) => x != null) + +console.log(testResults) +``` + +[An `async` function](https://www.w3schools.com/js/js_async.asp) returns a `Promise` object. With the common syntax, `await x()`, we wait for that `Promise` to be fulfilled before we continue processing. This is simple to program and follow, but it is also inefficient. While we are waiting for the `Promise` for a specific event to be fulfilled we can already get working on the next event. + +Here we use [`map`](https://www.w3schools.com/jsref/jsref_map.asp) to create an array of `Promise` objects. Then we use [`Promise.all`](https://www.javascripttutorial.net/es6/javascript-promise-all/) to wait for all of those promises to the resolved. We then [`filter`](https://www.w3schools.com/jsref/jsref_filter.asp) those results to remove the non-suspicious events. + +### Suspicious `Transfer` events + +Another possible way to identify scam tokens is to see if they have any suspicious transfers. For example, transfers from accounts that don't have that many tokens. You can see [how to implement this test](https://github.com/qbzzt/20230915-scam-token-detection/blob/main/susTransfer.ts), but `wARB` doesn't have this issue. + +## Conclusion + +Automated detection of ERC-20 scams suffers from [false negatives](https://en.wikipedia.org/wiki/False_positives_and_false_negatives#False_negative_error), because a scam can use a perfectly normal ERC-20 token contract that just doesn't represent anything real. So you should always attempt to _get the token address from a trusted source_. + +Automated detection can help in certain cases, such as DeFi pieces, where there are many tokens and they need to be handled automatically. But as always [caveat emptor](https://www.investopedia.com/terms/c/caveatemptor.asp), do your own research, and encourage your users to do likewise. + +--- + +## Developers > Tutorials > Secret State + +_There are no secrets on the blockchain_. Everything that is posted on the blockchain is open to everybody to read. This is necessary, because the blockchain is based on anybody being able to verify it. However, games often rely on secret state. For example, the game of [minesweeper]() makes absolutely no sense if you can just go on a blockchain explorer and see the map. + +The simplest solution is to use a [server component](/developers/tutorials/server-components/) to hold the secret state. However, the reason we use blockchain is to prevent cheating by the game developer. We need to ensure the server component's honesty. The server can provide a hash of the state, and use [zero-knowledge proofs](/zero-knowledge-proofs/#why-zero-knowledge-proofs-are-important) to prove that the state used to calculate the result of a move is the correct one. + +After reading this article you will know how to create this kind of secret state holding server, a client for showing the state, and an onchain component for communication between the two. The main tools we use will be: + +| Tool | Purpose | Verified on version | +| --------------------------------------------- | ------------------------------------------------------- | ------------------: | +| [Zokrates](https://zokrates.github.io/) | Zero-knowledge proofs and their verification | 1.1.9 | +| [Typescript](https://www.typescriptlang.org/) | Programming language for both the server and the client | 5.4.2 | +| [Node](https://nodejs.org/en) | Running the server | 20.18.2 | +| [Viem](https://viem.sh/) | Communication with the Blockchain | 2.9.20 | +| [MUD](https://mud.dev/) | Onchain data management | 2.0.12 | +| [React](https://react.dev/) | Client user interface | 18.2.0 | +| [Vite](https://vitejs.dev/) | Serving the client code | 4.2.1 | + +## Minesweeper example + +[Minesweeper]() is a game that includes a secret map with a minefield. The player chooses to dig in a specific location. If that location has a mine, it's game over. Otherwise, the player gets the number of mines in the eight squares surrounding that location. + +This application is written using [MUD](https://mud.dev/), a framework that lets us store data onchain using a [key-value database](https://aws.amazon.com/nosql/key-value/) and synchronize that data automatically with offchain components. In addition to synchronization, MUD makes it easy to provide access control, and for other users to [extend](https://mud.dev/guides/extending-a-world) our application permissionlessly. + +### Running the minesweeper example + +To run the minesweeper example: + +1. Make sure you [have the prerequisites installed](https://mud.dev/quickstart#prerequisites): [Node](https://mud.dev/quickstart#prerequisites), [Foundry](https://book.getfoundry.sh/getting-started/installation), [`git`](https://git-scm.com/downloads), [`pnpm`](https://git-scm.com/downloads), and [`mprocs`](https://github.com/pvolok/mprocs). + +2. Clone the repository. + + ```sh copy + git clone https://github.com/qbzzt/20240901-secret-state.git + ``` + +3. Install the packages. + + ```sh copy + cd 20240901-secret-state/ + pnpm install + npm install -g mprocs + ``` + + If Foundry was installed as part of `pnpm install`, you need to restart the command-line shell. + +4. Compile the contracts + + ```sh copy + cd packages/contracts + forge build + cd ../.. + ``` + + +5. Start the program (including an [anvil](https://book.getfoundry.sh/anvil/) blockchain) and wait. + + ```sh copy + mprocs + ``` + + Note that the startup takes a long time. To see the progress, first use the down arrow to scroll to the _contracts_ tab to see the MUD contracts being deployed. When you get the message _Waiting for file changes…_, the contracts are deployed and further progress will happen in the _server_ tab. There, you wait until you get the message _Verifier address: 0x...._. + + If this step is successful, you will see the `mprocs` screen, with the different processes on the left and the console output for the currently selected process on the right. + + ![The mprocs screen](./mprocs.png) + + If there is a problem with `mprocs`, you can run the four processes manually, each in its own command line window: + + - **Anvil** + + ```sh + cd packages/contracts + anvil --base-fee 0 --block-time 2 + ``` + + - **Contracts** + + ```sh + cd packages/contracts + pnpm mud dev-contracts --rpc http://127.0.0.1:8545 + ``` + + - **Server** + + ```sh + cd packages/server + pnpm start + ``` + + - **Client** + + ```sh + cd packages/client + pnpm run dev + ``` + +6. Now you can browse to [the client](http://localhost:3000), click **New Game**, and start playing. + +### Tables + +We need [several tables](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/mud.config.ts) onchain. + +- `Configuration`: This table is a singleton, it has no key and single record. It is used to hold game configuration information: + - `height`: The height of a minefield + - `width`: The width of a minefield + - `numberOfBombs`: The number of bombs in each minefield +- `VerifierAddress`: This table is also a singleton. It is used to hold one part of the configuration, the address of the verifier contract (`verifier`). We could have put this information in the `Configuration` table, but it is set by a different component, the server, so it's easier to put it in a separate table. + +- `PlayerGame`: The key is the player's address. The data is: + + - `gameId`: 32-byte value that is the hash of the map the player is playing on (the game identifier). + - `win`: a boolean that is whether the player won the game. + - `lose`: a boolean that is whether the player lost the game. + - `digNumber`: the number of successful digs in the game. + +- `GamePlayer`: This table holds the reverse mapping, from `gameId` to player address. + +- `Map`: The key is a tuple of three values: + + - `gameId`: 32-byte value that is the hash of the map the player is playing on (the game identifier). + - `x` coordinate + - `y` coordinate + + The value is a single number. It's 255 if a bomb was detected. Otherwise, it is the number of bombs around that location plus one. We cannot just use the number of bombs, because by default all storage in the EVM and all row values in MUD are zero. We need to distinguish between "the player haven't dug here yet" and "the player dug here, and found there are zero bombs around". + +In addition, communication between the client and server happens through the onchain component. This is also implemented using tables. + +- `PendingGame`: Unserviced requests to start a new game. +- `PendingDig`: Unserviced requests to dig in a specific place in a specific game. This is an [offchain table](https://mud.dev/store/tables#types-of-tables), meaning that it does not get written to EVM storage, it's only readable offchain using events. + +### Execution and data flows + +These flows coordinate execution between the client, the onchain component, and the server. + +#### Initialization + +When you run `mprocs`, these steps happen: + +1. [`mprocs`](https://github.com/pvolok/mprocs) runs four components: + + - [Anvil](https://book.getfoundry.sh/anvil/), which runs a local blockchain + - [Contracts](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/contracts), which compiles (if needed) and deploys the contracts for MUD + - [Client](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/client), which runs [Vite](https://vitejs.dev/) to serve the UI and client code to web browsers. + - [Server](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/server), which performs the server actions + +2. The `contracts` package deploys the MUD contracts and then runs [the `PostDeploy.s.sol` script](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/script/PostDeploy.s.sol). This script sets the configuration. The code from github specifies [a 10x5 minefield with eight mines in it](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/script/PostDeploy.s.sol#L23). + +3. [The server](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts) starts by [setting up MUD](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L6). Among other things, this activates data synchronization, so that a copy of the relevant tables exists in the server's memory. + +4. The server subscribes a function to be executed [when the `Configuration` table changes](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L23). [This function](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L24-L168) is called after `PostDeploy.s.sol` executes and modifies the table. + +5. When the server initialization function has the configuration, [it calls `zkFunctions`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L34-L35) to initialize [the zero-knowledge part of the server](#using-zokrates-from-typescript). This cannot happen until we get the configuration because the zero-knowledge functions have to have the width and height of the minefield as constants. + +6. After the zero-knowledge part of the server is initialized, the next step is to [deploy the zero-knowledge verification contract to the blockchain](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L42-L53) and set the verifiee address in MUD. + +7. Finally, we subscribe to updates so we'll see when a player requests either [to start a new game](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L55-L71) or to [dig in an existing game](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L73-L108). + +#### New game + +This is what happens when the player requests a new game. + +1. If there is no game in progress for this player, or there is one but with a gameId of zero, the client displays a [new game button](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175). When the user presses this button, [React runs the `newGame` function](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L96). + +2. [`newGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/mud/createSystemCalls.ts#L43-L46) is a `System` call. In MUD all calls are routed through the `World` contract, and in most cases you call `__`. In this case, the call is to `app__newGame`, which MUD then routes to [`newGame` in `GameSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L16-L22). + +3. The onchain function checks that the player does not have a game in progress, and if there isn't one [adds the request to the `PendingGame` table](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L21). + +4. The server detects the change in `PendingGame` and [runs the subscribed function](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L55-L71). This function calls [`newGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L110-L114), which in turn calls [`createGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L116-L144). + +5. The first thing `createGame` does is [create a random map with the appropriate number of mines](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L120-L135). Then, it calls [`makeMapBorders`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L147-L166) to create a map with blank borders, which is necessary for Zokrates. Finally, `createGame` calls [`calculateMapHash`](#calculateMapHash), to get the hash of the map, which is used as the game ID. + +6. The `newGame` function adds the new game to `gamesInProgress`. + +7. The last thing the server does is call [`app__newGameResponse`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L38-L43), which is onchain. This function is in a different `System`, [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol), to enable access control. Access control is defined in the [MUD configuration file](https://mud.dev/config), [`mud.config.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/mud.config.ts#L67-L72). + + The access list only allows a single address to call the `System`. This restricts access to the server functions to a single address, so nobody can impersonate the server. + +8. The onchain component updates the relevant tables: + + - Create the game in `PlayerGame`. + - Set the reverse mapping in `GamePlayer`. + - Remove the request from `PendingGame`. + +9. The server identifies the change in `PendingGame`, but does not do anything because [`wantsGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L58-L60) is false. + +10. On the client [`gameRecord`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L143-L148) is set to the `PlayerGame` entry for the player's address. When `PlayerGame` changes, `gameRecord` changes too. + +11. If there is a value in `gameRecord`, and the game hasn't been won or lost, the client [displays the map](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175-L190). + +#### Dig + +1. The player [clicks the map cell's button](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L188), which calls [the `dig` function](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/mud/createSystemCalls.ts#L33-L36). This function calls [`dig` onchain](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L24-L32). + +2. The onchain component [performs a number of sanity checks](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L25-L30), and if successful adds the dig request to [`PendingDig`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L31). + +3. The server [detects the change in `PendingDig`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L73). [If it is valid](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L75-L84), it [calls the zero-knowledge code](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L86-L95) (explained below) to generate both the result and a proof that it is valid. + +4. [The server](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L97-L107) calls [`digResponse`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L45-L64) onchain. + +5. `digResponse` does two things. First, it checks [the zero knowledge proof](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L47-L61). Then, if the proof checks out, it calls [`processDigResult`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L67-L86) to actually process the result. + +6. `processDigResult` checks if the game has been [lost](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L76-L78) or [won](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L83-L86), and [updates `Map`, the onchain map](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L80). + +7. The client picks up the updates automatically and [updates the map displayed to the player](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175-L190), and if applicable tells the player if it's a win or a lose. + +## Using Zokrates + +In the flows explained above we skipped over the zero-knowledge parts, treating them as a black box. Now let's crank it open and see how that code is written. + +### Hashing the map + +We can use [this JavaScript code](https://github.com/ZK-Plus/ICBC24_Tutorial_Compute-Offchain-Verify-onchain/tree/solutions/exercise) to implement [Poseidon](https://www.poseidon-hash.info), the Zokrates hash function we use. However, while this would be faster, it would also be more complicated than just using the Zokrates hash function to do it. This is a tutorial, and so the code is optimized for simplicity, not for performance. Therefore, we need two different Zokrates programs, one to just calculate the hash of a map (`hash`) and one to actually create a zero-knowledge proof of the result of the dig in a location on the map (`dig`). + +### The hash function + +This is the function that calculates the hash of a map. We'll go over this code line by line. + +``` +import "hashes/poseidon/poseidon.zok" as poseidon; +import "utils/pack/bool/pack128.zok" as pack128; +``` + +These two lines import two functions from the [Zokrates standard library](https://zokrates.github.io/toolbox/stdlib.html). [The first function](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/hashes/poseidon/poseidon.zok) is a [Poseidon hash](https://www.poseidon-hash.info/). It takes an array of [`field` elements](https://zokrates.github.io/language/types.html#field) and returns a `field`. + +The field element in Zokrates is typically less than 256 bits long, but not by much. To simplify the code, we restrict the map to be up to 512 bits, and hash an array of four fields, and in each field we use only 128 bits. [The `pack128` function](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok) changes an array of 128 bits into a `field` for this purpose. + +``` + def hashMap(bool[$][$] map) -> field ` and `$` because the Zokrates programs are stored in this application as [template strings](https://www.w3schools.com/js/js_string_templates.asp). Code between `$` is evaluated by JavaScript, and this way the program can be used for different map sizes. The map parameter has a one location wide border all around it without any bombs, which is the reason we need to add two to the width and height. + +The return value is a `field` that contains the hash. + +``` + bool[512] mut map1d = [false; 512]; +``` + +The map is two-dimensional. However, the `pack128` function does not work with two-dimensional arrays. So we first flatten the map into a 512-byte array, using `map1d`. By default Zokrates variables are constants, but we need to assign values to this array in a loop, so we define it as [`mut`](https://zokrates.github.io/language/variables.html#mutability). + +We need to initialize the array because Zokrates doesn't have `undefined`. The `[false; 512]` expression means [an array of 512 `false` values](https://zokrates.github.io/language/types.html#declaration-and-initialization). + +``` + u32 mut counter = 0; +``` + +We also need a counter to distinguish between the bits we already filled in `map1d` and those we haven't. + +``` + for u32 x in 0..$ ` is a compile time constant because `width` is set by the TypeScript code before it calls the compiler. + +``` + for u32 y in 0..$ + } +``` + +For every location in the map, put that value in the `map1d` array and increment the counter. + +``` + field[4] hashMe = [ + pack128(map1d[0..128]), + pack128(map1d[128..256]), + pack128(map1d[256..384]), + pack128(map1d[384..512]) + ]; +``` + +The `pack128` to create an array of four `field` values from `map1d`. In Zokrates `array[a..b]` means the slice of the array that starts at `a` and ends at `b-1`. + +``` + return poseidon(hashMe); +} +``` + +Use `poseidon` to convert this array to a hash. + +### The hash program + +The server needs to call `hashMap` directly to create game identifiers. However, Zokrates can only call the `main` function on a program to start, so we create a program with a `main` that calls the hash function. + +``` +$ + +def main(bool[$][$] map) -> field +``` + +### The dig program + +This is the heart of the zero-knowledge part of the application, where we produce the proofs that are used to verify dig results. + +``` +$ + +// The number of mines in location (x,y) +def map2mineCount(bool[$][$] map, u32 x, u32 y) -> u8 else ; +} +``` + +#### Why map border + +Zero-knowledge proofs use [arithmetic circuits](https://medium.com/web3studio/simple-explanations-of-arithmetic-circuits-and-zero-knowledge-proofs-806e59a79785), which don't have an easy equivalent to an `if` statement. Instead, they use the equivalent of the [conditional operator](https://en.wikipedia.org/wiki/Ternary_conditional_operator). If `a` can be either zero or one, you can calculate `if a else ` as `ab+(1-a)c`. + +Because of this, a Zokrates `if` statement always evaluates both branches. For example, if you have this code: + +``` +bool[5] arr = [false; 5]; +u32 index=10; +return if index>4 else +``` + +It will error out, because it needs to calculate `arr[10]`, even though that value will be later multiplied by zero. + +This is the reason we need a one location wide border all around the map. We need to calculate the total number of mines around a location, and that means we need to see the location one row above and below, to the left and to the right, of the location where we're digging. Which means those location have to exist in the map array that Zokrates is provided. + +``` +def main(private bool[$][$] map, u32 x, u32 y) -> (field, u8) else + ); +} +``` + +If the player hasn't hit a mine, add the mine counts for the area around the location and return that. + +### Using Zokrates from TypeScript + +Zokrates has a command line interface, but in this program we use it in the [TypeScript code](https://zokrates.github.io/toolbox/zokrates_js.html). + +The library that contains the Zokrates definitions is called [`zero-knowledge.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts). + +```typescript +``` + +Import the [Zokrates JavaScript bindings](https://zokrates.github.io/toolbox/zokrates_js.html). We only need the [`initialize`](https://zokrates.github.io/toolbox/zokrates_js.html#initialize) function because it returns a promise that resolves to all the Zokrates definitions. + +```typescript +export const zkFunctions = async (width: number, height: number) : Promise => + ` + +const hashProgram = ` + $ + . + . + . + ` + +const digProgram = ` + $ + . + . + . + ` +``` + +Next we have the hash function and two Zokrates programs we saw above. + +```typescript +const digCompiled = zokrates.compile(digProgram) +const hashCompiled = zokrates.compile(hashProgram) +``` + +Here we compile those programs. + +```typescript +// Create the keys for zero knowledge verification. +// On a production system you'd want to use a setup ceremony. +// (https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony). +const keySetupResults = zokrates.setup(digCompiled.program, "") +const verifierKey = keySetupResults.vk +const proverKey = keySetupResults.pk +``` + +On a production system we might use a more complicated [setup ceremony](https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony), but this is good enough for a demonstration. It's not a problem that the users can know the prover key - they still cannot use it to prove things unless they are true. Because we specify the entropy (the second parameter, `""`), the results are always going to be the same. + +**Note:** Compilation of Zokrates programs and key creation are slow processes. There is no need to repeat them every time, just when map size changes. On a production system you'd do them once, and then store the output. The only reason I am not doing it here is for the sake of simplicity. + +#### `calculateMapHash` + +```typescript +const calculateMapHash = function (hashMe: boolean[][]): string +``` + +The [`computeWitness`](https://zokrates.github.io/toolbox/zokrates_js.html#computewitnessartifacts-args-options) function actually runs the Zokrates program. It returns a structure with two fields: `output`, which is the output of the program as a JSON string, and `witness`, which is the information needed to create the a zero knowledge proof of the result. Here we just need the output. + +The output is a string of the form `"31337"`, a decimal number enclosed in quotation marks. But the output we need for `viem` is a hexadecimal number of the form `0x60A7`. So we use `.slice(1,-1)` to remove the quotation marks and then `BigInt` to run the remaining string, which is a decimal number, to a [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). `.toString(16)` converts this `BigInt` into a hexadecimal string, and `"0x"+` adds the marker for hexadecimal numbers. + +```typescript +// Dig and return a zero knowledge proof of the result +// (server-side code) +``` + +The zero knowledge proof includes the public inputs (`x` and `y`) and results (hash of the map and number of bombs). + +```typescript + const zkDig = function(map: boolean[][], x: number, y: number) : any `, `$`]) +``` + +Execute the dig program. + +```typescript + const proof = zokrates.generateProof( + digCompiled.program, + runResults.witness, + proverKey) + + return proof + } +``` + +Use [`generateProof`](https://zokrates.github.io/toolbox/zokrates_js.html#generateproofprogram-witness-provingkey-entropy) and return the proof. + +```typescript +const solidityVerifier = ` + // Map size: $ x $ + \n$ + ` +``` + +A Solidity verifier, a smart contract we can deploy to the blockchain and use to verify proofs generated by `digCompiled.program`. + +```typescript + return +} +``` + +Finally, return everything that other code might need. + +## Security tests + +Security tests are important because a functionality bug will eventually reveal itself. But if the application is insecure, that is likely to remain hidden for a long time before it is revealed by somebody cheating and getting away with resources that belong to others. + +### Permissions + +There is one privileged entity in this game, the server. It is the only user allowed to call the functions in [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol). We can use [`cast`](https://book.getfoundry.sh/cast/) to verify calls to permissioned functions are only allowed as the server account. + +[The server's private key is in `setupNetwork.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/mud/setupNetwork.ts#L52). + +1. On the computer that runs `anvil` (the blockchain), set these environment variables. + + ```sh copy + WORLD_ADDRESS=0x8d8b6b8414e1e3dcfd4168561b9be6bd3bf6ec4b + UNAUTHORIZED_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a + AUTHORIZED_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + ``` + +2. Use `cast` to attempt to set the verifier address as an unauthorized address. + + ```sh copy + cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $UNAUTHORIZED_KEY + ``` + + Not only does `cast` report a failure, but you can open **MUD Dev Tools** in the game on the browser, click **Tables**, and select **app\_\_VerifierAddress**. See that the address is not zero. + +3. Set the verifier address as the server's address. + + ```sh copy + cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $AUTHORIZED_KEY + ``` + + The address in **app\_\_VerifiedAddress** should now be zero. + +All MUD functions in the same `System` go through the same access control, so I consider this test sufficient. If you don't, you can check the other functions in [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol). + +### Zero-knowledge abuses + +The math to verify Zokrates is beyond the scope of this tutorial (and my abilities). However, we can run various checks on the zero-knowledge code to verify that if it is not done correctly it fails. All of these tests are going to require us to change [`zero-knowledge.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts) and restart the entire application. It is not sufficient to restart the server process, because it puts the application in an impossible state (the player has a game in progress, but the game is no longer available to the server). + +#### Wrong answer + +The simplest possibility is to provide the wrong answer in the zero-knowledge proof. To do that, we go inside `zkDig` and [modify line 91](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L91): + +```ts +proof.inputs[3] = "0x" + "1".padStart(64, "0") +``` + +This means we'll always claim there is one bomb, regardless of the correct answer. Try to play with this version, and you'll see in the **server** tab of the `pnpm dev` screen this error: + +``` + cause: , +``` + +So this kind of cheat fails. + +#### Wrong proof + +What happens if we provide the correct information, but just have the wrong proof data? Now, replace line 91 with: + +```ts +proof.proof = +``` + +It still fails, but now it fails without a reason because it happens during the verifier call. + +### How can a user verify the zero trust code? + +Smart contracts are relatively easy to verify. Typically, the developer publishes the source code to a block explorer, and the block explorer verifies that the source code does compile to the code in the [contract deployment transaction](https://ethereum.org/en/developers/docs/smart-contracts/deploying/). In the case of MUD `System`s this is [slightly more complicated](https://mud.dev/cli/verify), but not by much. + +This is harder with zero-knowledge. The verifier includes some constants and runs some calculations on them. This doesn't tell you what is being proved. + +```solidity + function verifyingKey() pure internal returns (VerifyingKey memory vk) + } + + field[4] hashMe = [ + pack128(map1d[0..128]), + pack128(map1d[128..256]), + pack128(map1d[256..384]), + pack128(map1d[384..512]) + ]; + + return poseidon(hashMe); + } + + + // The number of mines in location (x,y) + def map2mineCount(bool[12][7] map, u32 x, u32 y) -> u8 else ; + } + + def main(private bool[12][7] map, u32 x, u32 y) -> (field, u8) else + ); + } + ``` + +3. Compile the Zokrates code and create the verification key. The verification key has to be created with the same entropy used in the original server, [in this case an empty string](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L67). + + ```sh copy + zokrates compile --input dig.zok + zokrates setup -e "" + ``` + +4. Create the Solidity verifier on your own, and verify it is functionally identical to the one on the blockchain (the server adds a comment, but that's not important). + + ```sh copy + zokrates export-verifier + diff verifier.sol ~/20240901-secret-state/packages/contracts/src/verifier.sol + ``` + +## Design decisions + +In any sufficiently complex application there are competing design goals that require trade-offs. Let's look at some of the tradeoffs and why the current solution is preferable to other options. + +### Why zero-knowledge + +For minesweeper you don't really need zero-knowledge. The server can always hold the map, and then just reveal all of it when the game is over. Then, at the end of the game, the smart contract can calculate the map hash, verify that it matches, and if it doesn't penalize the server or disregard the game completely. + +I didn't use this simpler solution because it only works for short games with a well defined end state. When a game is potentially infinite (such as the case with [autonomous worlds](https://0xparc.org/blog/autonomous-worlds)), you need a solution that proves the state _without_ revealing it. + +As a tutorial this article needed a short game that is easy to understand, but this technique is most useful for longer games. + +### Why Zokrates? + +[Zokrates](https://zokrates.github.io/) isn't the only zero-knowledge library available, but it is similar to a normal, [imperative](https://en.wikipedia.org/wiki/Imperative_programming) programming language and supports boolean variables. + +For your application, with different requirements, you might prefer to use [Circum](https://docs.circom.io/getting-started/installation/) or [Cairo](https://www.cairo-lang.org/tutorials/getting-started-with-cairo/). + +### When to compile Zokrates + +In this program we compile the Zokrates programs [every time the server starts](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L60-L61). This is clearly a waste of resources, but this is a tutorial, optimized for simplicity. + +If I were writing a production-level application, I'd check if I have a file with the compiled Zokrates programs at this minefield size, and if so use that. The same is true for deploying a verifier contract onchain. + +### Creating the verifier and prover keys + +[Key creation](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L63-L69) is another pure calculation that needn't be done more than once for a given minefield size. Again, it is done only once for the sake of simplicity. + +Additionally, we could use [a setup ceremony](https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony). The advantage of a setup ceremony is that you need either the entropy or some intermediate result from each participant to cheat on the zero-knowledge proof. If at least one ceremony participant is honest and deletes that information, the zero-knowledge proofs are safe from certain attacks. However, there is _no mechanism_ to verify that information has been deleted from everywhere. If zero-knowledge proofs are critically important, you want to participate in the setup ceremony. + +Here we rely on [perpetual powers of tau](https://github.com/privacy-scaling-explorations/perpetualpowersoftau), which had dozens of participants. It is probably safe enough, and much simpler. We also don't add entropy to the during key creation, which makes it easier for users to [verify the zero-knowledge configuration](#user-verify-zero-trust). + +### Where to verify + +We can verify the zero-knowledge proofs either onchain (which costs gas) or in the client (using [`verify`](https://zokrates.github.io/toolbox/zokrates_js.html#verifyverificationkey-proof)). I chose the first, because this lets you [verify the verifier](#user-verify-zero-trust) once and then trust that if doesn't change as long as the contract address for it stays the same. If verification was done on the client, you'd have to verify the code you receive each time you download the client. + +Also, while this game is single player, a lot of blockchain games are multi-player. onchain verification means you only verify the zero-knowledge proof once. Doing it in the client would require each client to verify independently. + +### Flatten the map in TypeScript or Zokrates? + +In general, when processing can be done either in TypeScript or Zokrates, it is better to do it TypeScript, which is a lot faster, and does not require zero-knowledge proofs. This is the reason, for example, that we don't provide Zokrates with the hash and make it verify that it is correct. Hashing has to be done inside Zokrates, but the match between the returned hash and the hash onchain can happen outside it. + +However, we still [flatten the map in Zokrates](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L15-L20), whereas we could have done it in TypeScript. The reason is that the other options are, in my opinion, worse. + +- Provide a one dimensional array of boolean to the Zokrates code, and use an expression such as `x*(height+2) ++y` to get the two dimensional map. This would make [the code](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L44-L47) somewhat more complicated, so I decided the performance gain isn't worth it for a tutorial. + +- Send Zokrates both the one dimensional array and the two dimensional array. However, this solution doesn't gain us anything. The Zokrates code would have to verify that the one dimensional array it is provided really is the correct representation of the two dimensional array. So there wouldn't be any performance gain. + +- Flatten the two dimensional array in Zokrates. This is the simplest option, so I chose it. + +### Where to store maps + +In this application [`gamesInProgress`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L20) is simply a variable in memory. This means that if you server dies and needs to be restarted, all the information it stored is lost. Not only are players unable to continue their game, they cannot even start a new game because the onchain component thinks they still have a game in progress. + +This is clearly bad design for a production system, in which you'd store this information in a database. The only reason I used a variable here is because this is a tutorial and simplicity is the main consideration. + +## Conclusion: Under what conditions is this the appropriate technique? + +So, now you know how to write a game with a server that stores secret state that doesn't belong onchain. But in what cases should you do it? There are two main considerations. + +- _Long running game_: [As mentioned above](#why-zero-knowledge), in a short game you can just publish the state once the game is over and have everything verified then. But that is not an option when the game takes a long or indefinite time, and the state needs to stay secret. + +- _Some centralization acceptable_: Zero-knowledge proofs can verify integrity, that an entity is not faking the results. What they can't do is ensure that the entity will still be available and answer messages. In situations where availability also needs to be decentralized, zero-knowledge proofs are not a sufficient solution, and you need [multi-party computation](https://en.wikipedia.org/wiki/Secure_multi-party_computation). + +### Acknowledgements + +- Alvaro Alonso read a draft of this article and cleared up some of my misunderstandings about Zokrates. + +Any remaining errors are my responsibility. + +--- + +## Developers > Tutorials > Secure Development Workflow + +## Smart contract development checklist + +Here's a high-level process we recommend following while you write your smart contracts. + +Check for known security issues: + +- Review your contracts with [Slither](https://github.com/crytic/slither). It has more than 40 built-in detectors for common vulnerabilities. Run it on every check-in with new code and ensure it gets a clean report (or use triage mode to silence certain issues). +- Review your contracts with [Crytic](https://crytic.io/). It checks for 50 issues that Slither does not. Crytic can help your team stay on top of each other too, by easily surfacing security issues in Pull Requests on GitHub. + +Consider special features of your contract: + +- Are your contracts upgradeable? Review your upgradeability code for flaws with [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) or [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/). We've documented 17 ways upgrades can go sideways. +- Do your contracts purport to conform to ERCs? Check them with [`slither-check-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance). This tool instantly identifies deviations from six common specs. +- Do you integrate with 3rd party tokens? Review our [token integration checklist](/developers/tutorials/token-integration-checklist/) before relying on external contracts. + +Visually inspect critical security features of your code: + +- Review Slither's [inheritance-graph](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) printer. Avoid inadvertent shadowing and C3 linearization issues. +- Review Slither's [function-summary](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) printer. It reports function visibility and access controls. +- Review Slither's [vars-and-auth](https://github.com/trailofbits/slither/wiki/Printer-documentation#variables-written-and-authorization) printer. It reports access controls on state variables. + +Document critical security properties and use automated test generators to evaluate them: + +- Learn to [document security properties for your code](/developers/tutorials/guide-to-smart-contract-security-tools/). It's tough as first, but it's the single most important activity for achieving a good outcome. It's also a prerequisite for using any of the advanced techniques in this tutorial. +- Define security properties in Solidity, for use with [Echidna](https://github.com/crytic/echidna) and [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html). Focus on your state machine, access controls, arithmetic operations, external interactions, and standards conformance. +- Define security properties with [Slither's Python API](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/). Focus on inheritance, variable dependencies, access controls, and other structural issues. +- Run your property tests on every commit with [Crytic](https://crytic.io). Crytic can consume and evaluate security property tests so everyone on your team can easily see that they pass on GitHub. Failing tests can block commits. + +Finally, be mindful of issues that automated tools cannot easily find: + +- Lack of privacy: everyone else can see your transactions while they're queued in the pool +- Front running transactions +- Cryptographic operations +- Risky interactions with external DeFi components + +## Ask for help + +[Ethereum office hours](https://calendly.com/dan-trailofbits/office-hours) run every Tuesday afternoon. These 1-hour, 1-on-1 sessions are an opportunity to ask us any questions you have about security, troubleshoot using our tools, and get feedback from experts about your current approach. We will help you work through this guide. + +Join our Slack: [Empire Hacking](https://join.slack.com/t/empirehacking/shared_invite/zt-h97bbrj8-1jwuiU33nnzg67JcvIciUw). We're always available in the #crytic and #ethereum channels if you have any questions. + +--- + +## Developers > Tutorials > Send Token Ethersjs + +## Send Token Using ethers.js(5.0) + +### In This Tutorial You'll Learn How To + +- Import ethers.js +- Transfer token +- Set gas price according to the network traffic situation + +### To-Get-Started + +To get started, we must first import the ethers.js library into our javascript +Include ethers.js(5.0) + +### Installing + +```shell +/home/ricmoo> npm install --save ethers +``` + +ES6 in the Browser + +```html + + // Your code here... + +``` + +ES3(UMD) in the Browser + +```html + +``` + +### Parameters + +1. **`contract_address`**: Token contract address (contract address is needed when the token you want to transfer is not ether) +2. **`send_token_amount`**: The amount you want to send to the receiver +3. **`to_address`**: The receiver's address +4. **`send_account`**: The sender's address +5. **`private_key`**: Private key of the sender to sign the transaction and actually transfer the tokens + +## Notice + +`signTransaction(tx)` is removed because `sendTransaction()` does it internally. + +## Sending Procedures + +### 1. Connect to network (testnet) + +#### Set Provider (Infura) + +Connect to Ropsten testnet + +```javascript +window.ethersProvider = new ethers.providers.InfuraProvider("ropsten") +``` + +### 2. Create wallet + +```javascript +let wallet = new ethers.Wallet(private_key) +``` + +### 3. Connect Wallet to net + +```javascript +let walletSigner = wallet.connect(window.ethersProvider) +``` + +### 4. Get current gas price + +```javascript +window.ethersProvider.getGasPrice() // gasPrice +``` + +### 5. Define Transaction + +These variables defined below are dependent on `send_token()` + +### Transaction parameters + +1. **`send_account`**: address of the token sender +2. **`to_address`**: address of the token receiver +3. **`send_token_amount`**: the amount of tokens to send +4. **`gas_limit`**: gas limit +5. **`gas_price`**: gas price + +[See below for how to use](#how-to-use) + +```javascript +const tx = +``` + +### 6. Transfer + +```javascript +walletSigner.sendTransaction(tx).then((transaction) => ) +``` + +## How to use it + +```javascript +let private_key = + "41559d28e936dc92104ff30691519693fc753ffbee6251a611b9aa1878f12a4d" +let send_token_amount = "1" +let to_address = "0x4c10D2734Fb76D3236E522509181CC3Ba8DE0e80" +let send_address = "0xda27a282B5B6c5229699891CfA6b900A716539E6" +let gas_limit = "0x100000" +let wallet = new ethers.Wallet(private_key) +let walletSigner = wallet.connect(window.ethersProvider) +let contract_address = "" +window.ethersProvider = new ethers.providers.InfuraProvider("ropsten") + +send_token( + contract_address, + send_token_amount, + to_address, + send_address, + private_key +) +``` + +### Success! + +![image of transaction done successfully](./successful-transaction.png) + +## send_token() + +```javascript +function send_token( + contract_address, + send_token_amount, + to_address, + send_account, + private_key +) `) + + if (contract_address) `) + + // Send tokens + contract.transfer(to_address, numberOfTokens).then((transferResult) => ) + } // ether send + else + console.dir(tx) + try ) + } catch (error) + } + }) +} +``` + +--- + +## Developers > Tutorials > Sending Transactions Using Web3 And Alchemy + +This is a beginner friendly guide to sending Ethereum transactions using Web3. There are three main steps in order to send a transaction to the Ethereum blockchain: create, sign, and broadcast. We’ll go through all three, hopefully answering any questions you might have! In this tutorial, we'll be using [Alchemy](https://www.alchemy.com/) to send our transactions to the Ethereum chain. You can [create a free Alchemy account here](https://auth.alchemyapi.io/signup). + +**NOTE:** This guide is for signing your transactions on the _backend_ for your app. If you want to integrate signing your transactions on the frontend, check out integrating [Web3 with a browser provider](https://docs.alchemy.com/reference/api-overview#with-a-browser-provider). + +## The Basics + +Like most blockchain developers when they first start, you might have done some research on how to send a transaction (something that should be pretty simple) and ran into a plethora of guides, each saying different things and leaving you a bit overwhelmed and confused. If you’re in that boat, don’t worry; we all were at some point! So, before we start, let’s get a few things straight: + +### 1\. Alchemy does not store your private keys + +- This means that Alchemy cannot sign and send transactions on your behalf. The reason for this is security purposes. Alchemy will never ask you to share your private key, and you should never share your private key with a hosted node (or anyone for that matter). +- You can read from the blockchain using Alchemy’s core API, but to write to it you’ll need to use something else to sign your transactions before sending them through Alchemy (this is the same for any other [node service](/developers/docs/nodes-and-clients/nodes-as-a-service/)). + +### 2\. What is a “signer”? + +- Signers will sign transactions for you using your private key. In this tutorial we’ll be using [Alchemy web3](https://docs.alchemyapi.io/alchemy/documentation/alchemy-web3) to sign our transaction, but you could also use any other web3 library. +- On the frontend, a good example of a signer would be [MetaMask](https://metamask.io/), which will sign and send transactions on your behalf. + +### 3\. Why do I need to sign my transactions? + +- Every user that wants to send a transaction on the Ethereum network must sign the transaction (using their private key), in order to validate that the origin of the transaction is who it claims to be. +- It is super important to protect this private key, since having access to it grants full control over your Ethereum account, allowing you (or anyone with access) to perform transactions on your behalf. + +### 4\. How do I protect my private key? + +- There are many ways to protect your private key and to use it to send off transactions. In this tutorial we will be using a `.env` file. However, you could also use a separate provider that stores private keys, use a keystore file, or other options. + +### 5\. What is the difference between `eth_sendTransaction` and `eth_sendRawTransaction`? + +`eth_sendTransaction` and `eth_sendRawTransaction` are both Ethereum API functions which broadcast a transaction to the Ethereum network so it will be added to a future block. They differ in how they handle signing of the transactions. + +- [`eth_sendTransaction`](https://docs.web3js.org/api/web3-eth/function/sendTransaction) is used for sending _unsigned_ transactions, which means the node you are sending to must manage your private key so it can sign the transaction before broadcasting it to the chain. Since Alchemy doesn't hold user's private keys, they do not support this method. +- [`eth_sendRawTransaction`](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction) is used to broadcast transactions that have already been signed. This means you first have to use [`signTransaction(tx, private_key)`](https://docs.web3js.org/api/web3-eth-accounts/function/signTransaction), then pass in the result into `eth_sendRawTransaction`. + +When using web3, `eth_sendRawTransaction` is accessed by calling the function [web3.eth.sendSignedTransaction](https://docs.web3js.org/api/web3-eth/function/sendSignedTransaction). + +This is what we will be using in this tutorial. + +### 6\. What is the web3 library? + +- Web3.js is a wrapper library around the standard JSON-RPC calls that is quite common to use in Ethereum development. +- There are many web3 libraries for different languages. In this tutorial we’ll be using [Alchemy Web3](https://docs.alchemy.com/reference/api-overview) which is written in JavaScript. You can check out other options [here](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries) like [ethers.js](https://docs.ethers.org/v5/). + +Okay, now that we have a few of these questions out of the way, let’s move on to the tutorial. Feel free to ask questions anytime in the Alchemy [discord](https://discord.gg/gWuC7zB)! + +### 7\. How to send secure, gas-optimized, and private transactions? + +- [Alchemy has a suite of Transact APIs](https://docs.alchemy.com/reference/transact-api-quickstart). You can use these to send reinforced transactions, simulate transactions before they happen, send private transactions, and send gas-optimized transactions +- You can also use the [Notify API](https://docs.alchemy.com/docs/alchemy-notify) to be alerted when your transaction is pulled from the mempool and added to the chain + +**NOTE:** This guide requires an Alchemy account, an Ethereum address or MetaMask wallet, NodeJs, and npm installed. If not, follow these steps: + +1. [Create a free Alchemy account](https://auth.alchemyapi.io/signup) +2. [Create MetaMask account](https://metamask.io/) (or get an Ethereum address) +3. [Follow these steps to install NodeJs and NPM](https://docs.alchemy.com/alchemy/guides/alchemy-for-macs) + +## Steps to Sending your Transaction + +### 1\. Create an Alchemy app on the Sepolia testnet + +Navigate to your [Alchemy Dashboard](https://dashboard.alchemyapi.io/) and create a new app, choosing Sepolia (or any other testnet) for your network. + +### 2\. Request ETH from the Sepolia faucet + +Follow the instructions on the [Alchemy Sepolia faucet](https://www.sepoliafaucet.com/) to receive ETH. Make sure to include your **Sepolia** Ethereum address (from MetaMask) and not another network. After following the instructions, double-check that you’ve received the ETH in your wallet. + +### 3\. Create a new project directory and `cd` into it + +Create a new project directory from the command line (terminal for macs) and navigate into it: + +``` +mkdir sendtx-example +cd sendtx-example +``` + +### 4\. Install Alchemy Web3 (or any web3 library) + +Run the following command in your project directory to install [Alchemy Web3](https://docs.alchemy.com/reference/api-overview): + +Note, if you'd like to use the ethers.js library, [follow the instructions here](https://docs.alchemy.com/docs/how-to-send-transactions-on-ethereum). + +``` +npm install @alch/alchemy-web3 +``` + +### 5\. Install dotenv + +We’ll use a `.env` file to safely store our API key and private key. + +``` +npm install dotenv --save +``` + +### 6\. Create the `.env` file + +Create a `.env` file in your project directory and add the following (replacing “`your-api-url`" and "`your-private-key`") + +- To find your Alchemy API URL, navigate to the app details page of the app you just created on your dashboard, click “View Key” in the top right corner, and grab the HTTP URL. +- To find your private key using MetaMask, check out this [guide](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key). + +``` +API_URL = "your-api-url" +PRIVATE_KEY = "your-private-key" +``` + + +Don't commit .env! Please make sure never to share or expose your .env file with anyone, as you are compromising your secrets in doing so. If you are using version control, add your .env to a gitignore file. + + +### 7\. Create `sendTx.js` file + +Great, now that we have our sensitive data protected in a `.env` file, let’s start coding. For our send transaction example, we’ll be sending ETH back to the Sepolia faucet. + +Create a `sendTx.js` file, which is where we will configure and send our example transaction, and add the following lines of code to it: + +``` +async function main() = process.env; + const = require("@alch/alchemy-web3"); + const web3 = createAlchemyWeb3(API_URL); + const myAddress = '0x610Ae88399fc1687FA7530Aac28eC2539c7d6d63' //TODO: replace this address with your own public address + + const nonce = await web3.eth.getTransactionCount(myAddress, 'latest'); // nonce starts counting from 0 + + const transaction = ; + + const signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); + + web3.eth.sendSignedTransaction(signedTx.rawTransaction, function(error, hash) else + }); +} + +main(); +``` + +Be sure to replace the address on **line 6** with your own public address. + +Now, before we jump into running this code, let's talk about some of the components here. + +- `nonce` : The nonce specification is used to keep track of the number of transactions sent from your address. We need this for security purposes and to prevent [replay attacks](https://docs.alchemyapi.io/resources/blockchain-glossary#account-nonce). To get the number of transactions sent from your address we use [getTransactionCount](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_gettransactioncount). +- `transaction`: The transaction object has a few aspects we need to specify + - `to`: This is the address we want to send ETH to. In this case, we are sending ETH back to the [Sepolia faucet](https://sepoliafaucet.com/) we initially requested from. + - `value`: This is the amount we wish to send, specified in Wei where 10^18 Wei = 1 ETH + - `gas`: There are many ways to determine the right amount of gas to include with your transaction. Alchemy even has a [gas price webhook](https://docs.alchemyapi.io/guides/alchemy-notify#address-activity-1) to notify you when the gas price falls within a certain threshold. For Mainnet transactions, it's good practice to check a gas estimator like [ETH Gas Station](https://ethgasstation.info/) to determine the right amount of gas to include. 21000 is the minimum amount of gas an operation on Ethereum will use, so to ensure our transaction will be executed we put 30000 here. + - `nonce`: see above nonce definition. Nonce starts counting from zero. + - [OPTIONAL] data: Used for sending additional information with your transfer, or calling a smart contract, not required for balance transfers, check out the note below. +- `signedTx`: To sign our transaction object we will use the `signTransaction` method with our `PRIVATE_KEY` +- `sendSignedTransaction`: Once we have a signed transaction, we can send it off to be included in a subsequent block by using `sendSignedTransaction` + +**A Note on data** +There are a two main types of transactions that can be sent in Ethereum. + +- Balance transfer: Send ETH from one address to another. No data field required, however, if you'd like to send additional information alongside your transaction, you can include that information in HEX format in this field. + - For example, let's say we wanted to write the hash of an IPFS document to the Ethereum chain in order to give it an immutable timestamp. Our data field should then look like data: `web3.utils.toHex(‘IPFS hash‘)`. And now anyone can query the chain and see when that document was added. +- Smart contract transaction: Execute some smart contract code on the chain. In this case, the data field should contain the smart function you wish to execute, alongside any parameters. + - For a practical example, check out Step 8 in this [Hello World Tutorial](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#step-8-create-the-transaction). + +### 8\. Run the code using `node sendTx.js` + +Navigate back to your terminal or command line and run: + +``` +node sendTx.js +``` + +### 9\. See your transaction in the Mempool + +Open up the [Mempool page](https://dashboard.alchemyapi.io/mempool) in your Alchemy dashboard and filter by the app you created to find your transaction. This is where we can watch our transaction transition from pending state to mined state (if successful) or dropped state if unsuccessful. Make sure to keep it on “All” so that you capture “mined”, “pending”, and “dropped” transactions. You can also search for your transaction by looking for transactions sent to address `0x31b98d14007bdee637298086988a0bbd31184523` . + +To view the details of your transaction once you’ve found it, select the tx hash, which should take you to a view that looks like this: + +![Mempool watcher screenshot](./mempool.png) + +From there you can view your transaction on Etherscan by clicking on the icon circled in red! + +**Yippieeee! You just sent your first Ethereum transaction using Alchemy 🎉** + +_For feedback and suggestions about this guide, please message Elan on Alchemy’s [Discord](https://discord.gg/A39JVCM)!_ + +_Originally published at [https://docs.alchemyapi.io/tutorials/sending-transactions-using-web3-and-alchemy](https://docs.alchemyapi.io/tutorials/sending-transactions-using-web3-and-alchemy)_ + +--- + +## Developers > Tutorials > Server Components + +## Introduction + +In most cases, a decentralized app uses a server to distribute the software, but all the actual interaction happens between the client (typically, web browser) and the blockchain. + +![Normal interaction between web server, client, and blockchain](./fig-1.svg) + +However, there are some cases where an application would benefit from having a server component that runs independently. Such a server would be able to respond to events, and to requests that come from other sources, such as an API, by issuing transactions. + +![The interaction with the addition of a server](./fig-2.svg) + +There are several possible tasks for such a server could fulfill. + +- Holder of secret state. In gaming it is often useful not to have all the information that the game knows available to the players. However, *there are no secrets on the blockchain*, any information that is in the blockchain is easy for anybody to figure out. Therefore, if part of the game state is to be kept secret, it has to be stored elsewhere (and possibly have the effects of that state verified using [zero-knowledge proofs](/zero-knowledge-proofs)). + +- Centralized oracle. If the stakes are sufficiently low, an external server that reads some information online and then posts it to the chain may be good enough to use as an [oracle](/developers/docs/oracles/). + +- Agent. Nothing happens on the blockchain without a transaction to activate it. A server can act on behalf of a user to perform actions such as [arbitrage](/developers/docs/mev/#mev-examples-dex-arbitrage) when the opportunity presents itself. + +## Sample program + +You can see a sample server [on github](https://github.com/qbzzt/20240715-server-component). This server listens to events coming from [this contract](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=contract_code), a modified version of Hardhat's Greeter. When the greeting is changed, it changes it back. + +To run it: + +1. Clone the repository. + + ```sh copy + git clone https://github.com/qbzzt/20240715-server-component.git + cd 20240715-server-component + ``` + +2. Install the necessary packages. If you don't have it already, [install Node first](https://nodejs.org/en/download/package-manager). + + ```sh copy + npm install + ``` + +3. Edit `.env` to specify the private key of an account that has ETH on the Holesky testnet. If you do not have ETH on Holesky, you can [use this faucet](https://holesky-faucet.pk910.de/). + + ```sh filename=".env" copy + PRIVATE_KEY=0x + ``` + +4. Start the server. + + ```sh copy + npm start + ``` + +5. Go to [a block explorer](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=write_contract), and using a different address than the one that has the private key modify the greeting. See that the greeting is automatically modified back. + +### How does it work? + +The easiest way to understand how to write a server component is to go over the sample one line by line. + +#### `src/app.ts` + +The vast majority of the program is contained in [`src/app.ts`](https://github.com/qbzzt/20240715-server-component/blob/main/src/app.ts). + + +##### Creating the prerequisite objects + +```typescript +``` + +These are the [Viem](https://viem.sh/) entities we need, functions and [the `Address` type](https://viem.sh/docs/glossary/types#address). This server is written in [TypeScript](https://www.typescriptlang.org/), which is an extension to JavaScript that makes it [strongly typed](https://en.wikipedia.org/wiki/Strong_and_weak_typing). + +```typescript +``` + +[This function](https://viem.sh/docs/accounts/privateKey) lets us generate the wallet information, including address, corresponding to a private key. + +```typescript +``` + +To use a blockchain in Viem you need to import its definition. In this case, we want to connect to the [Holesky](https://github.com/eth-clients/holesky) test blockchain. + +```typescript +// This is how we add the definitions in .env to process.env. +dotenv.config() +``` + +This is how we read `.env` into the environment. We need it for the private key (see later). + +```typescript +const greeterAddress : Address = "0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6" +const greeterABI = [ + + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + . + . + . + + ], + "name": "setGreeting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const +``` + +To use a contract we need its address and the [ABI](/glossary/#abi) for it. We provide both here. + +In JavaScript (and therefore TypeScript) you can't assign a new value to a constant, but you *can* modify the object that is stored in it. By using the suffix `as const` we are telling TypeScript that the list itself is constant and may not be changed. + +```typescript +const publicClient = createPublicClient() +``` + +Create a Viem [public client](https://viem.sh/docs/clients/public.html). Public clients do not have an attached private key, and therefore cannot send transactions. They can call [`view` functions](https://www.tutorialspoint.com/solidity/solidity_view_functions.htm), read account balances, etc. + +```typescript +const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x$`) +``` + +The environment variables are available in [`process.env`](https://www.totaltypescript.com/how-to-strongly-type-process-env). However, TypeScript is strongly typed. An environment variable can be be any string, or empty, so the type for an environment variable is `string | undefined`. However, a key is defined in Viem as `0x$` (`0x` followed by a string). Here we tell TypeScript that the `PRIVATE_KEY` environment variable will be of that type. If it isn't, we'll get a runtime error. + +The [`privateKeyToAccount`](https://viem.sh/docs/accounts/privateKey) function then uses this private key to create a full account object. + +```typescript +const walletClient = createWalletClient() +``` + +Next, we use the account object to create a [wallet client](https://viem.sh/docs/clients/wallet). This client has a private key and an address, so it can be used to send transactions. + +```typescript +const greeter = getContract( +}) +``` + +Now that we have all the prerequisites, we can finally create a [contract instance](https://viem.sh/docs/contract/getContract). We will use this contract instance to communicate with the onchain contract. + + +##### Reading from the blockchain + +```typescript +console.log(`Current greeting:`, await greeter.read.greet()) +``` + +The contract functions that are read only ([`view`](https://www.tutorialspoint.com/solidity/solidity_view_functions.htm) and [`pure`](https://www.tutorialspoint.com/solidity/solidity_pure_functions.htm)) are available under `read`. In this case, we use it to access the [`greet`](https://eth-holesky.blockscout.com/address/0xB8f6460Dc30c44401Be26B0d6eD250873d8a50A6?tab=read_contract#cfae3217) function, which returns the greeting. + +JavaScript is single-threaded, so when we fire off a long running process we need to [specify we do it asynchronously](https://eloquentjavascript.net/11_async.html#h-XvLsfAhtsE). Calling the blockchain, even for a read only operation, requires a round-trip between the computer and a blockchain node. That is the reason we specify here the code needs to `await` for the result. + +If you are interested in how this work you can [read about it here](https://www.w3schools.com/js/js_promise.asp), but in practical terms all you need to know is that you `await` the results if you start an operation that takes a long time, and that any function that does this has to be declared as `async`. + + +##### Issuing transactions + +```typescript +const setGreeting = async (greeting: string): Promise => `) + + return txHash +} +``` + +Report the hash of the transaction (as part of a URL to the block explorer to view it) and return it. + + +##### Responding to events + +```typescript +greeter.watchEvent.SetGreeting( changed the greeting to $`) +``` + +There could be multiple events, but foir simplicity we only care about the first one. `logs[0].args` are the arguments of the event, in this case `sender` and `greeting`. + +```typescript + if (logs[0].args.sender != account.address) + setGreeting(`$ insists on it being Hello!`) + } +}) +``` + +If the sender is *not* this server, use `setGreeting` to change the greeting. + +#### `package.json` + +[This file](https://github.com/qbzzt/20240715-server-component/blob/main/package.json) controls the [Node.js](https://nodejs.org/en) configuration. This article only explains the important definitions. + +```json +, +``` + +The scripts are various application actions. In this case, the only one we have is `start`, which compiles and then runs the server. The `tsc` command is part of the `typescript` package and compiles TypeScript into JavaScript. If you want to run it manually, it is located in `node_modules/.bin`. The second command runs the server. + +```json + "type": "module", +``` + +There are multiple types of JavaScript node applications. The `module` type lets us have `await` in the top level code, which is important when you do slow (and there asynchronous) operations. + +```json + "devDependencies": , +``` + +These are packages that are only required for development. Here we need `typescript` and the because we are using it with Node.js, we are also getting the types for node variables and objects, such as `process`. [The `^` notation](https://github.com/npm/node-semver?tab=readme-ov-file#caret-ranges-123-025-004) means that version or a higher version that doesn't have breaking changes. See [here](https://semver.org) for more information about the meaning of version numbers. + +```json + "dependencies": +} +``` + +These are packages that are required at runtime, when running `dist/app.js`. + +## Conclusion + +The centralized server we created here does its job, which is to act as an agent for a user. Anybody else who wants the dapp to continue functioning and is willing to spend the gas can run a new instance of the server with their own address. + +However, this only works when the centralized server's actions can be easily verified. If the centralized server has any secret state information, or runs difficult calculations, it is a centralized entity that you need trust to use the application, which is exactly what blockchains try to avoid. In a future article I plan to show how to use [zero-knowledge proofs](/zero-knowledge-proofs) to get around this problem. + +--- + +## Developers > Tutorials > Set Up Web3js To Use Ethereum In Javascript + +In this tutorial, we’ll see how to get started with [web3.js](https://web3js.readthedocs.io/) to interact with the Ethereum blockchain. Web3.js can be used both in frontends and backends to read data from the blockchain or make transactions and even deploy smart contracts. + +The first step is to include web3.js in your project. To use it in a web page, you can import the library directly using a CDN like JSDeliver. + +```html + +``` + +If you prefer installing the library to use in your backend or a frontend project that uses build you can install it using npm: + +```bash +npm install web3 --save +``` + +Then to import Web3.js into a Node.js script or Browserify frontend project, you can use the following line of JavaScript: + +```js +const Web3 = require("web3") +``` + +Now that we included the library in the project we need to initialize it. Your project needs to be able to communicate with the blockchain. Most Ethereum libraries communicate with a [node](/developers/docs/nodes-and-clients/) through RPC calls. To initiate our Web3 provider, we’ll instantiate a Web3 instance passing as the constructor the URL of the provider. If you have a node or [ganache instance running on your computer](https://ethereumdev.io/testing-your-smart-contract-with-existing-protocols-ganache-fork/) it will look like this: + +```js +const web3 = new Web3("http://localhost:8545") +``` + +If you’d like to directly access a hosted node you can find options on [nodes as a service](/developers/docs/nodes-and-clients/nodes-as-a-service). + +```js +const web3 = new Web3("https://cloudflare-eth.com") +``` + +To test that we correctly configured our Web3 instance, we’ll try to retrieve the latest block number using the `getBlockNumber` function. This function accepts a callback as a parameter and returns the block number as an integer. + +```js +var Web3 = require("web3") +const web3 = new Web3("https://cloudflare-eth.com") + +web3.eth.getBlockNumber(function (error, result) ) +``` + +If you execute this program, it will simply print the latest block number: the top of the blockchain. You can also use `await/async` function calls to avoid nesting callbacks in your code: + +```js +async function getBlockNumber() + +getBlockNumber() +``` + +You can see all the functions available on the Web3 instance in [the official web3.js documentation](https://docs.web3js.org/). + +Most of Web3 libraries are asynchronous because in the background the library makes JSON-RPC calls to the node which send backs the result. + + + +If you are working in the browser, some wallets directly inject a Web3 instance and you should try to use it whenever possible especially if you plan to interact with the user’s Ethereum address to make transactions. + +Here is the snippet to detect if a MetaMask wallet is available and try to enable it if it is. It will later allow you to read the user’s balance and enable them to validate transactions you’d like to make them do on the Ethereum blockchain: + +```js +if (window.ethereum != null) catch (error) +} +``` + +Alternatives to web3.js like [Ethers.js](https://docs.ethers.io/) do exist and are also commonly used. In the next tutorial we’ll see [how to easily listen to new incoming blocks on the blockchain and see what they contain](https://ethereumdev.io/listening-to-new-transactions-happening-on-the-blockchain/). + +--- + +## Developers > Tutorials > Short Abi + +## Introduction + +In this article, you learn about [optimistic rollups](/developers/docs/scaling/optimistic-rollups), the cost of transactions on them, and how that different cost structure requires us to optimize for different things than on the Ethereum Mainnet. +You also learn how to implement this optimization. + +### Full disclosure + +I'm a full time [Optimism](https://www.optimism.io/) employee, so examples in this article will run on Optimism. +However, the technique explained here should work just as well for other rollups. + +### Terminology + +When discussing rollups, the term 'layer 1' (L1) is used for Mainnet, the production Ethereum network. +The term 'layer 2' (L2) is used for the rollup or any other system that relies on L1 for security but does most of its processing offchain. + +## How can we further reduce the cost of L2 transactions? + +[Optimistic rollups](/developers/docs/scaling/optimistic-rollups) have to preserve a record of every historical transaction so that anybody will be able to go through them and verify that the current state is correct. +The cheapest way to get data into the Ethereum Mainnet is to write it as calldata. +This solution was chosen by both [Optimism](https://help.optimism.io/hc/en-us/articles/4413163242779-What-is-a-rollup-) and [Arbitrum](https://developer.offchainlabs.com/docs/rollup_basics#intro-to-rollups). + +### Cost of L2 transactions + +The cost of L2 transactions is composed of two components: + +1. L2 processing, which is usually extremely cheap +2. L1 storage, which is tied to Mainnet gas costs + +As I'm writing this, on Optimism the cost of L2 gas is 0.001 [Gwei](/developers/docs/gas/#pre-london). +The cost of L1 gas, on the other hand, is approximately 40 gwei. +[You can see the current prices here](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m). + +A byte of calldata costs either 4 gas (if it is zero) or 16 gas (if it is any other value). +One of the most expensive operations on the EVM is writing to storage. +The maximum cost of writing a 32-byte word to storage on L2 is 22100 gas. Currently, this is 22.1 gwei. +So if we can save a single zero byte of calldata, we'll be able to write about 200 bytes to storage and still come out ahead. + +### The ABI + +The vast majority of transactions access a contract from an externally-owned account. +Most contracts are written in Solidity and interpret their data field per [the application binary interface (ABI)](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). + +However, the ABI was designed for L1, where a byte of calldata costs approximately the same as four arithmetic operations, not L2 where a byte of calldata costs more than a thousand arithmetic operations. +The calldata is divided like this: + +| Section | Length | Bytes | Wasted bytes | Wasted gas | Necessary bytes | Necessary gas | +| ------------------- | -----: | ----: | -----------: | ---------: | --------------: | ------------: | +| Function selector | 4 | 0-3 | 3 | 48 | 1 | 16 | +| Zeroes | 12 | 4-15 | 12 | 48 | 0 | 0 | +| Destination address | 20 | 16-35 | 0 | 0 | 20 | 320 | +| Amount | 32 | 36-67 | 17 | 64 | 15 | 240 | +| Total | 68 | | | 160 | | 576 | + +Explanation: + +- **Function selector**: The contract has less than 256 functions, so we can distinguish them with a single byte. + These bytes are typically non-zero and therefore [cost sixteen gas](https://eips.ethereum.org/EIPS/eip-2028). +- **Zeroes**: These bytes are always zero because a twenty-byte address does not require a thirty-two-byte word to hold it. + Bytes that hold zero cost four gas ([see the yellow paper](https://ethereum.github.io/yellowpaper/paper.pdf), Appendix G, + p. 27, the value for `G``txdatazero`). +- **Amount**: If we assume that in this contract `decimals` is eighteen (the normal value) and the maximum amount of tokens we transfer will be 1018, we get a maximum amount of 1036. + 25615 > 1036, so fifteen bytes are enough. + +A waste of 160 gas on L1 is normally negligible. A transaction costs at least [21,000 gas](https://yakkomajuri.medium.com/blockchain-definition-of-the-week-ethereum-gas-2f976af774ed), so an extra 0.8% doesn't matter. +However, on L2, things are different. Almost the entire cost of the transaction is writing it to L1. +In addition to the transaction calldata, there are 109 bytes of transaction header (destination address, signature, etc.). +The total cost is therefore `109*16+576+160=2480`, and we are wasting about 6.5% of that. + +## Reducing costs when you don't control the destination + +Assuming that you do not have control over the destination contract, you can still use a solution similar to [this one](https://github.com/qbzzt/ethereum.org-20220330-shortABI). +Let's go over the relevant files. + +### Token.sol + +[This is the destination contract](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/Token.sol). +It is a standard ERC-20 contract, with one additional feature. +This `faucet` function lets any user get some token to use. +It would make a production ERC-20 contract useless, but it makes life easier when an ERC-20 exists only to facilitate testing. + +```solidity + /** + * @dev Gives the caller 1000 tokens to play with + */ + function faucet() external // function faucet +``` + +### CalldataInterpreter.sol + +[This is the contract that transactions are supposed to call with shorter calldata](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/CalldataInterpreter.sol). +Let's go over it line by line. + +```solidity +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + + +``` + +We need the token function to know how to call it. + +```solidity +contract CalldataInterpreter // constructor +``` + +The token address is the only parameter we need to specify. + +```solidity + function calldataVal(uint startByte, uint length) + private pure returns (uint) + + + fallback() external +``` + +After we call `token.faucet()` we get tokens. However, as the proxy contract, we do not **need** tokens. +The EOA (externally owned account) or contract that called us does. +So we transfer all of our tokens to whoever called us. + +```solidity + // transfer (assume we have an allowance for it) + if (_func == 2) +``` + +Overall, a transfer takes 35 bytes of calldata: + +| Section | Length | Bytes | +| ------------------- | -----: | ----: | +| Function selector | 1 | 0 | +| Destination address | 32 | 1-32 | +| Amount | 2 | 33-34 | + +```solidity + } // fallback + +} // contract CalldataInterpreter +``` + +### test.js + +[This JavaScript unit test](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/test/test.js) shows us how to use this mechanism (and how to verify it works correctly). +I am going to assume you understand [chai](https://www.chaijs.com/) and [ethers](https://docs.ethers.io/v5/) and only explain the parts that specifically apply to the contract. + +```js +const = require("chai"); + +describe("CalldataInterpreter", function () + await (await signer.sendTransaction(faucetTx)).wait() +``` + +We call [the signer's `sendTransaction` method](https://docs.ethers.io/v5/api/signer/#Signer-sendTransaction) because we already specified the destination (`faucetTx.to`) and we need the transaction to be signed. + +```javascript +// Check the faucet provides the tokens correctly +expect(await token.balanceOf(signer.address)).to.equal(1000) +``` + +Here we verify the balance. +There is no need to save gas on `view` functions, so we just run them normally. + +```javascript +// Give the CDI an allowance (approvals cannot be proxied) +const approveTX = await token.approve(cdi.address, 10000) +await approveTX.wait() +expect(await token.allowance(signer.address, cdi.address)).to.equal(10000) +``` + +Give the calldata interpreter an allowance to be able to do transfers. + +```javascript +// Transfer tokens +const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" +const transferTx = +``` + +Create a transfer transaction. The first byte is "0x02", followed by the destination address, and finally the amount (0x0100, which is 256 in decimal). + +```javascript + await (await signer.sendTransaction(transferTx)).wait() + + // Check that we have 256 tokens less + expect (await token.balanceOf(signer.address)).to.equal(1000-256) + + // And that our destination got them + expect (await token.balanceOf(destAddr)).to.equal(256) + }) // it +}) // describe +``` + +## Reducing the cost when you do control the destination contract + +If you do have control over the destination contract you can create functions that bypass the `msg.sender` checks because they trust the calldata interpreter. +[You can see an example of how this works here, in the `control-contract` branch](https://github.com/qbzzt/ethereum.org-20220330-shortABI/tree/control-contract). + +If the contract were responding only to external transactions, we could get by with having just one contract. +However, that would break [composability](/developers/docs/smart-contracts/composability/). +It is much better to have a contract that responds to normal ERC-20 calls, and another contract that responds to transactions with short call data. + +### Token.sol + +In this example we can modify `Token.sol`. +This lets us have a number of functions that only the proxy may call. +Here are the new parts: + +```solidity + // The only address allowed to specify the CalldataInterpreter address + address owner; + + // The CalldataInterpreter address + address proxy = address(0); +``` + +The ERC-20 contract needs to know the identity of the authorized proxy. +However, we cannot set this variable in the constructor, because we don't know the value yet. +This contract is instantiated first because the proxy expects the token's address in its constructor. + +```solidity + /** + * @dev Calls the ERC20 constructor. + */ + constructor( + ) ERC20("Oris useless token-2", "OUT-2") +``` + +The address of the creator (called `owner`) is stored here because that is the only address allowed to set the proxy. + +```solidity + /** + * @dev set the address for the proxy (the CalldataInterpreter). + * Can only be called once by the owner + */ + function setProxy(address _proxy) external // function setProxy +``` + +The proxy has privileged access, because it can bypass security checks. +To make sure we can trust the proxy we only let `owner` call this function, and only once. +Once `proxy` has a real value (not zero), that value cannot change, so even if the owner decides to become rogue, or the mnemonic for it is revealed, we are still safe. + +```solidity + /** + * @dev Some functions may only be called by the proxy. + */ + modifier onlyProxy +``` + +If so, run the function which we modify. + +```solidity + /* Functions that allow the proxy to actually proxy for accounts */ + + function transferProxy(address from, address to, uint256 amount) + public virtual onlyProxy() returns (bool) + + + function approveProxy(address from, address spender, uint256 amount) + public virtual onlyProxy() returns (bool) + + + function transferFromProxy( + address spender, + address from, + address to, + uint256 amount + ) public virtual onlyProxy() returns (bool) + +``` + +These are three operations that normally require the message to come directly from the entity transferring tokens or approving an allowance. +Here we have a proxy version these operations which: + +1. Is modified by `onlyProxy()` so nobody else is allowed to control them. +2. Gets the address that would normally be `msg.sender` as an extra parameter. + +### CalldataInterpreter.sol + +The calldata interpreter is nearly identical to the one above, except that the proxied functions receive a `msg.sender` parameter and there is no need for an allowance for `transfer`. + +```solidity + // transfer (no need for allowance) + if (_func == 2) + + // approve + if (_func == 3) + + // transferFrom + if (_func == 4) +``` + +### Test.js + +There are a few changes between the previous testing code and this one. + +```js +const Cdi = await ethers.getContractFactory("CalldataInterpreter") +const cdi = await Cdi.deploy(token.address) +await cdi.deployed() +await token.setProxy(cdi.address) +``` + +We need to tell the ERC-20 contract which proxy to trust + +```js +console.log("CalldataInterpreter addr:", cdi.address) + +// Need two signers to verify allowances +const signers = await ethers.getSigners() +const signer = signers[0] +const poorSigner = signers[1] +``` + +To check `approve()` and `transferFrom()` we need a second signer. +We call it `poorSigner` because it does not get any of our tokens (it does need to have ETH, of course). + +```js +// Transfer tokens +const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" +const transferTx = +await (await signer.sendTransaction(transferTx)).wait() +``` + +Because the ERC-20 contract trusts the proxy (`cdi`), we don't need an allowance to relay transfers. + +```js +// approval and transferFrom +const approveTx = +await (await signer.sendTransaction(approveTx)).wait() + +const destAddr2 = "0xE1165C689C0c3e9642cA7606F5287e708d846206" + +const transferFromTx = +await (await poorSigner.sendTransaction(transferFromTx)).wait() + +// Check the approve / transferFrom combo was done correctly +expect(await token.balanceOf(destAddr2)).to.equal(255) +``` + +Test the two new functions. +Note that `transferFromTx` requires two address parameters: the giver of the allowance and the receiver. + +## Conclusion + +Both [Optimism](https://medium.com/ethereum-optimism/the-road-to-sub-dollar-transactions-part-2-compression-edition-6bb2890e3e92) and [Arbitrum](https://developer.offchainlabs.com/docs/special_features) are looking for ways to reduce the size of the calldata written to L1 and therefore the cost of transactions. +However, as infrastructure providers looking for generic solutions, our abilities are limited. +As the dapp developer, you have application-specific knowledge, which lets you optimize your calldata much better than we could in a generic solution. +Hopefully, this article helps you find the ideal solution for your needs. + +--- + +## Developers > Tutorials > Smart Contract Security Guidelines + +Follow these high-level recommendations to build more secure smart contracts. + +## Design guidelines + +The design of the contract should be discussed ahead of time, prior to writing any line of code. + +### Documentation and specifications + +Documentation can be written at different levels, and should be updated while implementing the contracts: + +- **A plain English description of the system**, describing what the contracts do and any assumptions on the codebase. +- **Schema and architectural diagrams**, including the contract interactions and the state machine of the system. [Slither printers](https://github.com/crytic/slither/wiki/Printer-documentation) can help to generate these schemas. +- **Thorough code documentation**, the [Natspec format](https://solidity.readthedocs.io/en/develop/natspec-format.html) can be used for Solidity. + +### Onchain vs offchain computation + +- **Keep as much code as you can offchain.** Keep the onchain layer small. Pre-process data with code offchain in such a way that verification onchain is simple. Do you need an ordered list? Sort the list offchain, then only check its order onchain. + +### Upgradeability + +We discussed the different upgradeability solutions in [our blogpost](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). Make a deliberate choice to support upgradeability or not prior to writing any code. The decision will influence how you structure your code. In general, we recommend: + +- **Favoring [contract migration](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) over upgradeability.** Migration systems have many of the same advantages as upgradeable ones, without their drawbacks. +- **Using the data separation pattern over the delegatecallproxy one.** If your project has a clear abstraction separation, upgradeability using data separation will necessitate only a few adjustments. The delegatecallproxy requires EVM expertise and is highly error-prone. +- **Document the migration/upgrade procedure before the deployment.** If you have to react under stress without any guidelines, you will make mistakes. Write the procedure to follow ahead of time. It should include: + - The calls that initiate the new contracts + - Where are stored the keys and how to access them + - How to check the deployment! Develop and test a post-deployment script. + +## Implementation guidelines + +**Strive for simplicity.** Always use the simplest solution that fits your purpose. Any member of your team should be able to understand your solution. + +### Function composition + +The architecture of your codebase should make your code easy to review. Avoid architectural choices that decrease the ability to reason about its correctness. + +- **Split the logic of your system**, either through multiple contracts or by grouping similar functions together (for example, authentication, arithmetic, ...). +- **Write small functions, with a clear purpose.** This will facilitate easier review and allow the testing of individual components. + +### Inheritance + +- **Keep the inheritance manageable.** Inheritance should be used to divide the logic, however, your project should aim to minimize the depth and width of the inheritance tree. +- **Use Slither’s [inheritance printer](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) to check the contracts’ hierarchy.** The inheritance printer will help you review the size of the hierarchy. + +### Events + +- **Log all crucial operations.** Events will help to debug the contract during the development, and monitor it after deployment. + +### Avoid known pitfalls + +- **Be aware of the most common security issues.** There are many online resources to learn about common issues, such as [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Capture the Ether](https://capturetheether.com/), or [Not so smart contracts](https://github.com/crytic/not-so-smart-contracts/). +- **Be aware of the warnings sections in the [Solidity documentation](https://solidity.readthedocs.io/en/latest/).** The warnings sections will inform you about non-obvious behavior of the language. + +### Dependencies + +- **Use well-tested libraries.** Importing code from well-tested libraries will reduce the likelihood that you write buggy code. If you want to write an ERC20 contract, use [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). +- **Use a dependency manager; avoid copy-pasting code.** If you rely on an external source, then you must keep it up-to-date with the original source. + +### Testing and verification + +- **Write thorough unit-tests.** An extensive test suite is crucial to build high-quality software. +- **Write [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) and [Manticore](https://github.com/trailofbits/manticore) custom checks and properties.** Automated tools will help ensure your contract is secure. Review the rest of this guide to learn how to write efficient checks and properties. +- **Use [crytic.io](https://crytic.io/).** Crytic integrates with GitHub, provides access to private Slither detectors, and runs custom property checks from Echidna. + +### Solidity + +- **Favor Solidity 0.5 over 0.4 and 0.6.** In our opinion, Solidity 0.5 is more secure and has better built-in practices than 0.4. Solidity 0.6 has proven too unstable for production and needs time to mature. +- **Use a stable release to compile; use the latest release to check for warnings.** Check that your code has no reported issues with the latest compiler version. However, Solidity has a fast release cycle and has a history of compiler bugs, so we do not recommend the latest version for deployment (see Slither’s [solc version recommendation](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33)). +- **Do not use inline assembly.** Assembly requires EVM expertise. Do not write EVM code if you have not _mastered_ the yellow paper. + +## Deployment guidelines + +Once the contract has been developed and deployed: + +- **Monitor your contracts.** Watch the logs, and be ready to react in case of contract or wallet compromise. +- **Add your contact info to [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** This list helps third-parties contact you if a security flaw is discovered. +- **Secure the wallets of privileged users.** Follow our [best practices](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) if you store keys in hardware wallets. +- **Have a response to incident plan.** Consider that your smart contracts can be compromised. Even if your contracts are free of bugs, an attacker may take control of the contract owner's keys. + +--- + +## Developers > Tutorials > Testing Erc 20 Tokens With Waffle + +In this tutorial you will learn how to: + +- Write tests for smart contracts with Waffle +- Use some popular matchers to test smart contracts with Waffle + +Assumptions: + +- you can get around in a terminal, +- you can create a new `JavaScript` project, +- you've written a few lines of `Solidity` code, +- you've written a few tests in `JavaScript`, +- you’ve used `yarn` or `npm`, JavaScripts’s package installer. + +Again, if any of these are untrue, or you don’t plan to reproduce the code in this article, you can likely still follow along just fine. + +## A few words about Waffle + +[Waffle](https://getwaffle.io) is the most advanced library for writing and testing smart contracts. + +Works with the [JavaScript API](/developers/docs/apis/javascript/) ethers-js. + +You can read more details in the [Waffle documentation](https://ethereum-waffle.readthedocs.io/en/latest/#waffle-documentation) ! + +## The quick tutorial + +First things first, create new `JavaScript` or `TypeScript` project ( I'll use `TS`, but if you use `JS` it's not a problem ) : + +Somewhat like this : + + +package.json + +```json + /**/*.ts'", + "lint:fix": "eslint --fix '/**/*.ts'", + "build": "waffle" + }, + "devDependencies": + } +``` + + + + +tsconfig.json + +```json + + } +``` + + + + +.gitignore + + node_modules + build + + + + +.eslintrc.js + +```js + module.exports = , + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": , + "rules": + } + ], + "@typescript-eslint/indent": [ + "error", + 2, + , + "FunctionDeclaration": , + "FunctionExpression": , + "ImportDeclaration": 1, + "MemberExpression": 1, + "ObjectExpression": 1, + "SwitchCase": 1, + "VariableDeclarator": 1, + "flatTernaryExpressions": false, + "ignoreComments": false, + "outerIIFEBody": 1 + } + ], + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/member-delimiter-style": [ + "error", + , + "singleline": + } + ], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + + ], + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-useless-constructor": "error", + "@typescript-eslint/no-var-requires": "warn", + "accessor-pairs": "error", + "array-bracket-spacing": [ + "error", + "never" + ], + "arrow-spacing": [ + "error", + + ], + "block-spacing": [ + "error", + "always" + ], + "brace-style": [ + "error", + "1tbs", + + ], + "camelcase": "off", + "comma-dangle": [ + "error", + + ], + "comma-spacing": [ + "error", + + ], + "comma-style": [ + "error", + "last" + ], + "computed-property-spacing": [ + "error", + "never" + ], + "constructor-super": "error", + "curly": [ + "error", + "multi-line" + ], + "dot-location": [ + "error", + "property" + ], + "eol-last": "error", + "eqeqeq": [ + "error", + "always", + + ], + "func-call-spacing": [ + "error", + "never" + ], + "generator-star-spacing": [ + "error", + + ], + "handle-callback-err": [ + "error", + "^(err|error)$" + ], + "import/default": "off", + "import/named": "off", + "import/no-extraneous-dependencies": [ + "error", + + ], + "import/no-unresolved": "off", + "indent": "off", + "key-spacing": [ + "error", + + ], + "keyword-spacing": [ + "error", + + ], + "linebreak-style": [ + "error", + "unix" + ], + "lines-between-class-members": [ + "error", + "always", + + ], + "max-len": [ + "error", + + ], + "new-cap": [ + "error", + + ], + "new-parens": "error", + "no-array-constructor": "error", + "no-async-promise-executor": "error", + "no-caller": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-condition": [ + "error", + + ], + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-args": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "error", + "no-extra-parens": [ + "error", + "functions" + ], + "no-fallthrough": "error", + "no-floating-decimal": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-implied-eval": "error", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": [ + "error", + + ], + "no-lone-blocks": "error", + "no-misleading-character-class": "error", + "no-mixed-operators": [ + "error", + + +To get started, install `ethereum-waffle`. In this tutorial, I'll use `yarn`, so to install `ethereum-waffle` run: + +```bash + yarn add --dev ethereum-waffle +``` + +## Step #2: Write a smart contract [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-a-contract) + +In this tutorial, I'll use [ERC20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/ded2b0a55c9c13731963ab7b85a70c8e73504bab/contracts/token/ERC20/ERC20.sol) token from [OpenZeppelin](https://openzeppelin.com). + +So, add `OpenZeppelin` by installing it with `yarn`: + +```bash + yarn add @openzeppelin/contracts -D +``` + +Then create `BasicToken.sol` contract in `src` directory: + +```solidity +pragma solidity ^0.6.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +// Example class - a mock class derived from ERC20 +contract BasicToken is ERC20 +} + +``` + +## Step #3: Compile your smart contract [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#compiling-the-contract) + +To compile your smart contract add the following entry in the `package.json` of your project : + +```json + +} +``` + +Also, add `waffle.json` file in the main directory of your project. + +An example of `waffle.json` configuration: + +```json + +``` + +You can read more about the Waffle configuration [here](https://ethereum-waffle.readthedocs.io/en/latest/configuration.html#configuration). + +Then just run `yarn build` to compile your smart contract. + +You should see that Waffle compiled your contract and placed the resulting JSON output inside the `build` directory. + + +BasicToken.json + +```json + + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + , + , + + ], + "name": "Approval", + "type": "event" + }, + , + , + + ], + "name": "Transfer", + "type": "event" + }, + , + + ], + "name": "allowance", + "outputs": [ + + ], + "stateMutability": "view", + "type": "function" + }, + , + + ], + "name": "approve", + "outputs": [ + + ], + "stateMutability": "nonpayable", + "type": "function" + }, + + ], + "name": "balanceOf", + "outputs": [ + + ], + "stateMutability": "view", + "type": "function" + }, + + ], + "stateMutability": "view", + "type": "function" + }, + , + + ], + "name": "decreaseAllowance", + "outputs": [ + + ], + "stateMutability": "nonpayable", + "type": "function" + }, + , + + ], + "name": "increaseAllowance", + "outputs": [ + + ], + "stateMutability": "nonpayable", + "type": "function" + }, + + ], + "stateMutability": "view", + "type": "function" + }, + + ], + "stateMutability": "view", + "type": "function" + }, + + ], + "stateMutability": "view", + "type": "function" + }, + , + + ], + "name": "transfer", + "outputs": [ + + ], + "stateMutability": "nonpayable", + "type": "function" + }, + , + , + + ], + "name": "transferFrom", + "outputs": [ + + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "evm": , + "object": "60806040523480156200001157600080fd5b506040516200153938038062001539833981810160405260208110156200003757600080fd5b81019080805190602001909291905050506040518060400160405280600581526020017f42617369630000000000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f42534300000000000000000000000000000000000000000000000000000000008152508160039080519060200190620000cc92919062000389565b508060049080519060200190620000e592919062000389565b506012600560006101000a81548160ff021916908360ff16021790555050506200011633826200011d60201b60201c565b5062000438565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415620001c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b620001d560008383620002fb60201b60201c565b620001f1816002546200030060201b62000f2d1790919060201c565b6002819055506200024f816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546200030060201b62000f2d1790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b505050565b6000808284019050838110156200037f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003cc57805160ff1916838001178555620003fd565b82800160010185558215620003fd579182015b82811115620003fc578251825591602001919060010190620003df565b5b5090506200040c919062000410565b5090565b6200043591905b808211156200043157600081600090555060010162000417565b5090565b90565b6110f180620004486000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025f57806370a08231146102c557806395d89b411461031d578063a457c2d7146103a0578063a9059cbb14610406578063dd62ed3e1461046c576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b66104e4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610586565b604051808215151515815260200191505060405180910390f35b61019f6105a4565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105ae565b604051808215151515815260200191505060405180910390f35b610243610687565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061069e565b604051808215151515815260200191505060405180910390f35b610307600480360360208110156102db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610751565b6040518082815260200191505060405180910390f35b610325610799565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036557808201518184015260208101905061034a565b50505050905090810190601f1680156103925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103ec600480360360408110156103b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061083b565b604051808215151515815260200191505060405180910390f35b6104526004803603604081101561041c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610908565b604051808215151515815260200191505060405180910390f35b6104ce6004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610926565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561057c5780601f106105515761010080835404028352916020019161057c565b820191906000526020600020905b81548152906001019060200180831161055f57829003601f168201915b5050505050905090565b600061059a6105936109ad565b84846109b5565b6001905092915050565b6000600254905090565b60006105bb848484610bac565b61067c846105c76109ad565b6106778560405180606001604052806028815260200161102660289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061062d6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b600190509392505050565b6000600560009054906101000a900460ff16905090565b60006107476106ab6109ad565b8461074285600160006106bc6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6109b5565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108315780601f1061080657610100808354040283529160200191610831565b820191906000526020600020905b81548152906001019060200180831161081457829003601f168201915b5050505050905090565b60006108fe6108486109ad565b846108f98560405180606001604052806025815260200161109760259139600160006108726109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b6001905092915050565b600061091c6109156109ad565b8484610bac565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610a3b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806110736024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ac1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610fde6022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061104e6025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610cb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610fbb6023913960400191505060405180910390fd5b610cc3838383610fb5565b610d2e81604051806060016040528060268152602001611000602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610dc1816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610f1a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610edf578082015181840152602081019050610ec4565b50505050905090810190601f168015610f0c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610fab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122081c840f087cef92feccb03fadc678b2708c331896ec5432b5d4c675f27b6d3e664736f6c63430006020033", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x11 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH3 0x1539 CODESIZE SUB DUP1 PUSH3 0x1539 DUP4 CODECOPY DUP2 DUP2 ADD PUSH1 0x40 MSTORE PUSH1 0x20 DUP2 LT ISZERO PUSH3 0x37 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x4261736963000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x3 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x4253430000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x3 SWAP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 PUSH3 0xCC SWAP3 SWAP2 SWAP1 PUSH3 0x389 JUMP JUMPDEST POP DUP1 PUSH1 0x4 SWAP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 PUSH3 0xE5 SWAP3 SWAP2 SWAP1 PUSH3 0x389 JUMP JUMPDEST POP PUSH1 0x12 PUSH1 0x5 PUSH1 0x0 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 PUSH1 0xFF AND MUL OR SWAP1 SSTORE POP POP POP PUSH3 0x116 CALLER DUP3 PUSH3 0x11D PUSH1 0x20 SHL PUSH1 0x20 SHR JUMP JUMPDEST POP PUSH3 0x438 JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH3 0x1C1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x1F DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH32 0x45524332303A206D696E7420746F20746865207A65726F206164647265737300 DUP2 MSTORE POP PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH3 0x1D5 PUSH1 0x0 DUP4 DUP4 PUSH3 0x2FB PUSH1 0x20 SHL PUSH1 0x20 SHR JUMP JUMPDEST PUSH3 0x1F1 DUP2 PUSH1 0x2 SLOAD PUSH3 0x300 PUSH1 0x20 SHL PUSH3 0xF2D OR SWAP1 SWAP2 SWAP1 PUSH1 0x20 SHR JUMP JUMPDEST PUSH1 0x2 DUP2 SWAP1 SSTORE POP PUSH3 0x24F DUP2 PUSH1 0x0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH3 0x300 PUSH1 0x20 SHL PUSH3 0xF2D OR SWAP1 SWAP2 SWAP1 PUSH1 0x20 SHR JUMP JUMPDEST PUSH1 0x0 DUP1 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP4 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 DUP5 ADD SWAP1 POP DUP4 DUP2 LT ISZERO PUSH3 0x37F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x1B DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH32 0x536166654D6174683A206164646974696F6E206F766572666C6F770000000000 DUP2 MSTORE POP PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH1 0x1F LT PUSH3 0x3CC JUMPI DUP1 MLOAD PUSH1 0xFF NOT AND DUP4 DUP1 ADD OR DUP6 SSTORE PUSH3 0x3FD JUMP JUMPDEST DUP3 DUP1 ADD PUSH1 0x1 ADD DUP6 SSTORE DUP3 ISZERO PUSH3 0x3FD JUMPI SWAP2 DUP3 ADD JUMPDEST DUP3 DUP2 GT ISZERO PUSH3 0x3FC JUMPI DUP3 MLOAD DUP3 SSTORE SWAP2 PUSH1 0x20 ADD SWAP2 SWAP1 PUSH1 0x1 ADD SWAP1 PUSH3 0x3DF JUMP JUMPDEST JUMPDEST POP SWAP1 POP PUSH3 0x40C SWAP2 SWAP1 PUSH3 0x410 JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST PUSH3 0x435 SWAP2 SWAP1 JUMPDEST DUP1 DUP3 GT ISZERO PUSH3 0x431 JUMPI PUSH1 0x0 DUP2 PUSH1 0x0 SWAP1 SSTORE POP PUSH1 0x1 ADD PUSH3 0x417 JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST SWAP1 JUMP JUMPDEST PUSH2 0x10F1 DUP1 PUSH3 0x448 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0xA9 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x39509351 GT PUSH2 0x71 JUMPI DUP1 PUSH4 0x39509351 EQ PUSH2 0x25F JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x2C5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x31D JUMPI DUP1 PUSH4 0xA457C2D7 EQ PUSH2 0x3A0 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x406 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x46C JUMPI PUSH2 0xA9 JUMP JUMPDEST DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0xAE JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x131 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x197 JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x1B5 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x23B JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xB6 PUSH2 0x4E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xF6 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xDB JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x123 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x17D PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x147 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x586 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x19F PUSH2 0x5A4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x221 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x1CB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x5AE JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x243 PUSH2 0x687 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x2AB PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x69E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x307 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x751 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x325 PUSH2 0x799 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x365 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x34A JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x392 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x3EC PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x3B6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x83B JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x452 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x41C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x908 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x4CE PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x482 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x926 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 ISZERO PUSH2 0x57C JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x551 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x57C JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x55F JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x59A PUSH2 0x593 PUSH2 0x9AD JUMP JUMPDEST DUP5 DUP5 PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x5BB DUP5 DUP5 DUP5 PUSH2 0xBAC JUMP JUMPDEST PUSH2 0x67C DUP5 PUSH2 0x5C7 PUSH2 0x9AD JUMP JUMPDEST PUSH2 0x677 DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1026 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x0 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 PUSH2 0x62D PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x5 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x747 PUSH2 0x6AB PUSH2 0x9AD JUMP JUMPDEST DUP5 PUSH2 0x742 DUP6 PUSH1 0x1 PUSH1 0x0 PUSH2 0x6BC PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP10 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xF2D SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 ISZERO PUSH2 0x831 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x806 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x831 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x814 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x8FE PUSH2 0x848 PUSH2 0x9AD JUMP JUMPDEST DUP5 PUSH2 0x8F9 DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1097 PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x0 PUSH2 0x872 PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP11 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x91C PUSH2 0x915 PUSH2 0x9AD JUMP JUMPDEST DUP5 DUP5 PUSH2 0xBAC JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 CALLER SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xA3B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x24 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x1073 PUSH1 0x24 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xAC1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x22 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xFDE PUSH1 0x22 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 PUSH1 0x1 PUSH1 0x0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 DUP4 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xC32 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x104E PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xCB8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x23 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xFBB PUSH1 0x23 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0xCC3 DUP4 DUP4 DUP4 PUSH2 0xFB5 JUMP JUMPDEST PUSH2 0xD2E DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x26 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1000 PUSH1 0x26 SWAP2 CODECOPY PUSH1 0x0 DUP1 DUP8 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP PUSH2 0xDC1 DUP2 PUSH1 0x0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xF2D SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH1 0x0 DUP1 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP4 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 DUP4 GT ISZERO DUP3 SWAP1 PUSH2 0xF1A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEDF JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xEC4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0xF0C JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST POP PUSH1 0x0 DUP4 DUP6 SUB SWAP1 POP DUP1 SWAP2 POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 DUP5 ADD SWAP1 POP DUP4 DUP2 LT ISZERO PUSH2 0xFAB JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x1B DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH32 0x536166654D6174683A206164646974696F6E206F766572666C6F770000000000 DUP2 MSTORE POP PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST POP POP POP JUMP INVALID GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220746F20746865207A65726F2061 PUSH5 0x6472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH2 0x7070 PUSH19 0x6F766520746F20746865207A65726F20616464 PUSH19 0x65737345524332303A207472616E7366657220 PUSH2 0x6D6F PUSH22 0x6E7420657863656564732062616C616E636545524332 ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220616D6F756E7420657863656564 PUSH20 0x20616C6C6F77616E636545524332303A20747261 PUSH15 0x736665722066726F6D20746865207A PUSH6 0x726F20616464 PUSH19 0x65737345524332303A20617070726F76652066 PUSH19 0x6F6D20746865207A65726F2061646472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH5 0x6563726561 PUSH20 0x656420616C6C6F77616E63652062656C6F77207A PUSH6 0x726FA2646970 PUSH7 0x735822122081C8 BLOCKHASH CREATE DUP8 0xCE 0xF9 0x2F 0xEC 0xCB SUB STATICCALL 0xDC PUSH8 0x8B2708C331896EC5 NUMBER 0x2B 0x5D 0x4C PUSH8 0x5F27B6D3E664736F PUSH13 0x63430006020033000000000000 ", + "sourceMap": "142:152:5:-:0;;;177:115;8:9:-1;5:2;;;30:1;27;20:12;5:2;177:115:5;;;;;;;;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;177:115:5;;;;;;;;;;;;;;;;2013:141:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2093:4;2085:5;:12;;;;;;;;;;;;:::i;:::-;;2117:6;2107:7;:16;;;;;;;;;;;;:::i;:::-;;2145:2;2133:9;;:14;;;;;;;;;;;;;;;;;;2013:141;;252:33:5::1;258:10;270:14;252:5;;;:33;;:::i;:::-;177:115:::0;142:152;;7835:370:2;7937:1;7918:21;;:7;:21;;;;7910:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7986:49;8015:1;8019:7;8028:6;7986:20;;;:49;;:::i;:::-;8061:24;8078:6;8061:12;;:16;;;;;;:24;;;;:::i;:::-;8046:12;:39;;;;8116:30;8139:6;8116:9;:18;8126:7;8116:18;;;;;;;;;;;;;;;;:22;;;;;;:30;;;;:::i;:::-;8095:9;:18;8105:7;8095:18;;;;;;;;;;;;;;;:51;;;;8182:7;8161:37;;8178:1;8161:37;;;8191:6;8161:37;;;;;;;;;;;;;;;;;;7835:370;;:::o;10695:92::-;;;;:::o;874:176:1:-;932:7;951:9;967:1;963;:5;951:17;;991:1;986;:6;;978:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;1035:8;;;874:176;;;;:::o;142:152:5:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;" + }, + "deployedBytecode": , + "object": "608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025f57806370a08231146102c557806395d89b411461031d578063a457c2d7146103a0578063a9059cbb14610406578063dd62ed3e1461046c576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b66104e4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610586565b604051808215151515815260200191505060405180910390f35b61019f6105a4565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105ae565b604051808215151515815260200191505060405180910390f35b610243610687565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061069e565b604051808215151515815260200191505060405180910390f35b610307600480360360208110156102db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610751565b6040518082815260200191505060405180910390f35b610325610799565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036557808201518184015260208101905061034a565b50505050905090810190601f1680156103925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103ec600480360360408110156103b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061083b565b604051808215151515815260200191505060405180910390f35b6104526004803603604081101561041c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610908565b604051808215151515815260200191505060405180910390f35b6104ce6004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610926565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561057c5780601f106105515761010080835404028352916020019161057c565b820191906000526020600020905b81548152906001019060200180831161055f57829003601f168201915b5050505050905090565b600061059a6105936109ad565b84846109b5565b6001905092915050565b6000600254905090565b60006105bb848484610bac565b61067c846105c76109ad565b6106778560405180606001604052806028815260200161102660289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061062d6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b600190509392505050565b6000600560009054906101000a900460ff16905090565b60006107476106ab6109ad565b8461074285600160006106bc6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6109b5565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108315780601f1061080657610100808354040283529160200191610831565b820191906000526020600020905b81548152906001019060200180831161081457829003601f168201915b5050505050905090565b60006108fe6108486109ad565b846108f98560405180606001604052806025815260200161109760259139600160006108726109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b6001905092915050565b600061091c6109156109ad565b8484610bac565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610a3b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806110736024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ac1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610fde6022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061104e6025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610cb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610fbb6023913960400191505060405180910390fd5b610cc3838383610fb5565b610d2e81604051806060016040528060268152602001611000602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610dc1816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610f1a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610edf578082015181840152602081019050610ec4565b50505050905090810190601f168015610f0c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610fab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122081c840f087cef92feccb03fadc678b2708c331896ec5432b5d4c675f27b6d3e664736f6c63430006020033", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0xA9 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x39509351 GT PUSH2 0x71 JUMPI DUP1 PUSH4 0x39509351 EQ PUSH2 0x25F JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x2C5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x31D JUMPI DUP1 PUSH4 0xA457C2D7 EQ PUSH2 0x3A0 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x406 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x46C JUMPI PUSH2 0xA9 JUMP JUMPDEST DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0xAE JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x131 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x197 JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x1B5 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x23B JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xB6 PUSH2 0x4E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xF6 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xDB JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x123 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x17D PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x147 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x586 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x19F PUSH2 0x5A4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x221 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x1CB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x5AE JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x243 PUSH2 0x687 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x2AB PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x69E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x307 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x751 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x325 PUSH2 0x799 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x365 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x34A JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x392 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x3EC PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x3B6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x83B JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x452 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x41C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x908 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 ISZERO ISZERO ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x4CE PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x482 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x926 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 ISZERO PUSH2 0x57C JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x551 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x57C JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x55F JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x59A PUSH2 0x593 PUSH2 0x9AD JUMP JUMPDEST DUP5 DUP5 PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x2 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x5BB DUP5 DUP5 DUP5 PUSH2 0xBAC JUMP JUMPDEST PUSH2 0x67C DUP5 PUSH2 0x5C7 PUSH2 0x9AD JUMP JUMPDEST PUSH2 0x677 DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1026 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x0 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 PUSH2 0x62D PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x5 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x747 PUSH2 0x6AB PUSH2 0x9AD JUMP JUMPDEST DUP5 PUSH2 0x742 DUP6 PUSH1 0x1 PUSH1 0x0 PUSH2 0x6BC PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP10 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xF2D SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH1 0x1 DUP2 PUSH1 0x1 AND ISZERO PUSH2 0x100 MUL SUB AND PUSH1 0x2 SWAP1 DIV DUP1 ISZERO PUSH2 0x831 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x806 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x831 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x814 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x8FE PUSH2 0x848 PUSH2 0x9AD JUMP JUMPDEST DUP5 PUSH2 0x8F9 DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1097 PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x0 PUSH2 0x872 PUSH2 0x9AD JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP11 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH2 0x9B5 JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x91C PUSH2 0x915 PUSH2 0x9AD JUMP JUMPDEST DUP5 DUP5 PUSH2 0xBAC JUMP JUMPDEST PUSH1 0x1 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 CALLER SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xA3B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x24 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x1073 PUSH1 0x24 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xAC1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x22 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xFDE PUSH1 0x22 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 PUSH1 0x1 PUSH1 0x0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 DUP4 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xC32 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x104E PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xCB8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x23 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xFBB PUSH1 0x23 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0xCC3 DUP4 DUP4 DUP4 PUSH2 0xFB5 JUMP JUMPDEST PUSH2 0xD2E DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x26 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x1000 PUSH1 0x26 SWAP2 CODECOPY PUSH1 0x0 DUP1 DUP8 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xE6D SWAP1 SWAP3 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH1 0x0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP PUSH2 0xDC1 DUP2 PUSH1 0x0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SLOAD PUSH2 0xF2D SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST PUSH1 0x0 DUP1 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP4 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 DUP4 GT ISZERO DUP3 SWAP1 PUSH2 0xF1A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEDF JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xEC4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0xF0C JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST POP PUSH1 0x0 DUP4 DUP6 SUB SWAP1 POP DUP1 SWAP2 POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 DUP5 ADD SWAP1 POP DUP4 DUP2 LT ISZERO PUSH2 0xFAB JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x1B DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH32 0x536166654D6174683A206164646974696F6E206F766572666C6F770000000000 DUP2 MSTORE POP PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST POP POP POP JUMP INVALID GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220746F20746865207A65726F2061 PUSH5 0x6472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH2 0x7070 PUSH19 0x6F766520746F20746865207A65726F20616464 PUSH19 0x65737345524332303A207472616E7366657220 PUSH2 0x6D6F PUSH22 0x6E7420657863656564732062616C616E636545524332 ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220616D6F756E7420657863656564 PUSH20 0x20616C6C6F77616E636545524332303A20747261 PUSH15 0x736665722066726F6D20746865207A PUSH6 0x726F20616464 PUSH19 0x65737345524332303A20617070726F76652066 PUSH19 0x6F6D20746865207A65726F2061646472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH5 0x6563726561 PUSH20 0x656420616C6C6F77616E63652062656C6F77207A PUSH6 0x726FA2646970 PUSH7 0x735822122081C8 BLOCKHASH CREATE DUP8 0xCE 0xF9 0x2F 0xEC 0xCB SUB STATICCALL 0xDC PUSH8 0x8B2708C331896EC5 NUMBER 0x2B 0x5D 0x4C PUSH8 0x5F27B6D3E664736F PUSH13 0x63430006020033000000000000 ", + "sourceMap": "142:152:5:-:0;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;142:152:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2219:81:2;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;2219:81:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4255:166;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;4255:166:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3262:98;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4881:317;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;4881:317:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3121:81;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;5593:215;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;5593:215:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3418:117;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3418:117:2;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2413:85;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;2413:85:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6295:266;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;6295:266:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3738:172;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3738:172:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3968:149;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3968:149:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2219:81;2256:13;2288:5;2281:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2219:81;:::o;4255:166::-;4338:4;4354:39;4363:12;:10;:12::i;:::-;4377:7;4386:6;4354:8;:39::i;:::-;4410:4;4403:11;;4255:166;;;;:::o;3262:98::-;3315:7;3341:12;;3334:19;;3262:98;:::o;4881:317::-;4987:4;5003:36;5013:6;5021:9;5032:6;5003:9;:36::i;:::-;5049:121;5058:6;5066:12;:10;:12::i;:::-;5080:89;5118:6;5080:89;;;;;;;;;;;;;;;;;:11;:19;5092:6;5080:19;;;;;;;;;;;;;;;:33;5100:12;:10;:12::i;:::-;5080:33;;;;;;;;;;;;;;;;:37;;:89;;;;;:::i;:::-;5049:8;:121::i;:::-;5187:4;5180:11;;4881:317;;;;;:::o;3121:81::-;3162:5;3186:9;;;;;;;;;;;3179:16;;3121:81;:::o;5593:215::-;5681:4;5697:83;5706:12;:10;:12::i;:::-;5720:7;5729:50;5768:10;5729:11;:25;5741:12;:10;:12::i;:::-;5729:25;;;;;;;;;;;;;;;:34;5755:7;5729:34;;;;;;;;;;;;;;;;:38;;:50;;;;:::i;:::-;5697:8;:83::i;:::-;5797:4;5790:11;;5593:215;;;;:::o;3418:117::-;3484:7;3510:9;:18;3520:7;3510:18;;;;;;;;;;;;;;;;3503:25;;3418:117;;;:::o;2413:85::-;2452:13;2484:7;2477:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2413:85;:::o;6295:266::-;6388:4;6404:129;6413:12;:10;:12::i;:::-;6427:7;6436:96;6475:15;6436:96;;;;;;;;;;;;;;;;;:11;:25;6448:12;:10;:12::i;:::-;6436:25;;;;;;;;;;;;;;;:34;6462:7;6436:34;;;;;;;;;;;;;;;;:38;;:96;;;;;:::i;:::-;6404:8;:129::i;:::-;6550:4;6543:11;;6295:266;;;;:::o;3738:172::-;3824:4;3840:42;3850:12;:10;:12::i;:::-;3864:9;3875:6;3840:9;:42::i;:::-;3899:4;3892:11;;3738:172;;;;:::o;3968:149::-;4057:7;4083:11;:18;4095:5;4083:18;;;;;;;;;;;;;;;:27;4102:7;4083:27;;;;;;;;;;;;;;;;4076:34;;3968:149;;;;:::o;590:104:0:-;643:15;677:10;670:17;;590:104;:::o;9357:340:2:-;9475:1;9458:19;;:5;:19;;;;9450:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9555:1;9536:21;;:7;:21;;;;9528:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9637:6;9607:11;:18;9619:5;9607:18;;;;;;;;;;;;;;;:27;9626:7;9607:27;;;;;;;;;;;;;;;:36;;;;9674:7;9658:32;;9667:5;9658:32;;;9683:6;9658:32;;;;;;;;;;;;;;;;;;9357:340;;;:::o;7035:530::-;7158:1;7140:20;;:6;:20;;;;7132:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7241:1;7220:23;;:9;:23;;;;7212:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7294:47;7315:6;7323:9;7334:6;7294:20;:47::i;:::-;7372:71;7394:6;7372:71;;;;;;;;;;;;;;;;;:9;:17;7382:6;7372:17;;;;;;;;;;;;;;;;:21;;:71;;;;;:::i;:::-;7352:9;:17;7362:6;7352:17;;;;;;;;;;;;;;;:91;;;;7476:32;7501:6;7476:9;:20;7486:9;7476:20;;;;;;;;;;;;;;;;:24;;:32;;;;:::i;:::-;7453:9;:20;7463:9;7453:20;;;;;;;;;;;;;;;:55;;;;7540:9;7523:35;;7532:6;7523:35;;;7551:6;7523:35;;;;;;;;;;;;;;;;;;7035:530;;;:::o;1746:187:1:-;1832:7;1864:1;1859;:6;;1867:12;1851:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1851:29:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1890:9;1906:1;1902;:5;1890:17;;1925:1;1918:8;;;1746:187;;;;;:::o;874:176::-;932:7;951:9;967:1;963;:5;951:17;;991:1;986;:6;;978:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;1035:8;;;874:176;;;;:::o;10695:92:2:-;;;;:::o" + } + }, + "bytecode": "60806040523480156200001157600080fd5b506040516200153938038062001539833981810160405260208110156200003757600080fd5b81019080805190602001909291905050506040518060400160405280600581526020017f42617369630000000000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f42534300000000000000000000000000000000000000000000000000000000008152508160039080519060200190620000cc92919062000389565b508060049080519060200190620000e592919062000389565b506012600560006101000a81548160ff021916908360ff16021790555050506200011633826200011d60201b60201c565b5062000438565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415620001c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b620001d560008383620002fb60201b60201c565b620001f1816002546200030060201b62000f2d1790919060201c565b6002819055506200024f816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546200030060201b62000f2d1790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b505050565b6000808284019050838110156200037f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003cc57805160ff1916838001178555620003fd565b82800160010185558215620003fd579182015b82811115620003fc578251825591602001919060010190620003df565b5b5090506200040c919062000410565b5090565b6200043591905b808211156200043157600081600090555060010162000417565b5090565b90565b6110f180620004486000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025f57806370a08231146102c557806395d89b411461031d578063a457c2d7146103a0578063a9059cbb14610406578063dd62ed3e1461046c576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b66104e4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610586565b604051808215151515815260200191505060405180910390f35b61019f6105a4565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105ae565b604051808215151515815260200191505060405180910390f35b610243610687565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061069e565b604051808215151515815260200191505060405180910390f35b610307600480360360208110156102db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610751565b6040518082815260200191505060405180910390f35b610325610799565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036557808201518184015260208101905061034a565b50505050905090810190601f1680156103925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103ec600480360360408110156103b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061083b565b604051808215151515815260200191505060405180910390f35b6104526004803603604081101561041c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610908565b604051808215151515815260200191505060405180910390f35b6104ce6004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610926565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561057c5780601f106105515761010080835404028352916020019161057c565b820191906000526020600020905b81548152906001019060200180831161055f57829003601f168201915b5050505050905090565b600061059a6105936109ad565b84846109b5565b6001905092915050565b6000600254905090565b60006105bb848484610bac565b61067c846105c76109ad565b6106778560405180606001604052806028815260200161102660289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061062d6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b600190509392505050565b6000600560009054906101000a900460ff16905090565b60006107476106ab6109ad565b8461074285600160006106bc6109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6109b5565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108315780601f1061080657610100808354040283529160200191610831565b820191906000526020600020905b81548152906001019060200180831161081457829003601f168201915b5050505050905090565b60006108fe6108486109ad565b846108f98560405180606001604052806025815260200161109760259139600160006108726109ad565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6109b5565b6001905092915050565b600061091c6109156109ad565b8484610bac565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610a3b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806110736024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ac1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610fde6022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061104e6025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610cb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610fbb6023913960400191505060405180910390fd5b610cc3838383610fb5565b610d2e81604051806060016040528060268152602001611000602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e6d9092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610dc1816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610f2d90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610f1a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610edf578082015181840152602081019050610ec4565b50505050905090810190601f168015610f0c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610fab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122081c840f087cef92feccb03fadc678b2708c331896ec5432b5d4c675f27b6d3e664736f6c63430006020033" + } +``` + + + +## Step #4: Test your smart contract [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) + +### Step #4.1 Install necessary dependencies [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) + +After we have successfully authored a Smart Contract we can test it. We will use `Waffle` to do it. + +Tests in `Waffle` are written using `Mocha` alongside with `Chai`. We can use a different test environment, but `Waffle` matchers only work with `Chai`. + +So, we need to add `Chai` to our dependencies : + +```bash + yarn add --dev mocha chai +``` + +### Step #4.2 Create test file [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) + +To write our test we need to create `BasicToken.test.ts` file in our test directory. + +```ts + +use(solidity) + +describe("BasicToken", () => ) +}) +``` + +So, we use `deployContract` method from `Waffle` to deploy our token. As arguments, we should pass `wallet`, the compiled json file of our contract and default balance. + +`Waffle` also allows us to create a `wallet`, which makes it very easy to deploy a contract. + +You can read more about `wallet` [here](https://ethereum-waffle.readthedocs.io/en/latest/basic-testing.html?highlight=wallet#getting-wallets) and you can read more about the deploying function [here](https://ethereum-waffle.readthedocs.io/en/latest/basic-testing.html?highlight=wallet#deploying-contracts). + +Let's write a simple test to check balance of our wallet. Since we submitted the value 1000 during the deployment our contract, the balance of our wallet must be 1000 tokens, which we can check in the first test. + +```ts +it("Assigns initial balance", async () => ) +``` + +To run the test use `yarn test` + +### Step #4.3 Emitting events [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/matchers.html?highlight=changeBalance#emitting-events) + +In this tutorial, I want to show you the most useful matchers of `Waffle`, so let's start with the first one. + +`Waffle` allows us to test what events where emitted. + +In this tutorial, I'll test the `transfer` method of our contract. + +In this test, I'll make a transfer from one wallet to another and check whether the `Transfer` event was called. + +```ts +it("Transfer emits event", async () => ) +``` + +Also, a big advantage of this matcher is that we can check which arguments this event was called with by adding `withArgs` to our test. + +This will allow us to be sure that our function is being called correctly! + +### Step #4.4 Revert with message [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/matchers.html?highlight=changeBalance#revert-with-message) + +`Waffle` allows us to test what message it was reverted with. + +We will use `revertedWith` matcher in our test to check it. + +We can write a test in which we will perform a transfer for an amount greater than we have on our wallet. +And then we'll check if the transaction reverted with the exact message! + +```ts +it("Can not transfer above the amount", async () => ) +``` + +### Step #4.5 Change-token-balance [Link to doc](https://ethereum-waffle.readthedocs.io/en/latest/matchers.html?highlight=changeBalance#change-balance) + +`Waffle` allows us to check for changes in the balances of the wallets! + +We can use the `changeTokenBalance` matcher to check the balance change or the `changeTokenBalances` for a multiple account. + +The matcher can accept `numbers`, `strings` and `BigNumbers` as a balance change, while the address should be specified as a wallet or a contract. + +Let's write the next test: + +```ts +it("Send transaction changes receiver balance", async () => ) + ).to.changeBalance(walletTo, 200) +}) +``` + +The above is a test for a single wallet. + +And the next one for multiple wallets: + +```ts +it("Send transaction changes sender and receiver balances", async () => ) + ).to.changeBalances([wallet, walletTo], [-200, 200]) +}) +``` + +The transaction is expected to be passed as a callback (we need to check the balance before the call) or as a transaction response. + +## Congratulations + +**Congratulations! You've made it through my tutorial. You've taken your first big step towards testing smart contracts with Waffle.** + +**Code from this tutorial you can be find [here](https://github.com/VladStarostenko/tutorial-for-ethereum-org-website).** + +**More documentation about `Waffle` available [here](https://getwaffle.io).** + +--- + +## Developers > Tutorials > The Graph Fixing Web3 Data Querying + +This time we will take a closer look at The Graph which essentially became part of the standard stack for developing dapps in the last year. Let's first see how we would do things the traditional way... + +## Without The Graph... + +So let's go with a simple example for illustration purposes. We all like games, so imagine a simple game with users placing bets: + +```solidity +pragma solidity 0.7.1; + +contract Game (''); + require(success, "Transfer failed"); + totalGamesPlayerWon++; + } else + + emit BetPlaced(msg.sender, msg.value, hasWon); + } +} +``` + +Now let's say in our dapp, we want to display total bets, the total games lost/won and also update it whenever someone plays again. The approach would be: + +1. Fetch `totalGamesPlayerWon`. +2. Fetch `totalGamesPlayerLost`. +3. Subscribe to `BetPlaced` events. + +We can listen to the [event in Web3](https://docs.web3js.org/api/web3/class/Contract#events) as shown on the right, but it requires handling quite a few cases. + +```solidity +GameContract.events.BetPlaced(, function(error, event) ) +.on('data', function(event) ) +.on('changed', function(event) ) +.on('error', function(error, receipt) ); +``` + +Now this is still somewhat fine for our simple example. But let's say we want to now display the amounts of bets lost/won only for the current player. Well we're out of luck, you better deploy a new contract that stores those values and fetch them. And now imagine a much more complicated smart contract and dapp, things can get messy quickly. + +![One Does Not Simply Query](./one-does-not-simply-query.jpg) + +You can see how this is not optimal: + +- Doesn't work for already deployed contracts. +- Extra gas costs for storing those values. +- Requires another call to fetch the data for an Ethereum node. + +![Thats not good enough](./not-good-enough.jpg) + +Now let's look at a better solution. + +## Let me introduce you to GraphQL + +First let's talk about GraphQL, originally designed and implemented by Facebook. You might be familiar with the traditional REST API model. Now imagine instead you could write a query for exactly the data that you wanted: + +![GraphQL API vs. REST API](./graphql.jpg) + +![](./graphql-query.gif) + +The two images pretty much capture the essence of GraphQL. With the query on the right we can define exactly what data we want, so there we get everything in one request and nothing more than exactly what we need. A GraphQL server handles the fetching of all data required, so it is incredibly easy for the frontend consumer side to use. [This is a nice explanation](https://www.apollographql.com/blog/graphql-explained) of how exactly the server handles a query if you're interested. + +Now with that knowledge, let's finally jump into blockchain space and The Graph. + +## What is The Graph? + +A blockchain is a decentralized database, but in contrast to what's usually the case, we don't have a query language for this database. Solutions for retrieving data are painful or completely impossible. The Graph is a decentralized protocol for indexing and querying blockchain data. And you might have guessed it, it's using GraphQL as query language. + +![The Graph](./thegraph.png) + +Examples are always the best to understand something, so let's use The Graph for our GameContract example. + +## How to create a Subgraph + +The definition for how to index data is called subgraph. It requires three components: + +1. Manifest (`subgraph.yaml`) +2. Schema (`schema.graphql`) +3. Mapping (`mapping.ts`) + +### Manifest (`subgraph.yaml`) + +The manifest is our configuration file and defines: + +- which smart contracts to index (address, network, ABI...) +- which events to listen to +- other things to listen to like function calls or blocks +- the mapping functions being called (see `mapping.ts` below) + +You can define multiple contracts and handlers here. A typical setup would have a subgraph folder inside the Hardhat project with its own repository. Then you can easily reference the ABI. + +For convenience reasons you also might want to use a template tool like mustache. Then you create a `subgraph.template.yaml` and insert the addresses based on the latest deployments. For a more advanced example setup, see for example the [Aave subgraph repo](https://github.com/aave/aave-protocol/tree/master/thegraph). + +And the full documentation can be seen [here](https://thegraph.com/docs/en/developing/creating-a-subgraph/#the-subgraph-manifest). + +```yaml +specVersion: 0.0.1 +description: Placing Bets on Ethereum +repository: - GitHub link - +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum/contract + name: GameContract + network: mainnet + source: + address: '0x2E6454...cf77eC' + abi: GameContract + startBlock: 6175244 + mapping: + kind: ethereum/events + apiVersion: 0.0.1 + language: wasm/assemblyscript + entities: + - GameContract + abis: + - name: GameContract + file: ../build/contracts/GameContract.json + eventHandlers: + - event: PlacedBet(address,uint256,bool) + handler: handleNewBet + file: ./src/mapping.ts +``` + +### Schema (`schema.graphql`) + +The schema is the GraphQL data definition. It will allow you to define which entities exist and their types. Supported types from The Graph are + +- Bytes +- ID +- String +- Boolean +- Int +- BigInt +- BigDecimal + +You can also use entities as type to define relationships. In our example we define a 1-to-many relationship from player to bets. The ! means the value can't be empty. The full documentation can be seen [here](https://thegraph.com/docs/en/developing/creating-a-subgraph/#the-subgraph-manifest). + +```graphql +type Bet @entity + +type Player @entity +``` + +### Mapping (`mapping.ts`) + +The mapping file in The Graph defines our functions that transform incoming events into entities. It is written in AssemblyScript, a subset of Typescript. This means it can be compiled into WASM (WebAssembly) for more efficient and portable execution of the mapping. + +You will need to define each function named in the `subgraph.yaml` file, so in our case we need only one: `handleNewBet`. We first try to load the Player entity from the sender address as id. If it doesn't exist, we create a new entity and fill it with starting values. + +Then we create a new Bet entity. The id for this will be `event.transaction.hash.toHex() + "-" + event.logIndex.toString()` ensuring always a unique value. Using only the hash isn't enough as someone might be calling the placeBet function several times in one transaction via a smart contract. + +Lastly we can update the Player entity with all the data. Arrays cannot be pushed to directly, but need to be updated as shown here. We use the id to reference the bet. And `.save()` is required at the end to store an entity. + +The full documentation can be seen here: https://thegraph.com/docs/en/developing/creating-a-subgraph/#writing-mappings. You can also add logging output to the mapping file, see [here](https://thegraph.com/docs/en/subgraphs/developing/creating/graph-ts/api/#api-reference). + +```typescript + +export function handleNewBet(event: PlacedBet): void + + let bet = new Bet( + event.transaction.hash.toHex() + "-" + event.logIndex.toString() + ) + bet.player = player.id + bet.playerHasWon = event.params.hasWon + bet.time = event.block.timestamp + bet.save() + + player.totalPlayedCount++ + if (event.params.hasWon) else + + // update array like this + let bets = player.bets + bets.push(bet.id) + player.bets = bets + + player.save() +} +``` + +## Using it in the Frontend + +Using something like Apollo Boost, you can easily integrate The Graph in your React dapp (or Apollo-Vue). Especially when using React hooks and Apollo, fetching data is as simple as writing a single GraphQL query in your component. A typical setup might look like this: + +```javascript +// See all subgraphs: https://thegraph.com/explorer/ +const client = new ApolloClient(}", +}) + +ReactDOM.render( + + + , + document.getElementById("root") +) +``` + +And now we can write for example a query like this. This will fetch us + +- how many times current user has won +- how many times current user has lost +- a list of timestamps with all his previous bets + +All in one single request to the GraphQL server. + +```javascript +const myGraphQlQuery = gql` + players(where: ) + } +` + +const = useQuery(myGraphQlQuery) + +React.useEffect(() => ) + } +}, [loading, error, data]) +``` + +![Magic](./magic.jpg) + +But we're missing one last piece of the puzzle and that's the server. You can either run it yourself or use the hosted service. + +## The Graph server + +### Graph Explorer: The hosted service + +The easiest way is to use the hosted service. Follow the instructions [here](https://thegraph.com/docs/en/deploying/deploying-a-subgraph-to-hosted/) to deploy a subgraph. For many projects you can actually find existing subgraphs in the [explorer](https://thegraph.com/explorer/). + +![The Graph-Explorer](./thegraph-explorer.png) + +### Running your own node + +Alternatively you can run your own node. Docs [here](https://github.com/graphprotocol/graph-node#quick-start). One reason to do this might be using a network that's not supported by the hosted service. The currently supported networks [can be found here](https://thegraph.com/docs/en/developing/supported-networks/). + +## The decentralized future + +GraphQL supports streams as well for newly incoming events. These are supported on the graph through [Substreams](https://thegraph.com/docs/en/substreams/) which are currently in open beta. + +In [2021](https://thegraph.com/blog/mainnet-migration/) The Graph began its transition to a decentralized indexing network. You can read more about the architecture of this decentralized indexing network [here](https://thegraph.com/docs/en/network/explorer/). + +Two key aspects are: + +1. Users pay the indexers for queries. +2. Indexers stake Graph Tokens (GRT). + +--- + +## Developers > Tutorials > Token Integration Checklist + +Follow this checklist when interacting with arbitrary tokens. Make sure you understand the risks associated with each item, and justify any exceptions to these rules. + +For convenience, all Slither [utilities](https://github.com/crytic/slither#tools) can be run directly on a token address, such as: + +[Using Slither tutorial](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) + +```bash +slither-check-erc 0xdac17f958d2ee523a2206206994597c13d831ec7 TetherToken +``` + +To follow this checklist, you'll want to have this output from Slither for the token: + +```bash +- slither-check-erc [target] [contractName] [optional: --erc ERC_NUMBER] +- slither [target] --print human-summary +- slither [target] --print contract-summary +- slither-prop . --contract ContractName # requires configuration, and use of Echidna and Manticore +``` + +## General considerations + +- **The contract has a security review.** Avoid interacting with contracts that lack a security review. Check the length of the assessment (aka “level of effort”), the reputation of the security firm, and the number and severity of the findings. +- **You have contacted the developers.** You may need to alert their team to an incident. Look for appropriate contacts on [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts). +- **They have a security mailing list for critical announcements.** Their team should advise users (like you!) when critical issues are found or when upgrades occur. + +## ERC conformity + +Slither includes a utility, [slither-check-erc](https://github.com/crytic/slither/wiki/ERC-Conformance), that reviews the conformance of a token to many related ERC standards. Use slither-check-erc to review that: + +- **Transfer and transferFrom return a boolean.** Several tokens do not return a boolean on these functions. As a result, their calls in the contract might fail. +- **The name, decimals, and symbol functions are present if used.** These functions are optional in the ERC20 standard and might not be present. +- **Decimals returns a uint8.** Several tokens incorrectly return a uint256. If this is the case, ensure the value returned is below 255. +- **The token mitigates the known [ERC20 race condition](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729).** The ERC20 standard has a known ERC20 race condition that must be mitigated to prevent attackers from stealing tokens. +- **The token is not an ERC777 token and has no external function call in transfer and transferFrom.** External calls in the transfer functions can lead to reentrancies. + +Slither includes a utility, [slither-prop](https://github.com/crytic/slither/wiki/Property-generation), that generates unit tests and security properties that can discover many common ERC flaws. Use slither-prop to review that: + +- **The contract passes all unit tests and security properties from slither-prop.** Run the generated unit tests, then check the properties with [Echidna](https://github.com/crytic/echidna) and [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html). + +Finally, there are certain characteristics that are difficult to identify automatically. Review for these conditions by hand: + +- **Transfer and transferFrom should not take a fee.** Deflationary tokens can lead to unexpected behavior. +- **Potential interest earned from the token is taken into account.** Some tokens distribute interest to token holders. This interest might be trapped in the contract if not taken into account. + +## Contract composition + +- **The contract avoids unneeded complexity.** The token should be a simple contract; a token with complex code requires a higher standard of review. Use Slither’s [human-summary printer](https://github.com/crytic/slither/wiki/Printer-documentation#human-summary) to identify complex code. +- **The contract uses SafeMath.** Contracts that do not use SafeMath require a higher standard of review. Inspect the contract by hand for SafeMath usage. +- **The contract has only a few non–token-related functions.** Non–token-related functions increase the likelihood of an issue in the contract. Use Slither’s [contract-summary printer](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary) to broadly review the code used in the contract. +- **The token only has one address.** Tokens with multiple entry points for balance updates can break internal bookkeeping based on the address (e.g. `balances[token_address][msg.sender]` might not reflect the actual balance). + +## Owner privileges + +- **The token is not upgradeable.** Upgradeable contracts might change their rules over time. Use Slither’s [human-summary printer](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary) to determine if the contract is upgradeable. +- **The owner has limited minting capabilities.** Malicious or compromised owners can abuse minting capabilities. Use Slither’s [human-summary printer](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary) to review minting capabilities, and consider manually reviewing the code. +- **The token is not pausable.** Malicious or compromised owners can trap contracts relying on pausable tokens. Identify pauseable code by hand. +- **The owner cannot blacklist the contract.** Malicious or compromised owners can trap contracts relying on tokens with a blacklist. Identify blacklisting features by hand. +- **The team behind the token is known and can be held responsible for abuse.** Contracts with anonymous development teams, or that reside in legal shelters should require a higher standard of review. + +## Token scarcity + +Reviews for issues of token scarcity requires manual review. Check for these conditions: + +- **No user owns most of the supply.** If a few users own most of the tokens, they can influence operations based on the token's repartition. +- **The total supply is sufficient.** Tokens with a low total supply can be easily manipulated. +- **The tokens are located in more than a few exchanges.** If all the tokens are in one exchange, a compromise of the exchange can compromise the contract relying on the token. +- **Users understand the associated risks of large funds or flash loans.** Contracts relying on the token balance must carefully take in consideration attackers with large funds or attacks through flash loans. +- **The token does not allow flash minting**. Flash minting can lead to substantial swings in the balance and the total supply, which neccessitate strict and comprehensive overflow checks in the operation of the token. + +--- + +## Developers > Tutorials > Transfers And Approval Of Erc 20 Tokens From A Solidity Smart Contract + +In the previous tutorial we studied [the anatomy of an ERC-20 token in Solidity](/developers/tutorials/understand-the-erc-20-token-smart-contract/) on the Ethereum blockchain. In this article we’ll see how we can use a smart contract to interact with a token using the Solidity language. + +For this smart contract, we’ll create a real dummy decentralized exchange where a user can trade ether for our newly deployed [ERC-20 token](/developers/docs/standards/tokens/erc-20/). + +For this tutorial we’ll use the code we wrote in the previous tutorial as a base. Our DEX will instantiate an instance of the contract in its constructor and perform the operations of: + +- exchanging tokens to ether +- exchanging ether to tokens + +We’ll start our Decentralized exchange code by adding our simple ERC20 codebase: + +```solidity +pragma solidity ^0.8.0; + +interface IERC20 + + +contract ERC20Basic is IERC20 + + function totalSupply() public override view returns (uint256) + + function balanceOf(address tokenOwner) public override view returns (uint256) + + function transfer(address receiver, uint256 numTokens) public override returns (bool) +``` + +If everything works you should see 2 events (a `Transfer` and `Sold`) in the transaction and your token balance and ether balance updated. + +![Two events in the transaction: Transfer and Sold](./transfer-and-sold-events.png) + + + +From this tutorial we saw how to check the balance and allowance of an ERC-20 token and also how to call `Transfer` and `TransferFrom` of an ERC20 smart contract using the interface. + +Once you make a transaction we have a JavaScript tutorial to [wait and get details about the transactions](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/) that were made to your contract and a [tutorial to decode events generated by token transfers or any other events](https://ethereumdev.io/how-to-decode-event-logs-in-javascript-using-abi-decoder/) as long as you have the ABI. + +Here is the complete code for the tutorial: + +```solidity +pragma solidity ^0.8.0; + +interface IERC20 + + +contract ERC20Basic is IERC20 + + function totalSupply() public override view returns (uint256) + + function balanceOf(address tokenOwner) public override view returns (uint256) + + function transfer(address receiver, uint256 numTokens) public override returns (bool) + +} +``` + +--- + +## Developers > Tutorials > Understand The Erc 20 Token Smart Contract + +One of the most significant [smart contract standards](/developers/docs/standards/) on Ethereum is known as [ERC-20](/developers/docs/standards/tokens/erc-20/), which has emerged as the technical standard used for all smart contracts on the Ethereum blockchain for fungible token implementations. + +ERC-20 defines a common list of rules that all fungible Ethereum tokens should adhere to. Consequently, this token standard empowers developers of all types to accurately predict how new tokens will function within the larger Ethereum system. This simplifies and eases developers’ tasks, because they can proceed with their work, knowing that each and every new project won’t need to be redone every time a new token is released, as long as the token follows the rules. + +Here is, presented as an interface, the functions an ERC-20 must implement. If you’re not sure about what is an interface: check our article about [OOP programming in Solidity](https://ethereumdev.io/inheritance-in-solidity-contracts-are-classes/). + +```solidity +pragma solidity ^0.6.0; + +interface IERC20 +``` + +Here is a line-by-line explainer of what every function is for. After this we’ll present a simple implementation of the ERC-20 token. + +## Getters + +```solidity +function totalSupply() external view returns (uint256); +``` + +Returns the amount of tokens in existence. This function is a getter and does not modify the state of the contract. Keep in mind that there are no floats in Solidity. Therefore most tokens adopt 18 decimals and will return the total supply and other results as followed 1000000000000000000 for 1 token. Not every token has 18 decimals and this is something you really need to watch for when dealing with tokens. + +```solidity +function balanceOf(address account) external view returns (uint256); +``` + +Returns the amount of tokens owned by an address (`account`). This function is a getter and does not modify the state of the contract. + +```solidity +function allowance(address owner, address spender) external view returns (uint256); +``` + +The ERC-20 standard allows an address to give an allowance to another address to be able to retrieve tokens from it. This getter returns the remaining number of tokens that the `spender` will be allowed to spend on behalf of `owner`. This function is a getter and does not modify the state of the contract and should return 0 by default. + +## Functions + +```solidity +function transfer(address recipient, uint256 amount) external returns (bool); +``` + +Moves the `amount` of tokens from the function caller address (`msg.sender`) to the recipient address. This function emits the `Transfer` event defined later. It returns true if the transfer was possible. + +```solidity +function approve(address spender, uint256 amount) external returns (bool); +``` + +Set the amount of `allowance` the `spender` is allowed to transfer from the function caller (`msg.sender`) balance. This function emits the Approval event. The function returns whether the allowance was successfully set. + +```solidity +function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +``` + +Moves the `amount` of tokens from `sender` to `recipient` using the allowance mechanism. amount is then deducted from the caller’s allowance. This function emits the `Transfer` event. + +## Events + +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +``` + +This event is emitted when the amount of tokens (value) is sent from the `from` address to the `to` address. + +In the case of minting new tokens, the transfer is usually `from` the 0x00..0000 address while in the case of burning tokens the transfer is `to` 0x00..0000. + +```solidity +event Approval(address indexed owner, address indexed spender, uint256 value); +``` + +This event is emitted when the amount of tokens (`value`) is approved by the `owner` to be used by the `spender`. + +## A basic implementation of ERC-20 tokens + +Here is the most simple code to base your ERC-20 token from: + +```solidity +pragma solidity ^0.8.0; + +interface IERC20 + + +contract ERC20Basic is IERC20 + + function totalSupply() public override view returns (uint256) + + function balanceOf(address tokenOwner) public override view returns (uint256) + + function transfer(address receiver, uint256 numTokens) public override returns (bool) + + function approve(address delegate, uint256 numTokens) public override returns (bool) + + function allowance(address owner, address delegate) public override view returns (uint) + + function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) +} +``` + +Another excellent implementation of the ERC-20 token standard is the [OpenZeppelin ERC-20 implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). + +--- + +## Developers > Tutorials > Uniswap V2 Annotated Code + +## Introduction + +[Uniswap v2](https://uniswap.org/whitepaper.pdf) can create an exchange market between any two ERC-20 tokens. In this article we will go over the source code for the contracts that implement this protocol and see why they are written this way. + +### What Does Uniswap Do? + +Basically, there are two types of users: liquidity providers and traders. + +The _liquidity providers_ provide the pool with the two tokens that can be exchanged (we'll call them **Token0** and **Token1**). In return, they receive a third token that represents partial ownership of the pool called a _liquidity token_. + +_Traders_ send one type of token to the pool and receive the other (for example, send **Token0** and receive **Token1**) out of the pool provided by the liquidity providers. The exchange rate is determined by the relative number of **Token0**s and **Token1**s that the pool has. In addition, the pool takes a small percent as a reward for the liquidity pool. + +When liquidity providers want their assets back they can burn the pool tokens and receive back their tokens, including their share of the rewards. + +[Click here for a fuller description](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/swaps/). + +### Why v2? Why not v3? + +[Uniswap v3](https://uniswap.org/whitepaper-v3.pdf) is an upgrade that is much more complicated than the v2. It is easier to first learn v2 and then go to v3. + +### Core Contracts vs Periphery Contracts + +Uniswap v2 is divided into two components, a core and a periphery. This division allows the core contracts, which hold the assets and therefore _have_ to be secure, to be simpler and easier to audit. All the extra functionality required by traders can then be provided by periphery contracts. + +## Data and Control Flows + +This is the flow of data and control that happens when you perform the three main actions of Uniswap: + +1. Swap between different tokens +2. Add liquidity to the market and get rewarded with pair exchange ERC-20 liquidity tokens +3. Burn ERC-20 liquidity tokens and get back the ERC-20 tokens that the pair exchange allows traders to exchange + +### Swap + +This is most common flow, used by traders: + +#### Caller + +1. Provide the periphery account with an allowance in the amount to be swapped. +2. Call one of the periphery contract's many swap functions (which one depends on whether ETH is involved or not, whether the trader specifies the amount of tokens to deposit or the amount of tokens to get back, etc). + Every swap function accepts a `path`, an array of exchanges to go through. + +#### In the periphery contract (UniswapV2Router02.sol) + +3. Identify the amounts that need to be traded on each exchange along the path. +4. Iterates over the path. For every exchange along the way it sends the input token and then calls the exchange's `swap` function. + In most cases the destination address for the tokens is the next pair exchange in the path. In the final exchange it is the address provided by the trader. + +#### In the core contract (UniswapV2Pair.sol) + +5. Verify that the core contract is not being cheated and can maintain sufficient liquidity after the swap. +6. See how many extra tokens we have in addition to the known reserves. That amount is the number of input tokens we received to exchange. +7. Send the output tokens to the destination. +8. Call `_update` to update the reserve amounts + +#### Back in the periphery contract (UniswapV2Router02.sol) + +9. Perform any necessary cleanup (for example, burn WETH tokens to get back ETH to send the trader) + +### Add Liquidity + +#### Caller + +1. Provide the periphery account with an allowance in the amounts to be added to the liquidity pool. +2. Call one of the periphery contract's `addLiquidity` functions. + +#### In the periphery contract (UniswapV2Router02.sol) + +3. Create a new pair exchange if necessary +4. If there is an existing pair exchange, calculate the amount of tokens to add. This is supposed to be identical value for both tokens, so the same ratio of new tokens to existing tokens. +5. Check if the amounts are acceptable (callers can specify a minimum amount below which they'd rather not add liquidity) +6. Call the core contract. + +#### In the core contract (UniswapV2Pair.sol) + +7. Mint liquidity tokens and send them to the caller +8. Call `_update` to update the reserve amounts + +### Remove Liquidity + +#### Caller + +1. Provide the periphery account with an allowance of liquidity tokens to be burned in exchange for the underlying tokens. +2. Call one of the periphery contract's `removeLiquidity` functions. + +#### In the periphery contract (UniswapV2Router02.sol) + +3. Send the liquidity tokens to the pair exchange + +#### In the core contract (UniswapV2Pair.sol) + +4. Send the destination address the underlying tokens in proportion to the burned tokens. For example if there are 1000 A tokens in the pool, 500 B tokens, and 90 liquidity tokens, and we receive 9 tokens to burn, we're burning 10% of the liquidity tokens so we send back the user 100 A tokens and 50 B tokens. +5. Burn the liquidity tokens +6. Call `_update` to update the reserve amounts + +## The Core Contracts + +These are the secure contracts which hold the liquidity. + +### UniswapV2Pair.sol + +[This contract](https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2Pair.sol) implements the actual pool that exchanges tokens. It is the core Uniswap functionality. + +```solidity +pragma solidity =0.5.16; + +import './interfaces/IUniswapV2Pair.sol'; +import './UniswapV2ERC20.sol'; +import './libraries/Math.sol'; +import './libraries/UQ112x112.sol'; +import './interfaces/IERC20.sol'; +import './interfaces/IUniswapV2Factory.sol'; +import './interfaces/IUniswapV2Callee.sol'; +``` + +These are all the interfaces that the contract needs to know about, either because the contract implements them (`IUniswapV2Pair` and `UniswapV2ERC20`) or because it calls contracts that implement them. + +```solidity +contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 + +```solidity + uint public constant MINIMUM_LIQUIDITY = 10**3; +``` + +To avoid cases of division by zero, there is a minimum number of liquidity tokens that always exist (but are owned by account zero). That number is **MINIMUM_LIQUIDITY**, a thousand. + +```solidity + bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); +``` + +This is the ABI selector for the ERC-20 transfer function. It is used to transfer ERC-20 tokens in the two token accounts. + +```solidity + address public factory; +``` + +This is the factory contract that created this pool. Every pool is an exchange between two ERC-20 tokens, the factory is a central point that connects all of these pools. + +```solidity + address public token0; + address public token1; +``` + +There are the addresses of the contracts for the two types of ERC-20 tokens that can be exchanged by this pool. + +```solidity + uint112 private reserve0; // uses single storage slot, accessible via getReserves + uint112 private reserve1; // uses single storage slot, accessible via getReserves +``` + +The reserves the pool has for each token type. We assume that the two represent the same amount of value, and therefore each token0 is worth reserve1/reserve0 token1's. + +```solidity + uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves +``` + +The timestamp for the last block in which an exchange occurred, used to track exchange rates across time. + +One of the biggest gas expenses of Ethereum contracts is storage, which persists from one call of the contract to the next. Each storage cell is 256 bits long. So three variables, `reserve0`, `reserve1`, and `blockTimestampLast`, are allocated in such a way a single storage value can include all three of them (112+112+32=256). + +```solidity + uint public price0CumulativeLast; + uint public price1CumulativeLast; +``` + +These variables hold the cumulative costs for each token (each in term of the other). They can be used to calculate the average exchange rate over a period of time. + +```solidity + uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event +``` + +The way the pair exchange decides on the exchange rate between token0 and token1 is to keep the multiple of the two reserves constant during trades. `kLast` is this value. It changes when a liquidity provider deposits or withdraws tokens, and it increases slightly because of the 0.3% market fee. + +Here is a simple example. Note that for the sake of simplicity the table only has three digits after the decimal point, and we ignore the 0.3% trading fee so the numbers are not accurate. + +| Event | reserve0 | reserve1 | reserve0 \* reserve1 | Average exchange rate (token1 / token0) | +| ------------------------------------------- | --------: | --------: | -------------------: | --------------------------------------- | +| Initial setup | 1,000.000 | 1,000.000 | 1,000,000 | | +| Trader A swaps 50 token0 for 47.619 token1 | 1,050.000 | 952.381 | 1,000,000 | 0.952 | +| Trader B swaps 10 token0 for 8.984 token1 | 1,060.000 | 943.396 | 1,000,000 | 0.898 | +| Trader C swaps 40 token0 for 34.305 token1 | 1,100.000 | 909.090 | 1,000,000 | 0.858 | +| Trader D swaps 100 token1 for 109.01 token0 | 990.990 | 1,009.090 | 1,000,000 | 0.917 | +| Trader E swaps 10 token0 for 10.079 token1 | 1,000.990 | 999.010 | 1,000,000 | 1.008 | + +As traders provide more of token0, the relative value of token1 increases, and vice versa, based on supply and demand. + +#### Lock + +```solidity + uint private unlocked = 1; +``` + +There is a class of security vulnerabilities that are based on [reentrancy abuse](https://medium.com/coinmonks/ethernaut-lvl-10-re-entrancy-walkthrough-how-to-abuse-execution-ordering-and-reproduce-the-dao-7ec88b912c14). Uniswap needs to transfer arbitrary ERC-20 tokens, which means calling ERC-20 contracts that may attempt to abuse the Uniswap market that calls them. +By having an `unlocked` variable as part of the contract, we can prevent functions from being called while they are running (within the same transaction). + +```solidity + modifier lock() +``` + +After the main function returns, release the lock. + +#### Misc. functions + +```solidity + function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) +``` + +This function provides callers with the current state of the exchange. Notice that Solidity functions [can return multiple values](https://docs.soliditylang.org/en/v0.8.3/contracts.html#returning-multiple-values). + +```solidity + function _safeTransfer(address token, address to, uint value) private +``` + +There are two ways in which an ERC-20 transfer call can report failure: + +1. Revert. If a call to an external contract reverts, then the boolean return value is `false` +2. End normally but report a failure. In that case the return value buffer has a non-zero length, and when decoded as a boolean value it is `false` + +If either of these conditions happen, revert. + +#### Events + +```solidity + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); +``` + +These two events are emitted when a liquidity provider either deposits liquidity (`Mint`) or withdraws it (`Burn`). In either case, the amounts of token0 and token1 that are deposited or withdrawn are part of the event, as well as the identity of the account that called us (`sender`). In the case of a withdrawal, the event also includes the target that received the tokens (`to`), which may not be the same as the sender. + +```solidity + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); +``` + +This event is emitted when a trader swaps one token for the other. Again, the sender and the destination may not be the same. +Each token may be either sent to the exchange, or received from it. + +```solidity + event Sync(uint112 reserve0, uint112 reserve1); +``` + +Finally, `Sync` is emitted every time tokens are added or withdrawn, regardless of the reason, to provide the latest reserve information (and therefore the exchange rate). + +#### Setup Functions + +These functions are supposed to be called once when the new pair exchange is set up. + +```solidity + constructor() public +``` + +The constructor makes sure we'll keep track of the address of the factory that created the pair. This information is required for `initialize` and for the factory fee (if one exists) + +```solidity + // called once by the factory at time of deployment + function initialize(address _token0, address _token1) external +``` + +This function allows the factory (and only the factory) to specify the two ERC-20 tokens that this pair will exchange. + +#### Internal Update Functions + +##### \_update + +```solidity + // update reserves and, on the first call per block, price accumulators + function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private +``` + +Each cost accumulator is updated with the latest cost (reserve of the other token/reserve of this token) times the elapsed time in seconds. To get an average price, you read the cumulative price in two points in time and divide by the time difference between them. For example, assume this sequence of events: + +| Event | reserve0 | reserve1 | timestamp | Marginal exchange rate (reserve1 / reserve0) | price0CumulativeLast | +| -------------------------------------------------------- | --------: | --------: | --------- | -------------------------------------------: | -------------------------: | +| Initial setup | 1,000.000 | 1,000.000 | 5,000 | 1.000 | 0 | +| Trader A deposits 50 token0 and gets 47.619 token1 back | 1,050.000 | 952.381 | 5,020 | 0.907 | 20 | +| Trader B deposits 10 token0 and gets 8.984 token1 back | 1,060.000 | 943.396 | 5,030 | 0.890 | 20+10\*0.907 = 29.07 | +| Trader C deposits 40 token0 and gets 34.305 token1 back | 1,100.000 | 909.090 | 5,100 | 0.826 | 29.07+70\*0.890 = 91.37 | +| Trader D deposits 100 token1 and gets 109.01 token0 back | 990.990 | 1,009.090 | 5,110 | 1.018 | 91.37+10\*0.826 = 99.63 | +| Trader E deposits 10 token0 and gets 10.079 token1 back | 1,000.990 | 999.010 | 5,150 | 0.998 | 99.63+40\*1.1018 = 143.702 | + +Let's say we want to calculate the average price of **Token0** between the timestamps 5,030 and 5,150. The difference in the value of `price0Cumulative` is 143.702-29.07=114.632. This is the average across two minutes (120 seconds). So the average price is 114.632/120 = 0.955. + +This price calculation is the reason we need to know the old reserve sizes. + +```solidity + reserve0 = uint112(balance0); + reserve1 = uint112(balance1); + blockTimestampLast = blockTimestamp; + emit Sync(reserve0, reserve1); + } +``` + +Finally, update the global variables and emit a `Sync` event. + +##### \_mintFee + +```solidity + // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) + function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) + } +``` + +Use the `UniswapV2ERC20._mint` function to actually create the additional liquidity tokens and assign them to `feeTo`. + +```solidity + } else if (_kLast != 0) + } +``` + +If there is no fee set `kLast` to zero (if it isn't that already). When this contract was written there was a [gas refund feature](https://eips.ethereum.org/EIPS/eip-3298) that encouraged contracts to reduce the overall size of the Ethereum state by zeroing out storage they did not need. +This code gets that refund when possible. + +#### Externally Accessible Functions + +Note that while any transaction or contract _can_ call these functions, they are designed to be called from the periphery contract. If you call them directly you won't be able to cheat the pair exchange, but you might lose value through a mistake. + +##### mint + +```solidity + // this low-level function should be called from a contract which performs important safety checks + function mint(address to) external lock returns (uint liquidity) else + require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED'); + _mint(to, liquidity); +``` + +Use the `UniswapV2ERC20._mint` function to actually create the additional liquidity tokens and give them to the correct account. + +```solidity + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Mint(msg.sender, amount0, amount1); + } +``` + +Update the state variables (`reserve0`, `reserve1`, and if needed `kLast`) and emit the appropriate event. + +##### burn + +```solidity + // this low-level function should be called from a contract which performs important safety checks + function burn(address to) external lock returns (uint amount0, uint amount1) + +``` + +The rest of the `burn` function is the mirror image of the `mint` function above. + +##### swap + +```solidity + // this low-level function should be called from a contract which performs important safety checks + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock +``` + +Get the current balances. The periphery contract sends us the tokens before calling us for the swap. This makes it easy for the contract to check that it is not being cheated, a check that _has_ to happen in the core contract (because we can be called by other entities than our periphery contract). + +```solidity + uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; + uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; + require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); + Adjusted, avoids stack too deep errors + uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); + uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); + require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K'); +``` + +This is a sanity check to make sure we don't lose from the swap. There is no circumstance in which a swap should reduce `reserve0*reserve1`. This is also where we ensure a fee of 0.3% is being sent on the swap; before sanity checking the value of K, we multiply both balances by 1000 subtracted by the amounts multiplied by 3, this means 0.3% (3/1000 = 0.003 = 0.3%) is being deducted from the balance before comparing its K value with the current reserves K value. + +```solidity + } + + _update(balance0, balance1, _reserve0, _reserve1); + emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); + } +``` + +Update `reserve0` and `reserve1`, and if necessary the price accumulators and the timestamp and emit an event. + +##### Sync or Skim + +It is possible for the real balances to get out of sync with the reserves that the pair exchange thinks it has. +There is no way to withdraw tokens without the contract's consent, but deposits are a different matter. An account can transfer tokens to the exchange without calling either `mint` or `swap`. + +In that case there are two solutions: + +- `sync`, update the reserves to the current balances +- `skim`, withdraw the extra amount. Note that any account is allowed to call `skim` because we don't know who deposited the tokens. This information is emitted in an event, but events are not accessible from the blockchain. + +```solidity + // force balances to match reserves + function skim(address to) external lock + + + + // force reserves to match balances + function sync() external lock +} +``` + +### UniswapV2Factory.sol + +[This contract](https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2Factory.sol) creates the pair exchanges. + +```solidity +pragma solidity =0.5.16; + +import './interfaces/IUniswapV2Factory.sol'; +import './UniswapV2Pair.sol'; + +contract UniswapV2Factory is IUniswapV2Factory +``` + +The only thing the constructor does is specify the `feeToSetter`. Factories start without a fee, and only `feeSetter` can change that. + +```solidity + function allPairsLength() external view returns (uint) +``` + +This function returns the number of exchange pairs. + +```solidity + function createPair(address tokenA, address tokenB) external returns (address pair) +``` + +When an opcode is not supported by Solidity yet we can call it using [inline assembly](https://docs.soliditylang.org/en/v0.8.3/assembly.html). + +```solidity + IUniswapV2Pair(pair).initialize(token0, token1); +``` + +Call the `initialize` function to tell the new exchange what two tokens it exchanges. + +```solidity + getPair[token0][token1] = pair; + getPair[token1][token0] = pair; // populate mapping in the reverse direction + allPairs.push(pair); + emit PairCreated(token0, token1, pair, allPairs.length); + } +``` + +Save the new pair information in the state variables and emit an event to inform the world of the new pair exchange. + +```solidity + function setFeeTo(address _feeTo) external + + function setFeeToSetter(address _feeToSetter) external +} +``` + +These two functions allow `feeSetter` to control the fee recipient (if any), and to change `feeSetter` to a new address. + +### UniswapV2ERC20.sol + +[This contract](https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) implements the ERC-20 liquidity token. It is similar to the [OpenZeppelin ERC-20 contract](/developers/tutorials/erc20-annotated-code), so I will only explain the part that is different, the `permit` functionality. + +Transactions on Ethereum cost ether (ETH), which is equivalent to real money. If you have ERC-20 tokens but not ETH, you can't send transactions, so you can't do anything with them. One solution to avoid this problem is [meta-transactions](https://docs.uniswap.org/contracts/v2/guides/smart-contract-integration/supporting-meta-transactions). +The owner of the tokens signs a transaction that allows somebody else to withdraw tokens offchain and sends it using the Internet to the recipient. The recipient, which does have ETH, then submits the permit on behalf of the owner. + +```solidity + bytes32 public DOMAIN_SEPARATOR; + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; +``` + +This hash is the [identifier for the transaction type](https://eips.ethereum.org/EIPS/eip-712#rationale-for-typehash). The only one we support here is `Permit` with these parameters. + +```solidity + mapping(address => uint) public nonces; +``` + +It is not feasible for a recipient to fake a digital signature. However, it is trivial to send the same transaction twice (this is a form of [replay attack](https://wikipedia.org/wiki/Replay_attack)). To prevent this, we use a [nonce](https://wikipedia.org/wiki/Cryptographic_nonce). If the nonce of a new `Permit` is not one more than the last one used, we assume it is invalid. + +```solidity + constructor() public +``` + +This is the code to retrieve the [chain identifier](https://chainid.network/). It uses an EVM assembly dialect called [Yul](https://docs.soliditylang.org/en/v0.8.4/yul.html). Note that in the current version of Yul you have to use `chainid()`, not `chainid`. + +```solidity + DOMAIN_SEPARATOR = keccak256( + abi.encode( + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), + keccak256(bytes(name)), + keccak256(bytes('1')), + chainId, + address(this) + ) + ); + } +``` + +Calculate the [domain separator](https://eips.ethereum.org/EIPS/eip-712#rationale-for-domainseparator) for EIP-712. + +```solidity + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external + +``` + +If everything is OK, treat this as [an ERC-20 approve](https://eips.ethereum.org/EIPS/eip-20#approve). + +## The Periphery Contracts + +The periphery contracts are the API (application program interface) for Uniswap. They are available for external calls, either from other contracts or decentralized applications. You could call the core contracts directly, but that's more complicated and you might lose value if you make a mistake. The core contracts only contain tests to make sure they aren't cheated, not sanity checks for anybody else. Those are in the periphery so they can be updated as needed. + +### UniswapV2Router01.sol + +[This contract](https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/UniswapV2Router01.sol) has problems, and [should no longer be used](https://docs.uniswap.org/contracts/v2/reference/smart-contracts/router-01). Luckily, the periphery contracts are stateless and don't hold any assets, so it is easy to deprecate it and suggest people use the replacement, `UniswapV2Router02`, instead. + +### UniswapV2Router02.sol + +In most cases you would use Uniswap through [this contract](https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/UniswapV2Router02.sol). +You can see how to use it [here](https://docs.uniswap.org/contracts/v2/reference/smart-contracts/router-02). + +```solidity +pragma solidity =0.6.6; + +import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol'; +import '@uniswap/lib/contracts/libraries/TransferHelper.sol'; + +import './interfaces/IUniswapV2Router02.sol'; +import './libraries/UniswapV2Library.sol'; +import './libraries/SafeMath.sol'; +import './interfaces/IERC20.sol'; +import './interfaces/IWETH.sol'; +``` + +Most of these we either encountered before, or are fairly obvious. The one exception is `IWETH.sol`. Uniswap v2 allows exchanges for any pair of ERC-20 tokens, but ether (ETH) itself isn't an ERC-20 token. It predates the standard and is transferred by unique mechanisms. To enable the use of ETH in contracts that apply to ERC-20 tokens people came up with the [wrapped ether (WETH)](https://weth.tkn.eth.limo/) contract. You send this contract ETH, and it mints you an equivalent amount of WETH. Or you can burn WETH, and get ETH back. + +```solidity +contract UniswapV2Router02 is IUniswapV2Router02 +``` + +This modifier makes sure that time limited transactions ("do X before time Y if you can") don't happen after their time limit. + +```solidity + constructor(address _factory, address _WETH) public +``` + +The constructor just sets the immutable state variables. + +```solidity + receive() external payable +``` + +This function is called when we redeem tokens from the WETH contract back into ETH. Only the WETH contract we use is authorized to do that. + +#### Add Liquidity + +These functions add tokens to the pair exchange, which increases the liquidity pool. + +```solidity + + // **** ADD LIQUIDITY **** + function _addLiquidity( +``` + +This function is used to calculate the amount of A and B tokens that should be deposited into the pair exchange. + +```solidity + address tokenA, + address tokenB, +``` + +These are the addresses of the ERC-20 token contracts. + +```solidity + uint amountADesired, + uint amountBDesired, +``` + +These are the amounts the liquidity provider wants to deposit. They are also the maximum amounts of A and B to be deposited. + +```solidity + uint amountAMin, + uint amountBMin +``` + +These are the minimum acceptable amounts to deposit. If the transaction cannot take place with these amounts or more, revert out of it. If you don't want this feature, just specify zero. + +Liquidity providers specify a minimum, typically, because they want to limit the transaction to an exchange rate that is close to the current one. If the exchange rate fluctuates too much it might mean news that change the underlying values, and they want to decide manually what to do. + +For example, imagine a case where the exchange rate is one to one and the liquidity provider specifies these values: + +| Parameter | Value | +| -------------- | ----: | +| amountADesired | 1000 | +| amountBDesired | 1000 | +| amountAMin | 900 | +| amountBMin | 800 | + +As long as the exchange rate stays between 0.9 and 1.25, the transaction takes place. If the exchange rate gets out of that range, the transaction gets cancelled. + +The reason for this precaution is that transactions are not immediate, you submit them and eventually a validator is going to include them in a block (unless your gas price is very low, in which case you'll need to submit another transaction with the same nonce and a higher gas price to overwrite it). You cannot control what happens during the interval between submission and inclusion. + +```solidity + ) internal virtual returns (uint amountA, uint amountB) +``` + +If there is no exchange for this token pair yet, create it. + +```solidity + (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB); +``` + +Get the current reserves in the pair. + +```solidity + if (reserveA == 0 && reserveB == 0) else else +``` + +In return give the `to` address liquidity tokens for partial ownership of the pool. The `mint` function of the core contract sees how many extra tokens it has (compared to what it had the last time liquidity changed) and mints liquidity accordingly. + +```solidity + function addLiquidityETH( + address token, + uint amountTokenDesired, +``` + +When a liquidity provider wants to provide liquidity to a Token/ETH pair exchange, there are a few differences. The contract handles wrapping the ETH for the liquidity provider. There is no need to specify how many ETH the user wants to deposit, because the user just sends them with the transaction (the amount is available in `msg.value`). + +```solidity + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) (); + assert(IWETH(WETH).transfer(pair, amountETH)); +``` + +To deposit the ETH the contract first wraps it into WETH and then transfers the WETH into the pair. Notice that the transfer is wrapped in an `assert`. This means that if the transfer fails this contract call also fails, and therefore the wrapping doesn't really happen. + +```solidity + liquidity = IUniswapV2Pair(pair).mint(to); + // refund dust eth, if any + if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); + } +``` + +The user has already sent us the ETH, so if there is any extra left over (because the other token is less valuable than the user thought), we need to issue a refund. + +#### Remove Liquidity + +These functions will remove liquidity and pay back the liquidity provider. + +```solidity + // **** REMOVE LIQUIDITY **** + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) +``` + +It is OK to do the transfer first and then verify it is legitimate, because if it isn't we'll revert out of all the state changes. + +```solidity + function removeLiquidityETH( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) +``` + +Remove liquidity for ETH is almost the same, except that we receive the WETH tokens and then redeem them for ETH to give back to the liquidity provider. + +```solidity + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external virtual override returns (uint amountA, uint amountB) + + + function removeLiquidityETHWithPermit( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external virtual override returns (uint amountToken, uint amountETH) +``` + +These functions relay meta-transactions to allow users without ether to withdraw from the pool, using [the permit mechanism](#UniswapV2ERC20). + +```solidity + + // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** + function removeLiquidityETHSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) public virtual override ensure(deadline) returns (uint amountETH) + +``` + +This function can be used for tokens that have transfer or storage fees. When a token has such fees we cannot rely on the `removeLiquidity` function to tell us how much of the token we get back, so we need to withdraw first and then get the balance. + +```solidity + + + function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external virtual override returns (uint amountETH) +``` + +The final function combines storage fees with meta-transactions. + +#### Trade + +```solidity + // **** SWAP **** + // requires the initial amount to have already been sent to the first pair + function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual +``` + +Finally, transfer the initial ERC-20 token to the account for the first pair exchange and call `_swap`. This is all happening in the same transaction, so the pair exchange knows that any unexpected tokens are part of this transfer. + +```solidity + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external virtual override ensure(deadline) returns (uint[] memory amounts) (); + assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); + _swap(amounts, path, to); + } + + + function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + external + virtual + override + ensure(deadline) + returns (uint[] memory amounts) + + + + function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + external + virtual + override + payable + ensure(deadline) + returns (uint[] memory amounts) + +``` + +These four variants all involve trading between ETH and tokens. The only difference is that we either receive ETH from the trader and use it to mint WETH, or we receive WETH from the last exchange in the path and burn it, sending the trader back the resulting ETH. + +```solidity + // **** SWAP (supporting fee-on-transfer tokens) **** + // requires the initial amount to have already been sent to the first pair + function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual + + + function swapExactETHForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) + external + virtual + override + payable + ensure(deadline) + (); + assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn)); + uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); + _swapSupportingFeeOnTransferTokens(path, to); + require( + IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, + 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' + ); + } + + + function swapExactTokensForETHSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) + external + virtual + override + ensure(deadline) + +``` + +These are the same variants used for normal tokens, but they call `_swapSupportingFeeOnTransferTokens` instead. + +```solidity + // **** LIBRARY FUNCTIONS **** + function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) + + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) + public + pure + virtual + override + returns (uint amountOut) + + + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) + public + pure + virtual + override + returns (uint amountIn) + + + function getAmountsOut(uint amountIn, address[] memory path) + public + view + virtual + override + returns (uint[] memory amounts) + + + function getAmountsIn(uint amountOut, address[] memory path) + public + view + virtual + override + returns (uint[] memory amounts) + +} +``` + +These functions are just proxies that call the [UniswapV2Library functions](#uniswapV2library). + +### UniswapV2Migrator.sol + +This contract was used to migrate exchanges from the old v1 to v2. Now that they have been migrated, it is no longer relevant. + +## The Libraries + +The [SafeMath library](https://docs.openzeppelin.com/contracts/2.x/api/math) is well documented, so there's no need to document it here. + +### Math + +This library contains some math functions that are not normally needed in Solidity code, so they aren't part of the language. + +```solidity +pragma solidity =0.5.16; + +// a library for performing various math operations + +library Math +``` + +This function gives you the amount of token B you'll get in return for token A if there is no fee involved. This calculation takes into account that the transfer changes the exchange rate. + +```solidity + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) +``` + +Solidity does not handle fractions natively, so we can't just multiply the amount out by 0.997. Instead, we multiply the numerator by 997 and the denominator by 1000, achieving the same effect. + +```solidity + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) +``` + +This function does roughly the same thing, but it gets the output amount and provides the input. + +```solidity + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) + } +} +``` + +These two functions handle identifying the values when it is necessary to go through several pair exchanges. + +### Transfer Helper + +[This library](https://github.com/Uniswap/uniswap-lib/blob/master/contracts/libraries/TransferHelper.sol) adds success checks around ERC-20 and Ethereum transfers to treat a revert and a `false` value return the same way. + +```solidity +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity >=0.6.0; + +// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false +library TransferHelper +``` + +For the sake of backwards compatibility with token that were created prior to the ERC-20 standard, an ERC-20 call can fail either by reverting (in which case `success` is `false`) or by being successful and returning a `false` value (in which case there is output data, and if you decode it as a boolean you get `false`). + +```solidity + + + function safeTransfer( + address token, + address to, + uint256 value + ) internal +``` + +This function implements [ERC-20's transfer functionality](https://eips.ethereum.org/EIPS/eip-20#transfer), which allows an account to spend out the allowance provided by a different account. + +```solidity + + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal +``` + +This function implements [ERC-20's transferFrom functionality](https://eips.ethereum.org/EIPS/eip-20#transferfrom), which allows an account to spend out the allowance provided by a different account. + +```solidity + + function safeTransferETH(address to, uint256 value) internal (new bytes(0)); + require(success, 'TransferHelper::safeTransferETH: ETH transfer failed'); + } +} +``` + +This function transfers ether to an account. Any call to a different contract can attempt to send ether. Because we don't need to actually call any function, we don't send any data with the call. + +## Conclusion + +This is a long article of about 50 pages. If you made it here, congratulations! Hopefully by now you've understood the considerations in writing a real-life application (as opposed to short sample programs) and are better to be able to write contracts for your own use cases. + +Now go and write something useful and amaze us. + +--- + +## Developers > Tutorials > Using Websockets + +This is an entry level guide to using WebSockets and Alchemy to make requests to the Ethereum blockchain. + +## WebSockets vs. HTTP + +Unlike HTTP, with WebSockets, you don't need to continuously make requests when you want specific information. WebSockets maintain a network connection for you (if done right) and listen for changes. + +As with any network connection, you should not assume that a WebSocket will remain open forever without interruption, but correctly handling dropped connections and reconnection by hand can be challenging to get right. Another downside of WebSockets is that you do not get HTTP status codes in the response, but only the error message. + +​[Alchemy Web3](https://docs.alchemy.com/reference/api-overview) automatically adds handling for WebSocket failures and retries with no configuration necessary. + +## Try it out + +The easiest way to test out WebSockets is to install a command line tool for making WebSocket requests such as [wscat](https://github.com/websockets/wscat). Using wscat, you can send requests as follows: + +_Note: if you have an Alchemy account you can replace `demo` with your own API key. [Sign up for a free Alchemy account here!](https://auth.alchemyapi.io/signup)_ + +``` +wscat -c wss://eth-mainnet.ws.alchemyapi.io/ws/demo + +> + + 7946893 +``` + +## Subscription API + +When connected through a WebSocket, you may use two additional methods: `eth_subscribe` and `eth_unsubscribe`. These methods will allow you to listen for particular events and be notified immediately. + +### `eth_subscribe` + +Creates a new subscription for specified events. [Learn more about `eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe). + +#### Parameters + +1. Subscription types +2. Optional params + +The first argument specifies the type of event for which to listen. The second argument contains additional options which depend on the first argument. The different description types, their options, and their event payloads are described below. + +#### Returns + +The subscription ID: This ID will be attached to any received events, and can also be used to cancel the subscription using `eth_unsubscribe`. + +#### Subscription events + +While the subscription is active, you will receive events which are objects with the following fields: + +- `jsonrpc`: Always "2.0" +- `method`: Always "eth_subscription" +- `params`: An object with the following fields: + - `subscription`: The subscription ID returned by the `eth_subscribe` call which created this subscription. + - `result`: An object whose contents vary depending on the type of subscription. + +#### Subscription types + +1. `alchemy_newFullPendingTransactions` + +Returns the transaction information for all transactions that are added to the pending state. This subscription type subscribes to pending transactions, similar to the standard Web3 call `web3.eth.subscribe("pendingTransactions")`, but differs in that it emits _full transaction information_ rather than just transaction hashes. + +Example: + +```json +> + + + + ]} + +< +< + } +} + +``` + +### `eth_unsubscribe` + +Cancels an existing subscription so that no further events are sent. + +Parameters + +1. Subscription ID, as previously returned from an `eth_subscribe` call. + +Returns + +`true` if a subscription was successfully cancelled, or `false` if no subscription existed with the given ID. + +Example: + +**Request** + +``` +curl https://eth-mainnet.alchemyapi.io/v2/your-api-key +-X POST +-H "Content-Type: application/json" +-d '' + + +``` + +**Result** + +```json + +``` + +--- + +[Sign up with Alchemy](https://auth.alchemyapi.io/signup) for free, check out [our documentation](https://docs.alchemyapi.io/), and for the latest news, follow us on [Twitter](https://twitter.com/AlchemyPlatform). + +--- + +## Developers > Tutorials > Waffle Dynamic Mocking And Testing Calls + +## What is this tutorial about? + +In this tutorial you will learn how to: + +- use dynamic mocking +- test interactions between smart contracts + +Assumptions: + +- you already know how to write a simple smart contract in `Solidity` +- you know your way around `JavaScript` and `TypeScript` +- you've done other `Waffle` tutorials or know a thing or two about it + +## Dynamic mocking + +Why is dynamic mocking useful? Well, it allows us to write unit tests instead of integration tests. What does it mean? It means that we don't have to worry about smart contracts' dependencies, thus we can test all of them in complete isolation. Let me show you how exactly you can do it. + +### **1. Project** + +Before we start we need to prepare a simple node.js project: + +```bash +mkdir dynamic-mocking +cd dynamic-mocking +mkdir contracts src + +yarn init +# or if you're using npm +npm init +``` + +Let's start with adding typescript and test dependencies - mocha & chai: + +```bash +yarn add --dev @types/chai @types/mocha chai mocha ts-node typescript +# or if you're using npm +npm install @types/chai @types/mocha chai mocha ts-node typescript --save-dev +``` + +Now let's add `Waffle` and `ethers`: + +```bash +yarn add --dev ethereum-waffle ethers +# or if you're using npm +npm install ethereum-waffle ethers --save-dev +``` + +Your project structure should look like this now: + +``` +. +├── contracts +├── package.json +└── test +``` + +### **2. Smart contract** + +To start dynamic mocking, we need a smart contract with dependencies. Don't worry, I've got you covered! + +Here's a simple smart contract written in `Solidity` whose sole purpose is to check if we're rich. It uses ERC20 token to check if we have enough tokens. Put it in `./contracts/AmIRichAlready.sol`. + +```solidity +pragma solidity ^0.6.2; + +interface IERC20 + +contract AmIRichAlready + + function check() public view returns (bool) +} +``` + +As we want to use dynamic mocking we don't need the whole ERC20, that's why we're using the IERC20 interface with only one function. + +It's time to build this contract! For that we will use `Waffle`. First, we're going to create a simple `waffle.json` config file which specifies compilation options. + +```json + +``` + +Now we're ready to build the contract with Waffle: + +```bash +npx waffle +``` + +Easy, right? In `build/` folder two files corresponding to the contract and the interface appeared. We will use them later for testing. + +### **3. Testing** + +Let's create a file called `AmIRichAlready.test.ts` for the actual testing. First of all, we have to handle the imports. We will need them for later: + +```typescript +import from "ethereum-waffle" +``` + +Except for JS dependencies, we need to import our built contract and interface: + +```typescript +``` + +Waffle uses `chai` for testing. However, before we can use it, we have to inject Waffle's matchers into chai itself: + +```typescript +use(solidity) +``` + +We need to implement `beforeEach()` function that will reset the state of the contract before each test. Let's first think of what we need there. To deploy a contract we need two things: a wallet and a deployed ERC20 contract to pass it as an argument for the `AmIRichAlready` contract. + +Firstly we create a wallet: + +```typescript +const [wallet] = new MockProvider().getWallets() +``` + +Then we need to deploy an ERC20 contract. Here's the tricky part - we have only an interface. This is the part where Waffle comes to save us. Waffle has a magical `deployMockContract()` function that creates a contract using solely the _abi_ of the interface: + +```typescript +const mockERC20 = await deployMockContract(wallet, IERC20.abi) +``` + +Now with both the wallet and the deployed ERC20, we can go ahead and deploy the `AmIRichAlready` contract: + +```typescript +const contract = await deployContract(wallet, AmIRichAlready, [ + mockERC20.address, +]) +``` + +With all of that, our `beforeEach()` function is finished. So far your `AmIRichAlready.test.ts` file should look like this: + +```typescript +import from "ethereum-waffle" + + +use(solidity) + +describe("Am I Rich Already", () => ) +}) +``` + +Let's write the first test for the `AmIRichAlready` contract. What do you think our test should be about? Yeah, you're right! We should check if we are already rich :) + +But wait a second. How will our mocked contract know what values to return? We haven't implemented any logic for the `balanceOf()` function. Again, Waffle can help here. Our mocked contract has some new fancy stuff to it now: + +```typescript +await mockERC20.mock..returns() +await mockERC20.mock..withArgs().returns() +``` + +With this knowledge we can finally write our first test: + +```typescript +it("returns false if the wallet has less than 1000000 tokens", async () => ) +``` + +Let's break down this test into parts: + +1. We set our mock ERC20 contract to always return balance of 999999 tokens. +2. Check if the `contract.check()` method returns `false`. + +We're ready to fire up the beast: + +![One test passing](./test-one.png) + +So the test works, but... there's still some room for improvement. The `balanceOf()` function will always return 99999. We can improve it by specifying a wallet for which the function should return something - just like a real contract: + +```typescript +it("returns false if the wallet has less than 1000001 tokens", async () => ) +``` + +So far, we've tested only the case where we're not rich enough. Let's test the opposite instead: + +```typescript +it("returns true if the wallet has at least 1000001 tokens", async () => ) +``` + +You run the tests... + +![Two tests passing](test-two.png) + +...and here you are! Our contract seems to work as intended :) + +## Testing contract calls + +Let's sum up what've done so far. We've tested the functionality of our `AmIRichAlready` contract and it seems to be working properly. That means we're done, right? Not exactly! Waffle allows us to test our contract even further. But how exactly? Well, in Waffle's arsenal there's a `calledOnContract()` and `calledOnContractWith()` matchers. They will allow us to check if our contract called the ERC20 mock contract. Here's a basic test with one of these matchers: + +```typescript +it("checks if contract called balanceOf on the ERC20 token", async () => ) +``` + +We can go even further and improve this test with the other matcher I told you about: + +```typescript +it("checks if contract called balanceOf with certain wallet on the ERC20 token", async () => ) +``` + +Let's check if the tests are correct: + +![Three tests passing](test-three.png) + +Great, all tests are green. + +Testing contract calls with Waffle is super easy. And here's the best part. These matchers work with both normal and mocked contracts! It is because Waffle records and filters EVM calls rather than inject code, like it is the case of popular testing libraries for other technologies. + +## The Finish Line + +Congrats! Now you know how to use Waffle to test contract calls and mock contracts dynamically. There are far more interesting features to discover. I recommend diving into Waffle's documentation. + +Waffle's documentation is available [here](https://ethereum-waffle.readthedocs.io/). + +Source code for this tutorial can be found [here](https://github.com/EthWorks/Waffle/tree/master/examples/dynamic-mocking-and-testing-calls). + +Tutorials you may also be interested in: + +- [Testing smart contracts with Waffle](/developers/tutorials/waffle-test-simple-smart-contract/) + +--- + +## Developers > Tutorials > Waffle Say Hello World With Hardhat And Ethers + +In this [Waffle](https://ethereum-waffle.readthedocs.io) tutorial, we will learn how to set up a simple "Hello world" smart contract project, using [hardhat](https://hardhat.org/) and [ethers.js](https://docs.ethers.io/v5/). Then we will learn how to add a new functionality to our smart contract and how to test it with Waffle. + +Let's start by creating a new project: + +```bash +yarn init +``` + +or + +```bash +npm init +``` + +and installing required packages: + +```bash +yarn add -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai +``` + +or + +```bash +npm install -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai +``` + +Next step is creating a sample hardhat project by running `npx hardhat`. + +```bash +888 888 888 888 888 +888 888 888 888 888 +888 888 888 888 888 +8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 +888 888 "88b 888P" d88" 888 888 "88b "88b 888 +888 888 .d888888 888 888 888 888 888 .d888888 888 +888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. +888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 + +👷 Welcome to Hardhat v2.0.3 👷‍ + +? What do you want to do? … +❯ Create a sample project +Create an empty hardhat.config.js +Quit +``` + +Select `Create a sample project` + +Our project's structure should look like this: + +``` +MyWaffleProject +├── contracts +│ └── Greeter.sol +├── node_modules +├── scripts +│ └── sample-script.js +├── test +│ └── sample-test.js +├── .gitattributes +├── .gitignore +├── hardhat.config.js +└── package.json +``` + +### Now let's talk about some of these files: + +- Greeter.sol - our smart contract written in solidity; + +```solidity +contract Greeter + +function greet() public view returns (string memory) + +function setGreeting(string memory _greeting) public +} +``` + +Our smart contract can be divided into three parts: + +1. constructor - where we declare a string type variable called `greeting`, +2. function greet - a function that will return the `greeting` when called, +3. function setGreeting - a function that allows us to change the `greeting` value. + +- sample-test.js - our tests file + +```js +describe("Greeter", function () ) +}) +``` + +### Next step consists of compiling our contract and running tests: + +Waffle tests use Mocha (a test framework) with Chai (an assertion library). All you have to do is run `npx hardhat test` and wait for the following message to appear. + +```bash +✓ Should return the new greeting once it's changed +``` + +### Everything looks great so far, let's add some more complexity to our project + +Imagine a situation where someone adds an empty string as a greeting. It wouldn't be a warm greeting, right? +Let's make sure that doesn't happen: + +We want to use solidity's `revert` when someone passes an empty string. A good thing is that we can easily test this functionality with Waffle's chai matcher `to.be.revertedWith()`. + +```js +it("Should revert when passing an empty string", async () => ) +``` + +Looks like our new test didn't pass: + +```bash +Deploying a Greeter with greeting: Hello, world! +Changing greeting from 'Hello, world!' to 'Hola, mundo!' + ✓ Should return the new greeting once it's changed (1514ms) +Deploying a Greeter with greeting: Hello, world! +Changing greeting from 'Hello, world!' to '' + 1) Should revert when passing an empty string + + + 1 passing (2s) + 1 failing +``` + +Let's implement this functionality into our smart contract: + +```solidity +require(bytes(_greeting).length > 0, "Greeting should not be empty"); +``` + +Now, our setGreeting function looks like this: + +```solidity +function setGreeting(string memory _greeting) public +``` + +Let's run tests again: + +```bash +✓ Should return the new greeting once it's changed (1467ms) +✓ Should revert when passing an empty string (276ms) + +2 passing (2s) +``` + +Congrats! You made it :) + +### Conclusion + +We made a simple project with Waffle, Hardhat and ethers.js. We learned how to set up a project, add a test and implement new functionality. + +For more great chai matchers to test your smart contracts, check [official Waffle's docs](https://ethereum-waffle.readthedocs.io/en/latest/matchers.html). + +--- + +## Developers > Tutorials > Waffle Test Simple Smart Contract + +## In this tutorial you'll learn how to + +- Test the changes of wallet balance +- Test emission of events with specified arguments +- Assert that a transaction was reverted + +## Assumptions + +- You can create a new JavaScript or TypeScript project +- You have some basic experience with tests in JavaScript +- You have used some package managers like yarn or npm +- You possess very basic knowledge of smart contracts and Solidity + +## Getting started + +The tutorial demonstrates test setup and run using yarn, but there is no problem if you prefer npm - I will provide proper references to the official Waffle [documentation](https://ethereum-waffle.readthedocs.io/en/latest/index.html). + +## Install Dependencies + +[Add](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#installation) ethereum-waffle and typescript dependencies to the dev dependencies of your project. + +```bash +yarn add --dev ethereum-waffle ts-node typescript @types/jest +``` + +## Example smart contract + +During the tutorial we'll work on a simple smart contract example - EtherSplitter. It does not much apart from allowing anyone to send some wei and split it evenly between two predefined receivers. +The split function requires the number of wei to be even, otherwise it will revert. For both receivers it performs a wei transfer followed by emission of the Transfer event. + +Place the snippet of EtherSplitter code in `src/EtherSplitter.sol`. + +```solidity +pragma solidity ^0.6.0; + +contract EtherSplitter + + function split() public payable +} +``` + +## Compile the contract + +To [compile](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#compiling-the-contract) the contract add the following entry to the package.json file: + +```json +"scripts": +``` + +Next, create the Waffle configuration file in the project root directory - `waffle.json` - and then paste the following configuration there: + +```json + +``` + +Run `yarn build`. As the result, the `build` directory will appear with the EtherSplitter compiled contract in JSON format. + +## Test setup + +Testing with Waffle requires using Chai matchers and Mocha, so you need to [add](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) them to your project. Update your package.json file and add the `test` entry in the scripts part: + +```json +"scripts": +``` + +If you want to [execute](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#running-tests) your tests, just run `yarn test` . + +## Testing + +Now create the `test` directory and create the new file `test\EtherSplitter.test.ts`. +Copy the snippet below and paste it to our test file. + +```ts + +use(solidity) + +describe("Ether Splitter", () => ) + + // add the tests here +}) +``` + +A few words before we start. +The `MockProvider` comes up with a mock version of the blockchain. It also delivers mock wallets that will serve us for testing EtherSplitter contract. We can get up to ten wallets by calling `getWallets()` method on the provider. In the example, we get three wallets - for the sender and for two receivers. + +Next, we declare a variable called 'splitter' - this is our mock EtherSplitter contract. It is created before each execution of a single test by the `deployContract` method. This method simulates deployment of a contract from the wallet passed as the first parameter (sender's wallet in our case). The second parameter is the ABI and the bytecode of the tested contract - we pass there the json file of the compiled EtherSplitter contract from the `build` directory. The third parameter is an array with the contract's constructor arguments, which in our case, are the two addresses of the receivers. + +## changeBalances + +First, we will check if the split method actually changes the balances of receivers' wallets. If we split 50 wei from senders account, we would expect the balances of both receivers to increase by 25 wei. We will use Waffle's `changeBalances` matcher: + +```ts +it("Changes accounts balances", async () => )).to.changeBalances( + [receiver1, receiver2], + [25, 25] + ) +}) +``` + +As the first parameter of the matcher, we pass an array of receivers' wallets, and as the second - an array of expected increases on corresponding accounts. +If we wanted to check the balance of one specific wallet, we could also use `changeBalance` matcher, which does not require passing arrays, as in the example below: + +```ts +it("Changes account balance", async () => )).to.changeBalance( + receiver1, + 25 + ) +}) +``` + +Note that in both cases of `changeBalance` and `changeBalances` we pass the split function as a callback because the matcher needs to access the state of balances before and after the call. + +Next, we'll test if the Transfer event was emitted after each transfer of wei. We'll turn to another matcher from Waffle: + +## Emit + +```ts +it("Emits event on the transfer to the first receiver", async () => )) + .to.emit(splitter, "Transfer") + .withArgs(sender.address, receiver1.address, 25) +}) + +it("Emits event on the transfer to the second receiver", async () => )) + .to.emit(splitter, "Transfer") + .withArgs(sender.address, receiver2.address, 25) +}) +``` + +The `emit` matcher allows us to check if a contract emitted an event on calling a method. As the parameters to the `emit` matcher, we provide the mock contract that we predict to emit the event, along with the name of that event. In our case, the mock contract is `splitter` and the name of the event - `Transfer`. We can also verify the precise values of arguments that the event was emitted with - we pass as many arguments to `withArgs` matcher, as our event declaration expects. In case of EtherSplitter contract, we pass the addresses of the sender and the receiver along with the transferred wei amount. + +## revertedWith + +As the last example, we'll check if the transaction was reverted in case of uneven number of wei. We'll use `revertedWith` matcher: + +```ts +it("Reverts when Vei amount uneven", async () => )).to.be.revertedWith( + "Uneven wei amount not allowed" + ) +}) +``` + +The test, if passed, will assure us that the transaction was reverted indeed. However, there must be also an exact match between the messages that we passed in `require` statement and the message we expect in `revertedWith`. If we go back to the code of EtherSplitter contract, in the `require` statement for the wei amount, we provide the message: 'Uneven wei amount not allowed'. This matches the message we expect in our test. If they were not equal, the test would fail. + +## Congratulations! + +You've made your first big step towards testing smart contracts with Waffle! You might be interested in other Waffle tutorials: + +- [Testing ERC20 with Waffle](/developers/tutorials/testing-erc-20-tokens-with-waffle/) +- [Waffle: Dynamic mocking and testing contract calls](/developers/tutorials/waffle-dynamic-mocking-and-testing-calls/#gatsby-focus-wrapper) +- [Waffle say hello world tutorial with hardhat and ethers](/developers/tutorials/waffle-say-hello-world-with-hardhat-and-ethers/) + +--- + +## Developers > Tutorials > Yellow Paper Evm + +[The Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) is the formal specification for Ethereum. Except where amended by [the EIP process](/eips/), it contains the exact description of how everything works. It is written as a mathematical paper, which includes terminology programmers may not find familiar. In this paper you learn how to read it, and by extension other related mathematical papers. + +## Which Yellow Paper? + +Like almost everything else in Ethereum, the Yellow Paper evolves over time. To be able to refer to a specific version, I uploaded [the current version at writing](yellow-paper-berlin.pdf). The section, page, and equation numbers I use will refer to that version. It is a good idea to have it open in a different window while reading this document. + +### Why the EVM? + +The original yellow paper was written right at the start of Ethereum's development. It describes the original proof-of-work based consensus mechanism that was originally used to secure the network. However, Ethereum switched off proof-of-work and started using proof-of-stake based consensus in September 2022. This tutorial will focus on the parts of the yellow paper defining the Ethereum Virtual Machine. The EVM was unchanged by the transition to proof-of-stake (except for the return value of the DIFFICULTY opcode). + +## 9 Execution model + +This section (p. 12-14) includes most of the definition of the EVM. + +The term _system state_ includes everything you need to know about the system to run it. In a typical computer, this means the memory, content of registers, etc. + +A [Turing machine](https://en.wikipedia.org/wiki/Turing_machine) is a computational model. Essentially, it is a simplified version of a computer, which is proved to have the same ability to run computations that a normal computer can (everything that a computer can calculate a Turing machine can calculate and vice versa). This model makes it easier to prove various theorems about what is and what isn't computable. + +The term [Turing-complete](https://en.wikipedia.org/wiki/Turing_completeness) means a computer that can run the same calculations as a Turing machine. Turing machines can get into infinite loops, and the EVM cannot because it would run out of gas, so it's only quasi-Turing-complete. + +## 9.1 Basics + +This section gives the basics of the EVM and how it compares with other computational models. + +A [stack machine](https://en.wikipedia.org/wiki/Stack_machine) is a computer that stores intermediate data not in registers, but in a [**stack**](). This is the preferred architecture for virtual machines because it is easy to implement meaning that bugs, and security vulnerabilities, are a lot less likely. The memory in the stack is divided into 256-bit words. This was chosen because it is convenient for Ethereum's core cryptographic operations such as Keccak-256 hashing and elliptic curve computations. The maximum size of the stack is 1024 items (1024 x 256 bits). When opcodes are executed they are usually getting their parameters from the stack. There are opcodes specifically for reorganizing elements in the stack such as `POP` (removes item from top of stack), `DUP_N` (duplicated N'th item in stack), etc. + +The EVM also has a volatile space called **memory** which is used to store data during execution. This memory is organized into 32-byte words. All memory locations are initialized to zero. If you execute this [Yul](https://docs.soliditylang.org/en/latest/yul.html) code to add a word to memory, it will fill 32 bytes of memory by padding the empty space in the word with zeros, i.e. it creates one word - with zeros in locations 0-29, 0x60 to 30, and 0xA7 to 31. + +```yul +mstore(0, 0x60A7) +``` + +`mstore` is one of three opcodes the EVM provides for interacting with memory - it loads a word into memory. The other two are `mstore8` which loads a single byte into memory, and `mload` which moves a word from memory to stack. + +The EVM also has a separate non-volatile **storage** model that is maintained as part of the system state - this memory is organized into word arrays (as opposed to word-addressable byte arrays in the stack). This storage is where contracts keep persistent data - a contract can only interact with its own storage. Storage is organized in key-value mappings. + +Although it is not mentioned in this section of the Yellow Paper, it is also useful to know there is a fourth type of memory. **Calldata** is byte-addressable read-only memory used to store the value passed with the `data` parameter of a transaction. The EVM has specific opcodes for managing `calldata`. `calldatasize` returns the size of the data. `calldataload` loads the data into the stack. `calldatacopy` copies the data into memory. + +The standard [Von Neumann architecture](https://en.wikipedia.org/wiki/Von_Neumann_architecture) stores code and data in the same memory. The EVM does not follow this standard for security reasons - sharing volatile memory makes it possible to change program code. Instead, code is saved to storage. + +There are only two cases in which code is executed from memory: + +- When a contract creates another contract (using [`CREATE`](https://www.evm.codes/#f0) or [`CREATE2`](https://www.evm.codes/#f5)), the code for the contract constructor comes from memory. +- During the creation of _any_ contract, the constructor code runs and then returns with the code of the actual contract, also from memory. + +The term exceptional execution means an exception that causes the execution of the current contract to halt. + +## 9.2 Fees overview + +This section explains how the gas fees are calculated. There are three costs: + +### Opcode cost + +The inherent cost of the specific opcode. To get this value, find the cost group of the opcode in Appendix H (p. 28, under equation (327)), and find the cost group in equation (324). This gives you a cost function, which in most cases uses parameters from Appendix G (p. 27). + +For example, the opcode [`CALLDATACOPY`](https://www.evm.codes/#37) is a member of group _Wcopy_. The opcode cost for that group is _Gverylow+Gcopy×⌈μs[2]÷32⌉_. Looking at Appendix G, we see that both constants are 3, which gives us _3+3×⌈μs[2]÷32⌉_. + +We still need to decipher the expression _⌈μs[2]÷32⌉_. The outmost part, _⌈ \ ⌉_ is the ceiling function, a function that given a value returns the smallest integer that is still not smaller than the value. For example, _⌈2.5⌉ = ⌈3⌉ = 3_. The inner part is _μs[2]÷32_. Looking at section 3 (Conventions) on p. 3, _μ_ is the machine state. The machine state is defined in section 9.4.1 on p. 13. According to that section, one of the machine state parameters is _s_ for the stack. Putting it all together, it seems that _μs[2]_ is location #2 in the stack. Looking at [the opcode](https://www.evm.codes/#37), location #2 in the stack is the size of the data in bytes. Looking at the other opcodes in group Wcopy, [`CODECOPY`](https://www.evm.codes/#39) and [`RETURNDATACOPY`](https://www.evm.codes/#3e), they also have a size of data in the same location. So _⌈μs[2]÷32⌉_ is the number of 32 byte words required to store the data being copied. Putting everything together, the inherent cost of [`CALLDATACOPY`](https://www.evm.codes/#37) is 3 gas plus 3 per word of data being copied. + +### Running cost + +The cost of running the code we're calling. + +- In the case of [`CREATE`](https://www.evm.codes/#f0) and [`CREATE2`](https://www.evm.codes/#f5), the constructor for the new contract. +- In the case of [`CALL`](https://www.evm.codes/#f1), [`CALLCODE`](https://www.evm.codes/#f2), [`STATICCALL`](https://www.evm.codes/#fa), or [`DELEGATECALL`](https://www.evm.codes/#f4), the contract we call. + +### Expanding memory cost + +The cost of expanding memory (if necessary). + +In equation 324, this value is written as _Cmem(μi')-Cmem(μi)_. Looking at section 9.4.1 again, we see that _μi_ is the number of words in memory. So _μi_ is the number of words in memory before the opcode and _μi'_ is the number of words in memory after the opcode. + +The function _Cmem_ is defined in equation 326: _Cmem(a) = Gmemory × a + ⌊a2 ÷ 512⌋_. _⌊x⌋_ is the floor function, a function that given a value returns the largest integer that is still not larger than the value. For example, _⌊2.5⌋ = ⌊2⌋ = 2._ When _a 2 2 ÷ 512⌋_ is positive. When the memory required is high enough the gas cost is proportional to the square of the amount of memory. + +**Note** that these factors only influence the _inherent_ gas cost - it does not take into account the fee market or tips to validators that determine how much an end user is required to pay - this is just the raw cost of running a particular operation on the EVM. + +[Read more about gas](/developers/docs/gas/). + +## 9.3 Execution environment + +The execution environment is a tuple, _I_, that includes information that isn't part of the blockchain state or the EVM. + +| Parameter | Opcode to access the data | Solidity code to access the data | +| --------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| _Ia_ | [`ADDRESS`](https://www.evm.codes/#30) | `address(this)` | +| _Io_ | [`ORIGIN`](https://www.evm.codes/#32) | `tx.origin` | +| _Ip_ | [`GASPRICE`](https://www.evm.codes/#3a) | `tx.gasprice` | +| _Id_ | [`CALLDATALOAD`](https://www.evm.codes/#35), etc. | `msg.data` | +| _Is_ | [`CALLER`](https://www.evm.codes/#33) | `msg.sender` | +| _Iv_ | [`CALLVALUE`](https://www.evm.codes/#34) | `msg.value` | +| _Ib_ | [`CODECOPY`](https://www.evm.codes/#39) | `address(this).code` | +| _IH_ | Block header fields, such as [`NUMBER`](https://www.evm.codes/#43) and [`DIFFICULTY`](https://www.evm.codes/#44) | `block.number`, `block.difficulty`, etc. | +| _Ie_ | Depth of the call stack for calls between contracts (including contract creation) | +| _Iw_ | Is the EVM allowed to change state, or is it running statically | + +A few other parameters are necessary to understand the rest of section 9: + +| Parameter | Defined in section | Meaning | +| --------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| _σ_ | 2 (p. 2, equation 1) | The state of the blockchain | +| _g_ | 9.3 (p. 13) | Remaining gas | +| _A_ | 6.1 (p. 8) | Accrued substate (changes scheduled for when the transaction ends) | +| _o_ | 9.3 (p. 13) | Output - the returned result in the case of internal transaction (when one contract calls another) and calls to view functions (when you are just asking for information, so there is no need to wait for a transaction) | + +## 9.4 Execution overview + +Now that have all the preliminaries, we can finally start working on how the EVM works. + +Equations 137-142 give us the initial conditions for running the EVM: + +| Symbol | Initial value | Meaning | +| ---------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| _μg_ | _g_ | Gas remaining | +| _μpc_ | _0_ | Program counter, the address of the next instruction to execute | +| _μm_ | _(0, 0, ...)_ | Memory, initialized to all zeros | +| _μi_ | _0_ | Highest memory location used | +| _μs_ | _()_ | The stack, initially empty | +| _μo_ | _∅_ | The output, empty set until and unless we stop either with return data ([`RETURN`](https://www.evm.codes/#f3) or [`REVERT`](https://www.evm.codes/#fd)) or without it ([`STOP`](https://www.evm.codes/#00) or [`SELFDESTRUCT`](https://www.evm.codes/#ff)). | + +Equation 143 tells us there are four possible conditions at each point in time during execution, and what to do with them: + +1. `Z(σ,μ,A,I)`. Z represents a function that tests whether an operation creates an invalid state transition (see [exceptional halting](#942-exceptional-halting)). If it evaluates to True, the new state is identical to the old one (except gas gets burned) because the changes have not been implemented. +2. If the opcode being executed is [`REVERT`](https://www.evm.codes/#fd), the new state is the same as the old state, some gas is lost. +3. If the sequence of operations is finished, as signified by a [`RETURN`](https://www.evm.codes/#f3)), the state is updated to the new state. +4. If we aren't at one of the end conditions 1-3, continue running. + +## 9.4.1 Machine State + +This section explains the machine state in greater detail. It specifies that _w_ is the current opcode. If _μpc_ is less than _||Ib||_, the length of the code, then that byte (_Ib[μpc]_) is the opcode. Otherwise, the opcode is defined as [`STOP`](https://www.evm.codes/#00). + +As this is a [stack machine](https://en.wikipedia.org/wiki/Stack_machine), we need to keep track of the number of items popped out (_δ_) and pushed in (_α_) by each opcode. + +## 9.4.2 Exceptional Halting + +This section defines the _Z_ function, which specifies when we have an abnormal termination. This is a [Boolean](https://en.wikipedia.org/wiki/Boolean_data_type) function, so it uses [_∨_ for a logical or](https://en.wikipedia.org/wiki/Logical_disjunction) and [_∧_ for a logical and](https://en.wikipedia.org/wiki/Logical_conjunction). + +We have an exceptional halt if any of these conditions is true: + +- **_μg w=∅_** + If the number of items popped for an opcode is undefined, then the opcode itself is undefined. + +- **_|| μs || w_** + Stack underflow, not enough items in the stack for the current opcode. + +- **_w = JUMP ∧ μs[0]∉D(Ib)_** + The opcode is [`JUMP`](https://www.evm.codes/#56) and the address is not a [`JUMPDEST`](https://www.evm.codes/#5b). Jumps are _only_ valid when the destination is a [`JUMPDEST`](https://www.evm.codes/#5b). + +- **_w = JUMPI ∧ μs[1]≠0 ∧ μs[0] ∉ D(Ib)_** + The opcode is [`JUMPI`](https://www.evm.codes/#57), the condition is true (non zero) so the jump should happen, and the address is not a [`JUMPDEST`](https://www.evm.codes/#5b). Jumps are _only_ valid when the destination is a [`JUMPDEST`](https://www.evm.codes/#5b). + +- **_w = RETURNDATACOPY ∧ μs[1]+μs[2]>|| μo ||_** + The opcode is [`RETURNDATACOPY`](https://www.evm.codes/#3e). In this opcode stack element _μs[1]_ is the offset to read from in the return data buffer, and stack element _μs[2]_ is the length of data. This condition occurs when you try to read beyond the end of the return data buffer. Note that there isn't a similar condition for the calldata or for the code itself. When you try to read beyond the end of those buffers you just get zeros. + +- **_|| μs || - δw + αw > 1024_** + + Stack overflow. If running the opcode will result in a stack of over 1024 items, abort. + +- **_¬Iw ∧ W(w,μ)_** + Are we running statically ([¬ is negation](https://en.wikipedia.org/wiki/Negation) and _Iw_ is true when we are allowed to change the blockchain state)? If so, and we're trying a state changing operation, it can't happen. + + The function _W(w,μ)_ is defined later in equation 150. _W(w,μ)_ is true if one of these conditions is true: + + - **_w ∈ \_** + These opcodes change the state, either by creating a new contract, storing a value, or destroying the current contract. + + - **_LOG0≤w ∧ w≤LOG4_** + If we are called statically we cannot emit log entries. + The log opcodes are all in the range between [`LOG0` (A0)](https://www.evm.codes/#a0) and [`LOG4` (A4)](https://www.evm.codes/#a4). + The number after the log opcode specifies how many topics the log entry contains. + - **_w=CALL ∧ μs[2]≠0_** + You can call another contract when you're static, but if you do you cannot transfer ETH to it. + +- **_w = SSTORE ∧ μg ≤ Gcallstipend_** + You cannot run [`SSTORE`](https://www.evm.codes/#55) unless you have more than Gcallstipend (defined as 2300 in Appendix G) gas. + +## 9.4.3 Jump Destination Validity + +Here we formally define what are the [`JUMPDEST`](https://www.evm.codes/#5b) opcodes. We cannot just look for byte value 0x5B, because it might be inside a PUSH (and therefore data and not an opcode). + +In equation (153) we define a function, _N(i,w)_. The first parameter, _i_, is the opcode's location. The second, _w_, is the opcode itself. If _w∈[PUSH1, PUSH32]_ that means the opcode is a PUSH (square brackets define a range that includes the endpoints). If that case the next opcode is at _i+2+(w−PUSH1)_. For [`PUSH1`](https://www.evm.codes/#60) we need to advance by two bytes (the PUSH itself and the one byte value), for [`PUSH2`](https://www.evm.codes/#61) we need to advance by three bytes because it's a two byte value, etc. All other EVM opcodes are just one byte long, so in all other cases _N(i,w)=i+1_. + +This function is used in equation (152) to define _DJ(c,i)_, which is the [set]() of all valid jump destinations in code _c_, starting with opcode location _i_. This function is defined recursively. If _i≥||c||_, that means that we're at or after the end of the code. We are not going to find any more jump destinations, so just return the empty set. + +In all other cases we look at the rest of the code by going to the next opcode and getting the set starting from it. _c[i]_ is the current opcode, so _N(i,c[i])_ is the location of the next opcode. _DJ(c,N(i,c[i]))_ is therefore the set of valid jump destinations that starts at the next opcode. If the current opcode isn't a `JUMPDEST`, just return that set. If it is `JUMPDEST`, include it in the result set and return that. + +## 9.4.4 Normal halting + +The halting function _H_, can return three types of values. + +- If we aren't in a halt opcode, return _∅_, the empty set. By convention, this value is interpreted as Boolean false. +- If we have a halt opcode that doesn't produce output (either [`STOP`](https://www.evm.codes/#00) or [`SELFDESTRUCT`](https://www.evm.codes/#ff)), return a sequence of size zero bytes as the return value. Note that this is very different from the empty set. This value means that the EVM really did halt, just there's no return data to read. +- If we have a halt opcode that does produce output (either [`RETURN`](https://www.evm.codes/#f3) or [`REVERT`](https://www.evm.codes/#fd)), return the sequence of bytes specified by that opcode. This sequence is taken from memory, the value at the top of the stack (_μs[0]_) is the first byte, and the value after it (_μs[1]_) is the length. + +## H.2 Instruction set + +Before we go to the final subsection of the EVM, 9.5, let's look at the instructions themselves. They are defined in Appendix H.2 which starts on p. 29. Anything that is not specified as changing with that specific opcode is expected to stay the same. Variables that do change are specified with as \′. + +For example, let's look at the [`ADD`](https://www.evm.codes/#01) opcode. + +| Value | Mnemonic | δ | α | Description | +| ----: | -------- | --- | --- | --------------------------------------------------------- | +| 0x01 | ADD | 2 | 1 | Addition operation. | +| | | | | _μ′s[0] ≡ μs[0] + μs[1]_ | + +_δ_ is the number of values we pop from the stack. In this case two, because we are adding the top two values. + +_α_ is the number of values we push back. In this case one, the sum. + +So the new stack top (_μ′s[0]_) is the sum of the old stack top (_μs[0]_) and the old value below it (_μs[1]_). + +Instead of going over all the opcodes with an "eyes glaze over list", This article explains only those opcodes that introduce something new. + +| Value | Mnemonic | δ | α | Description | +| ----: | --------- | --- | --- | ---------------------------------------------------------------------------------------------------------- | +| 0x20 | KECCAK256 | 2 | 1 | Compute Keccak-256 hash. | +| | | | | _μ′s[0] ≡ KEC(μm[μs[0] . . . (μs[0] + μs[1] − 1)])_ | +| | | | | _μ′i ≡ M(μi,μs[0],μs[1])_ | + +This is the first opcode that accesses memory (in this case, read only). However, it might expand beyond the current limits of the memory, so we need to update _μi._ We do this using the _M_ function defined in equation 328 on p. 29. + +| Value | Mnemonic | δ | α | Description | +| ----: | -------- | --- | --- | --------------------------------- | +| 0x31 | BALANCE | 1 | 1 | Get balance of the given account. | +| | | | | ... | + +The address whose balance we need to find is _μs[0] mod 2160_. The top of the stack is the address, but because addresses are only 160 bits, we calculate the value [modulo](https://en.wikipedia.org/wiki/Modulo_operation) 2160. + +If _σ[μs[0] mod 2160] ≠ ∅_, it means that there is information about this address. In that case, _σ[μs[0] mod 2160]b_ is the balance for that address. If _σ[μs[0] mod 2160] = ∅_, it means that this address is uninitialized and the balance is zero. You can see the list of account information fields in section 4.1 on p. 4. + +The second equation, _A'a ≡ Aa ∪ \_, is related to the difference in cost between access to warm storage (storage that has recently been accessed and is likely to be cached) and cold storage (storage that hasn't been accessed and is likely to be in slower storage that is more expensive to retrieve). _Aa_ is the list of addresses previously accessed by the transaction, which should therefore be cheaper to access, as defined in section 6.1 on p. 8. You can read more about this subject in [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929). + +| Value | Mnemonic | δ | α | Description | +| ----: | -------- | --- | --- | --------------------------------------- | +| 0x8F | DUP16 | 16 | 17 | Duplicate 16th stack item. | +| | | | | _μ′s[0] ≡ μs[15]_ | + +Note that to use any stack item, we need to pop it, which means we also need to pop all the stack items on top of it. In the case of [`DUP`](https://www.evm.codes/#8f) and [`SWAP`](https://www.evm.codes/#9f), this means having to pop and then push up to sixteen values. + +## 9.5 The execution cycle + +Now that we have all the parts, we can finally understand how the execution cycle of the EVM is documented. + +Equation (155) says that given the state: + +- _σ_ (global blockchain state) +- _μ_ (EVM state) +- _A_ (substate, changes to happen when the transaction ends) +- _I_ (execution environment) + +The new state is _(σ', μ', A', I')_. + +Equations (156)-(158) define the stack and the change in it due to an opcode (_μs_). Equation (159) is the change in gas (_μg_). Equation (160) is the change in the program counter (_μpc_). Finally, equations (161)-(164) specify that the other parameters stay the same, unless explicitly changed by the opcode. + +With this the EVM is fully defined. + +## Conclusion + +Mathematical notation is precise and has allowed the Yellow Paper to specify every detail of Ethereum. However, it does have some drawbacks: + +- It can only be understood by humans, which means that [compliance tests](https://github.com/ethereum/tests) must be written manually. +- Programmers understand computer code. + They may or may not understand mathematical notation. + +Maybe for these reasons, the newer [consensus layer specs](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/README.md) are written in Python. There are [execution layer specs in Python](https://ethereum.github.io/execution-specs), but they are not complete. Until and unless the entire Yellow Paper is also translated to Python or a similar language, the Yellow Paper will continue in service, and it is helpful to be able to read it. + +--- + +# Eips + +## Eips + +# Introduction to Ethereum Improvement Proposals (EIPs) + +## What are EIPs? + +[Ethereum Improvement Proposals (EIPs)](https://eips.ethereum.org/) are standards specifying potential new features or processes for Ethereum. EIPs contain technical specifications for the proposed changes and act as the “source of truth” for the community. Network upgrades and application standards for Ethereum are discussed and developed through the EIP process. + +Anyone within the Ethereum community has the ability to create an EIP. Guidelines for writing EIPs are included in [EIP-1](https://eips.ethereum.org/EIPS/eip-1). An EIP should primarily provide a concise technical specification with a small amount of motivation. The EIP author is responsible for reaching consensus within the community and documenting alternative opinions. Given the high technical barrier for submitting a well-formed EIP, historically, most EIP authors are typically application or protocol developers. + +## Why do EIPs matter? + +EIPs play a central role in how changes happen and are documented on Ethereum. They are the way for people to propose, debate, and adopt changes. There are [different types of EIPs](https://eips.ethereum.org/EIPS/eip-1#eip-types), including core EIPs for low-level protocol changes that affect consensus and require a network upgrade like [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), and ERCs for application standards like [EIP-20](https://eips.ethereum.org/EIPS/eip-20) and [EIP-721](https://eips.ethereum.org/EIPS/eip-721). + +Every network upgrade consists of a set of EIPs that need to be implemented by each [Ethereum client](/learn/#clients-and-nodes) on the network. This means that to stay in consensus with other clients on the Ethereum Mainnet, client developers need to make sure they have all implemented the required EIPs. + +Along with providing a technical specification for changes, EIPs are the unit around which governance happens in Ethereum: anyone is free to propose one, and then various stakeholders in the community will debate to determine if it should be adopted as a standard or included in a network upgrade. Because non-core EIPs don't have to be adopted by all applications (for example, it is possible to create a fungible token that doesn't implement EIP-20), but core EIPs must be widely adopted (because all nodes must upgrade to stay part of the same network), core EIPs require a broader consensus within the community than non-core EIPs. + +## History of EIPs + +The [Ethereum Improvement Proposals (EIPs) GitHub repository](https://github.com/ethereum/EIPs) was created in October 2015. The EIP process is based on the [Bitcoin Improvement Proposals (BIPs)](https://github.com/bitcoin/bips) process, which itself is based on the [Python Enhancement Proposals (PEPs)](https://www.python.org/dev/peps/) process. + +EIP editors are tasked with process of reviewing EIPs for technical soundness, formatting issues, and correcting spelling, grammar, and code style. Martin Becze, Vitalik Buterin, Gavin Wood, and a few others were the original EIP editors from 2015 to late 2016. + +The current EIP editors are + +- Alex Beregszaszi (@axic) +- Gavin John (@Pandapip1) +- Greg Colvin (@gcolvin) +- Matt Garnett (@lightclient) +- Sam Wilson (@SamWilsn) + +Emeritus EIP editors are + +- Casey Detrio (@cdetrio) +- Hudson Jameson (@Souptacular) +- Martin Becze (@wanderer) +- Micah Zoltu (@MicahZoltu) +- Nick Johnson (@arachnid) +- Nick Savers (@nicksavers) +- Vitalik Buterin (@vbuterin) + +If you would like to become an EIP editor, please check [EIP-5069](https://eips.ethereum.org/EIPS/eip-5069). + +EIP editors decide when a proposal is ready to become an EIP, and help EIP authors move their proposals forward. [Ethereum Cat Herders](https://www.ethereumcatherders.com/) help organize meetings between the EIP editors and the community (see [EIPIP](https://github.com/ethereum-cat-herders/EIPIP)). + +Full standardization process alongside with chart is described in [EIP-1](https://eips.ethereum.org/EIPS/eip-1) + +## Learn more + +If you’re interested to read more about EIPs, check out the [EIPs website](https://eips.ethereum.org/) and [EIP-1](https://eips.ethereum.org/EIPS/eip-1). Here are some useful links: + +- [A list of every Ethereum Improvement Proposal](https://eips.ethereum.org/all) +- [A description of all EIP types](https://eips.ethereum.org/EIPS/eip-1#eip-types) +- [A description of all EIP statuses](https://eips.ethereum.org/EIPS/eip-1#eip-process) + +### Community education projects + +- [PEEPanEIP](https://www.youtube.com/playlist?list=PL4cwHXAawZxqu0PKKyMzG_3BJV_xZTi1F) — *PEEPanEIP is an educational video series that discusses Ethereum Improvement Proposal (EIPs) and key features of upcoming upgrades.* +- [EIPs For Nerds](https://ethereum2077.substack.com/t/eip-research) — *EIPs For Nerds provides comprehensive, ELI5-style overviews of various Ethereum Improvement Proposals (EIPs), including core EIPs and application/infrastructure-layer EIPs (ERCs), to educate readers and shape consensus around proposed changes to the Ethereum protocol.* +- [EIPs.wtf](https://www.eips.wtf/) — *EIPs.wtf provides extra information for Ethereum Improvement Proposals (EIPs), including their status, implementation details, related pull requests, and community feedback.* +- [EIP.Fun](https://eipfun.substack.com/) — *EIP.Fun provides the latest news on Ethereum Improvement Proposals (EIPs), updates on EIP meetings, and more.* +- [EIPs Insight](https://eipsinsight.com/) — *EIPs Insight is a representation of state of Ethereum Improvement Proposals (EIPs) process & statistics as per information collected from different resources.* + +## Participate + +Anyone can create an EIP. Before submitting a proposal, one must read [EIP-1](https://eips.ethereum.org/EIPS/eip-1) which outlines the EIP process and how to write an EIP, and solicit feedback on [Ethereum Magicians](https://ethereum-magicians.org/), where proposals are first discussed with the community before a draft is submitted. + +## References + + + +Page content provided in part from [Ethereum Protocol Development Governance and Network Upgrade Coordination](https://hudsonjameson.com/2020-03-23-ethereum-protocol-development-governance-and-network-upgrade-coordination/) by Hudson Jameson + +--- + +# Energy Consumption + +## Energy Consumption + +# Ethereum's energy expenditure + +Ethereum is a green blockchain. Ethereum's [proof-of-stake](/developers/docs/consensus-mechanisms/pos) consensus mechanism uses ETH instead of [energy to secure the network](/developers/docs/consensus-mechanisms/pow). Ethereum's energy consumption is approximately [~0.0026 TWh/yr](https://carbon-ratings.com/eth-report-2022) across the entire global network. + +The energy consumption estimate for Ethereum comes from a [CCRI (Crypto Carbon Ratings Institute)](https://carbon-ratings.com) study. They generated bottom-up estimates of the electricity consumption and carbon footprint of the Ethereum network ([see the report](https://carbon-ratings.com/eth-report-2022)). They measured the electricity consumption of different nodes with various hardware and client software configurations. The estimated **2,601 MWh** (0.0026 TWh) for the network’s annual electricity consumption corresponds to yearly carbon emissions of **870 tonnes CO2e** applying regional-specific carbon intensity factors. This value changes as nodes enter and leave the network - you can keep track using a rolling 7-day average estimate by the [Cambridge Blockchain network Sustainability Index](https://ccaf.io/cbnsi/ethereum) (note that they use a slightly different method for their estimates - details available on their site). + +To contextualize Ethereum's energy consumption, we can compare annualized estimates for some other products and industries. This helps us better understand whether the estimate for Ethereum is high or low. + + + +The chart above displays the estimated energy consumption in TWh/yr for Ethereum, compared to several other products and industries. The estimates provided are sourced from publicly available information, accessed in July 2023, with links to the sources available in the table below. + +| | Annualized energy consumption (TWh) | Comparison to PoS Ethereum | Source | +| :------------------ | :---------------------------------: | :------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| Global data centers | 190 | 73,000x | [source](https://www.iea.org/commentaries/data-centres-and-energy-from-global-headlines-to-local-headaches) | +| Bitcoin | 149 | 53,000x | [source](https://ccaf.io/cbnsi/cbeci/comparisons) | +| Gold mining | 131 | 50,000x | [source](https://ccaf.io/cbnsi/cbeci/comparisons) | +| Gaming in USA\* | 34 | 13,000x | [source](https://www.researchgate.net/publication/336909520_Toward_Greener_Gaming_Estimating_National_Energy_Use_and_Energy_Efficiency_Potential) | +| PoW Ethereum | 21 | 8,100x | [source](https://ccaf.io/cbnsi/ethereum/1) | +| Google | 19 | 7,300x | [source](https://www.gstatic.com/gumdrop/sustainability/google-2022-environmental-report.pdf) | +| Netflix | 0.457 | 176x | [source](https://assets.ctfassets.net/4cd45et68cgf/7B2bKCqkXDfHLadrjrNWD8/e44583e5b288bdf61e8bf3d7f8562884/2021_US_EN_Netflix_EnvironmentalSocialGovernanceReport-2021_Final.pdf) | +| PayPal | 0.26 | 100x | [source]() | +| AirBnB | 0.02 | 8x | [source]() | +| **PoS Ethereum** | **0.0026** | **1x** | [source](https://carbon-ratings.com/eth-report-2022) | + +\*Includes end user devices such as PCs, laptops, and gaming consoles. + +Getting accurate estimates for energy consumption is complicated, especially when what is being measured has a complex supply chain or deployment details that influence its efficiency. For example, estimates of energy consumption for Netflix and Google vary depending upon whether they only include the energy used to maintain their systems and deliver content to users (_direct expenditure_) or whether they include the expenditure required to produce content, run corporate offices, advertise, etc (_indirect expenditure_). Indirect expenditure could also include the energy required to consume content on end-user devices such as TVs, computers and mobiles. + +The estimates above are not perfect comparisons. The amount of indirect expenditure that is accounted for varies by source, and rarely includes the energy from end-user devices. Each underlying source includes more details on what is being measured. + +The table and chart above also include comparisons to Bitcoin and proof-of-work Ethereum. It is important to note that the energy consumption of proof-of-work networks is not static and changes day-to-day. Estimates can also vary widely between sources. The topic attracts nuanced [debate](https://www.coindesk.com/business/2020/05/19/the-last-word-on-bitcoins-energy-consumption/), not only about the amount of energy consumed, but also about the sources of that energy and the related ethics. Energy consumption does not necessarily map precisely to environmental footprint because different projects might use different energy sources, including a lesser or greater proportion of renewables. For example, [Cambridge Bitcoin Electricity Consumption Index](https://ccaf.io/cbnsi/cbeci/comparisons) indicates that the Bitcoin network demand could theoretically be powered by gas flaring or electricity that would otherwise be lost in transmission and distribution. Ethereum's route to sustainability was to replace the energy-hungry part of the network with a green alternative. + +You can browse energy consumption and carbon emission estimates for many industries on the [Cambridge Blockchain Network Sustainability Index site](https://ccaf.io/cbnsi/ethereum). + +## Per-transaction estimates + +Many articles estimate "per-transaction" energy expenditure for blockchains. This can be misleading because the energy required to propose and validate a block is independent of the number of transactions within it. A per-transaction unit of energy expenditure implies that fewer transactions would lead to smaller energy expenditure and vice-versa, which is not the case. Also, per-transaction estimates are very sensitive to how a blockchain's transaction throughput is defined, and tweaking this definition can be gamed to make the value seem larger or smaller. + +On Ethereum, for example, the transaction throughput is not only that of the base layer - it is also the sum of the transaction throughput of all of its "[layer 2](/layer-2/)" rollups. Layer 2's are not generally included in calculations, but accounting for the additional energy consumed by sequencers (small) and the number of transactions they process (large) would likely drastically reduce per-transaction estimates. This is one reason why comparisons of per-transaction energy consumption across platforms can be misleading. + +## Ethereum's carbon debt + +Ethereum's energy expenditure is very low, but this has not always been the case. Ethereum originally used proof-of-work which had a much greater environmental cost than the current proof-of-stake mechanism. + +From the very beginning, Ethereum planned to implement a proof-of-stake based consensus mechanism, but doing so without sacrificing security and decentralization took years of focused research and development. Therefore, a proof-of-work mechanism was used to get the network started. Proof-of-work requires miners to use their computing hardware to calculate a value, expending energy in the process. + +![Comparing Ethereum's energy consumption pre- and post-Merge, using the Eiffel Tower (330 meters tall) on the left to symbolize the high energy consumption before The Merge, and a small 4 cm tall Lego figure on the right to represent the dramatic reduction in energy usage after The Merge](energy_consumption_pre_post_merge.png) + +CCRI estimates that The Merge reduced Ethereum's annualized electricity consumption by more than **99.988%**. Likewise, Ethereum’s carbon footprint was decreased by approximately **99.992%** (from 11,016,000 to 870 tonnes CO2e). To put this in perspective, the reduction in emissions is like going from the height of the Eiffel Tower to a small plastic toy figure, as illustrated in the figure above. As a result, the environmental cost of securing the network is drastically reduced. At the same time, the network's security is believed to have improved. + +## A green application layer + +While Ethereum's energy consumption is very low, there is also a substantial, growing, and highly active [**regenerative finance (ReFi)**](/refi/) community building on Ethereum. ReFi applications use DeFi components to build financial applications that have positive externalities benefiting the environment. ReFi is part of a wider ["solarpunk"](https://en.wikipedia.org/wiki/Solarpunk) movement that is closely aligned with Ethereum and aims to couple technological advancement and environmental stewardship. The decentralized, permissionless, and composable nature of Ethereum makes it the ideal base layer for the ReFi and solarpunk communities. + +Web3 native public goods funding platforms such as [Gitcoin](https://gitcoin.co) run climate rounds to stimulate environmentally conscious building on Ethereum's application layer. Through the development of these initiatives (and others, e.g. [DeSci](/desci/)), Ethereum is becoming an environmentally and socially net-positive technology. + + + If you think this page can be made more accurate, please raise an issue or PR. The stats on this page are estimates based on publicly available data - they do not represent an official statement or promise from the ethereum.org team, or the Ethereum Foundation. + + +## Further reading + +- [Cambridge Blockchain Network Sustainability Index](https://ccaf.io/cbnsi/ethereum) +- [White House report on proof-of-work blockchains](https://www.whitehouse.gov/wp-content/uploads/2022/09/09-2022-Crypto-Assets-and-Climate-Report.pdf) +- [Ethereum Emissions: A Bottom-up Estimate](https://kylemcdonald.github.io/ethereum-emissions/) - _Kyle McDonald_ +- [Ethereum Energy Consumption Index](https://digiconomist.net/ethereum-energy-consumption/) - _Digiconomist_ +- [ETHMerge.com](https://ethmerge.com/) - _[@InsideTheSim](https://twitter.com/InsideTheSim)_ +- [The Merge - Implications on the Electricity Consumption and Carbon Footprint of the Ethereum Network](https://carbon-ratings.com/eth-report-2022) - _CCRI_ +- [Ethereum's energy consumption](https://mirror.xyz/jmcook.eth/ODpCLtO4Kq7SCVFbU4He8o8kXs418ZZDTj0lpYlZkR8) + +## Related topics + +- [Ethereum's vision](/roadmap/vision/) +- [The Beacon Chain](/roadmap/beacon-chain) +- [The Merge](/roadmap/merge/) + +--- + +# Enterprise + +## Enterprise > Use Cases + +# Enterprise use cases on Ethereum Mainnet + +Ethereum can help many kinds of businesses, including large companies: + +- Increase trust and reduce the cost of coordination between business parties +- Improve business network accountability and operational efficiency +- Build new business models and value creation opportunities +- Competitively future-proof their organization + + +Get in touch + + +## Enterprise applications built on Ethereum + +Here are some of the enterprise applications that have been built on top of the public Ethereum Mainnet and L2s by and for traditional, non-blockchain based companies. + +### Payments + +- [Brave Browser](https://basicattentiontoken.org/) - _pays users for their attention to advertisements and users can pay publishers to support them, via the Basic Attention Token_ +- [EthereumAds](https://ethereumads.com/) - _lets web site operators sell advertising space and get paid via Ethereum_ +- [hCaptcha](https://www.hcaptcha.com/) - _Bot prevention CAPTCHA system which pays web site operators for the work done by users to label data for machine learning. Now deployed by Cloudflare_ +- [Opera MiniPay](https://www.opera.com/products/minipay) - _makes mobile payments more accessible and secure for people in Africa with a non-custodial wallet and leverages phone numbers for easy transactions_ +- [Roxpay](https://www.roxpay.ch/) - _automates pay-per-use asset invoicing and payments_ +- [SAP Digital Currency Hub](https://community.sap.com/t5/technology-blogs-by-sap/cross-border-payments-made-easy-with-digital-money-experience-the-future/ba-p/13560384) - _cross border payments with stablecoins_ +- [Toku](https://www.toku.com/) - _payroll, token grant administration, tax compliance, local employment, benefits & distributed HR solutions_ +- [Xerof](https://www.xerof.com/) - _facilitates fast and inexpensive international (cross-border) B2B payments_ + +### Finance + +- [ABN AMRO](https://tokeny.com/tokeny-fuels-abn-amro-bank-in-tokenizing-green-bonds-on-polygon/) - _with Tokeny, tokenized green bonds_ +- [Anvil](https://anvil.xyz/) - _a system of Ethereum-based smart contracts that manages collateral and issues fully secured credit_ +- [Mata Capital](https://consensys.io/blockchain-use-cases/finance/mata-capital) - _real estate investment tokenization_ +- [Obligate](https://www.obligate.com/) - _regulated and KYC'd onchain bonds and commercial paper_ +- [Siemens](https://press.siemens.com/global/en/pressrelease/siemens-remains-pioneer-another-digital-bond-successfully-issued-blockchain) - _bond issuance_ +- [Sila](https://silamoney.com/) - _banking and ACH payments infrastructure-as-a-service, using a stablecoin_ +- [Societe Generale FORGE](https://www.sgforge.com/product/bonds/) - _bond issuance_ +- [Taurus](https://www.taurushq.com/) - _issues tokenized securities_ +- [Visa Tokenized Asset Platform](https://developer.visa.com/capabilities/visa-tokenized-asset-platform) - _provides the tools and infrastructure for banks to tokenize fiat currencies on blockchain networks_ + +### Asset tokenization + +- [AgroToken](https://agrotoken.io/en/) - _tokenizing and trading agricultural commodities_ +- [Bitbond](https://www.bitbond.com/) - _improves the issuance, settlement and custody of financial assets with tokenization_ +- [Blocksquare](https://blocksquare.io/) - _tokenization infrastructure for real estate_ +- [Centrifuge](https://centrifuge.io/) - _tokenized receivables financing, debt, and assets_ +- [Clearmatics](https://www.clearmatics.com) - _builds decentralised network platforms for the p2p exchange of tokenised value_ +- [dClimate](https://www.dclimate.net/) - _decentralized climate information ecosystem_ +- [Fabrica](https://www.fabrica.land/) - _a platform for digitizing real estate assets, enabling DeFi borrowing and property trading_ +- [Propy](https://propy.com/) - _a platform to automate residential real estate transactions with smart contracts_ +- [RealT](https://realt.co/) - _investors around the globe can buy into the US real estate market through fully-compliant, fractional, tokenized ownership_ +- [Rubey](https://www.rubey.be/) - _a platform that tokenizes high-end art to make it accessible to retail investors_ +- [Swarm](https://swarm.com/) - _a platform focused on the digitization and trading of real-world assets in a regulatory compliant manner_ +- [Thallo](https://www.thallo.io/) - _a platform to integrate digital carbon credits into business transactions_ +- [Tokenchampions](https://tokenchampions.com/) - _tokenizes European football players' image rights_ + +### Notarization of data + +- [ANSA](https://www.ansa.it/english/news/science_tecnology/2020/04/06/ansa-using-blockchain-to-help-readers_af820b4f-0947-439b-843e-52e114f53318.html) - _Italian news agency fights fake news and enables readers to verify the origin of news stories by recording them on Mainnet_ +- [Breitling](https://www.breitling.com/us-en/about/digital-passport/) - _records provenance and repair history of watches on Ethereum_ +- [BRØK](https://www.xn--brk-1na.no/) - _a cap tables platform for unlisted companies on the public, provided by The Norwegian Government_ +- [Certifaction](https://certifaction.com/) - _legally valid eSignatures with by privacy-by-design_ +- [EthSign](https://ethsign.xyz/) - _records signed electronic documents on the Ethereum blockchain_ +- [Stacktical](https://stacktical.com/) - _enables the software development, digital issuance and digital signature of Service Level Agreements (SLA) with native escrowing capabilities_ +- [Verizon Full Transparency](https://www.verizon.com/about/news/transparency-technology) - _logs press releases to ensure corporate accountability and trust_ +- [Verify](https://www.verifymedia.com/) - _by Fox Corporation stores hashes of media content on a Layer 2 to facilitate content licensing and combating deepfakes_ +- [WolfTown](https://www.mef.net/edge-view-blog/automated-secure-timely-sla-reporting-is-finally-a-reality/) - _by MEF and Sage Management automates Service Level Agreement reporting between telecom carriers_ + +### Supply chain + +- [CargoX](https://cargox.io/) - _electronic bill of lading and document transfer provider for shipping_ +- [Circularize](https://www.circularise.com/) - _an end-to-end traceability solution for raw materials made into products_ +- [EY OpsChain Contract Manager](https://blockchain.ey.com/) - _enables companies to engage in a procurement workflow by issuing RFQ’s, contracts, purchase orders, and invoices across a network of business partners_ +- [Global Battery Passport project](https://dlt.mobi/gbp-mvp/) _uses DIDs anchored on Ethereum through MOBI's Integrated Trust Network to track EV batteries, for compliance with EU regulations_ +- [Minespider](https://www.minespider.com/) - _supply chain tracking and provenance, and CO2 emissions tracking_ +- [Morpheus.network](https://morpheus.network/) - _supply chain automation platform_ +- [StaTwig](https://statwig.com/) - _supply chain operations_ +- [TradeTrust](https://www.tradetrust.io/) - _verifies electronic Bills of Lading (eBLs) for international shipping_ +- [Tradeverifyd](https://tradeverifyd.com/) - _data exchange platform for global trade; supports Transactions with Decentralized Identity on Ethereum_ + +### Insurance + +- [Arbol](https://www.arbolmarket.com/) - _parmetric insurance to cover weather related risks_ +- [Etherisc](https://etherisc.com/) - _decentralized insurance for a variety of risks_ +- [Nayms](https://www.nayms.com/) - _a digital space for the creation of insurance programs, the raising and trading of capital, the writing of risk, and the payment rails for premium and claim transactions, built with AON_ + +### Identity, credentials and certifications + +- [BCdiploma](https://www.bcdiploma.com/) - _digitizes and verifies diplomas, certificates, and micro-credentials_ +- [Bhutan National Digital Identity](https://www.bhutanndi.com/) - \_a foundation for Bhutan’s digital economy, facilitating trusted interactions between individuals and organizations +- [Hyland Credentials](https://www.hylandcredentials.com) - _digital diplomas and other education credentials, licenses, and certificates_ +- [Palau Digital Residency Program](https://rns.id/) - _offers global citizens the ability to have a legal Palau government-issued ID_ +- [QuarkID](https://quarkid.org/) _is a self-soverign identity protocol for managing essential personal documents such as birth and marriage certificates, academic credentials, and proof of income, developed by the government of Buenos Aires for use in Argentina and other South American countries_ +- [Spherity](https://www.spherity.com/) - _offers digital identity management solutions to establish digital trust in ecosystems, focusing on decentralized identities and verifiable credentials_ +- [Zug Digital ID](https://ezug.ch/en/) - _is a blockchain-based identity system in Switzerland, offering residents digital access to government services and supporting functionalities like e-bike borrowing and municipal voting_ + +### Entertainment, NFTs, and Loyalty + +- [The British Museum's Sandbox](https://decrypt.co/150405/british-museum-enter-metaverse-via-sandbox) - _an NFT collection_ +- [Fruitlab](https://fruitlab.com/) - _a platform for gamers to earn from watching, sharing and playing online games_ +- [Lamborghini](https://venturebeat.com/games/lamborghini-and-animocas-motorverse-tap-base-blockchain-for-in-game-assets/) - _creates in-game assets for Animoca’s Web3 racing game Motorverse_ +- [Nike Swoosh](https://www.swoosh.nike/) - _an NFT platform_ +- [Sothbebys Metaverse](https://metaverse.sothebys.com/) - _a digital art NFT marketplace by Sothebys_ +- [Soneium](https://soneium.org/) - \_a Layer 2 by Sony to support Web3 games and NFTs + +If you would like to add to this list, please see [instructions for contributing](/contributing/). + +## Enterprise developer resources + +### Scalability solutions + +Most new blockchain applications are being built on [Layer 2](/layer-2) chains. Layer 2 is a set of technologies or systems that run on top of Ethereum (Layer 1), inherit security properties from Layer 1, and provide greater transaction processing capacity (throughput), lower transaction fees (operating cost), and faster transaction confirmations than Layer 1. Layer 2 scaling solutions are secured by Layer 1, but they enable blockchain applications to handle many more users or actions or data than Layer 1 could accommodate. Many of them leverage recent advances in cryptography and zero-knowledge (ZK) proofs to maximize performance and security, and some offer an additional level of privacy. + +[L2 Beat](https://l2beat.com/scaling/summary) maintains an up to date list of Layer 2 networks and key metrics. + +### Products, services, and tools + +- [4EVERLAND](https://www.4everland.org/) - _provides APIs, RPC services and tools for hosting decentralized applications and enabling decentralized storage on Ethereum_ +- [Alchemy](https://www.alchemy.com/) - _provides API services and tools for building and monitoring applications on Ethereum_ +- [Baseline Project](https://www.baseline-protocol.org/) - _a set of tools and libraries that helps enterprises coordinate complex, multi-party business processes and workflows with privacy while keeping data in respective systems of record. The standard enables two or more state machines to achieve and maintain data consistency and workflow continuity by using a network as a common frame of reference._ +- [Blast](https://blastapi.io/) - _an API platform that provides RPC/WSS APIs for Ethereum Archive Mainnet and Testnets._ +- [Blockapps](https://blockapps.net/) - _implementation of the Enterprise Ethereum protocol, tooling and APIs that form the STRATO platform_ +- [Chainlens](https://www.chainlens.com/) - _SaaS and on-prem blockchain data and analytics platform from Web3 Labs_ +- [Chainstack](https://chainstack.com/) - _mainnet and testnet Ethereum infrastructure hosted in public & isolated customer clouds_ +- [ConsenSys](https://consensys.io/) - _provides a range of products and tools for building on Ethereum, as well as consulting and custom development services_ +- [Crossmint](http://crossmint.com/) _Enterprise-grade web3 development platform to deploy smart contracts, enable credit-card and cross chain payments, and use APIs to create, distribute, sell, store, and edit NFTs._ +- [Envision Blockchain](https://envisionblockchain.com/) - _provides enterprise focused consulting and development services specializing in Ethereum Mainnet_ +- [EY OpsChain](https://blockchain.ey.com/products/contract-manager) - _provides a procurement workflow by issuing RFQ’s, contracts, purchase orders, and invoices across your network of trusted business partners_ +- [Hyperledger Besu](https://www.hyperledger.org/use/besu) - _an enterprise focused open-source Ethereum client developed under the Apache 2.0 license and written in Java_ +- [Infura](https://infura.io/) - _scalable API access to the Ethereum and IPFS networks_ +- [Kaleido](https://kaleido.io/) - _an enterprise-focused development platform that offers simplified blockchain and digital asset applications_ +- [Moralis](http://moralis.io/) - _enterprise grade APIs and Nodes with a SOC2 type 2 certification_ +- [Nightfall](https://github.com/EYBlockchain/nightfall_3) - _an application for transferring ERC20, ERC721 and ERC1155 applications under Zero Knowledge, using an Optimistic Rollup, from Ernst & Young_ +- [NodeReal](https://nodereal.io/) - _provides scalable blockchain infrastructure and API services provider for the Web3 ecosystem_ +- [QuickNode](https://www.quicknode.com/) - _provides reliable and fast nodes with high-level APIs like NFT API, Token API, etc., while delivering a unified product suite and enterprise-grade solutions_ +- [Tenderly](https://tenderly.co) - _a Web3 development platform that provides debugging, observability, and infrastructure building blocks for developing, testing, monitoring, and operating smart contracts_ +- [Unibright](https://unibright.io/) - _a team of blockchain specialists, architects, developers and consultants with 20+ years of experience in business processes and integration_ +- [Zeeve](https://www.zeeve.io/) - _provides a range of products and tools for building on Ethereum, also infrastructure and APIs for Enterprise Web3 applications._ + +## Resources + +### Further reading + +Non-technical resources for understanding how businesses can benefit from Ethereum + +- [Why Are Blockchains Useful For Business?](https://entethalliance.org/why-are-blockchains-useful-for-business/) - _Discusses the value of blockchains through the lens of predictability_ +- [Enterprise Ethereum Alliance 2023 Business Readiness Report](https://entethalliance.org/eea-ethereum-business-readiness-report-2023/) - _surveys the potential and capabilities of public Ethereum and the broader Ethereum ecosystem for businesses_ +- [_Ethereum for Business_ by Paul Brody](https://www.uapress.com/product/ethereum-for-business/) - _is a plain-English guide to the use cases that generate returns from asset management to payments to supply chains_ + +### Organizations + +Some collaborative efforts to make Ethereum enterprise friendly have been made by different organizations + +- [Enterprise Ethereum Alliance](https://entethalliance.org/) - The EEA helps organizations to adopt and use Ethereum technology in their daily business operations. Its goal is accelerating business Ethereum through professional and commercial support, advocacy and research, standards development and ecosystem trust services. +- [Global Blockchain Business Council](https://www.gbbc.io/) - The GBBC is an industry association for the blockchain technology ecosystem. Through engaging policymakers and regulators, curating events and in-depth discussions, and driving research, GBBC is dedicated to further adoption of blockchain to create more secure, equitable, and functional societies. + + + + + Get in touch + +--- + +# Eth + +## Eth > Supply + +# ETH Supply and Issuance + +## Prerequisites + +This article is written for beginners with no prior knowledge. However, to fully understand the topic, it is helpful to have a basic understanding of concepts such as [Ethereum Improvement Proposals (EIPs)](/eips/#introduction-to-ethereum-improvement-proposals), [Proof-of-work (PoW)](/developers/docs/consensus-mechanisms/pow/), [Proof-of-stake (PoS)](/developers/docs/consensus-mechanisms/pos/), and [The London Upgrade](/history/#london). + +## How Many ETH Tokens Are There Today? + +The total supply of ETH is dynamic and changes constantly due to two main factors: + +1. **Proof-of-Stake (PoS) Issuance**: New ETH is created as rewards for validators who secure the network +2. **EIP-1559 Burning**: A portion of transaction fees are permanently removed from circulation + +You can track the current supply and these changes in real-time on platforms like [Ultrasound Money](https://ultrasound.money). + +Ethereum's supply and issuance are essential metrics for understanding the health and future of the network. But what exactly does ETH issuance mean? Let's break it down. + +## Why ETH Supply and Issuance Matter + +In traditional finance, central banks control the supply of money, often printing more to stimulate economies. Ethereum, on the other hand, operates on a transparent and predictable system governed by its code. Knowing how many ETH exist and how quickly new ETH is issued helps: + +- **Build Trust**: The Ethereum community can verify supply and issuance data directly from the blockchain. +- **Understand Value**: The relationship between issuance and ETH burn rates impacts ETH's inflation or deflation, influencing its value over time. +- **Track Network Health**: Changes in issuance and burn rates reflect the activity and security of the network. + +## What is ETH Issuance? + +ETH issuance refers to the process of creating new ETH as rewards for validators who secure the Ethereum network. It's separate from total supply, which is the total amount of ETH in circulation. + +### In simple terms: +- **Issuance** adds new ETH to the network. +- **Burning** (introduced by EIP-1559) removes ETH from the network by destroying a portion of the transaction fees. + +These two forces determine whether Ethereum's supply grows (inflationary) or shrinks (deflationary) over time. + +## ETH Supply and Issuance Today + +Ethereum's Proof-of-Stake (PoS) system has drastically reduced ETH issuance compared to its earlier Proof-of-Work (PoW) model. Validators—who lock up ETH to secure the network—earn ETH as rewards. You can see the current issuance rate on [Ultrasound Money](https://ultrasound.money). + +However, this number is dynamic. Thanks to EIP-1559, when network activity is high, ETH burn rates can surpass issuance, creating a deflationary effect. For example, during periods of high demand, like NFT launches or DeFi activity, more ETH may be burned than issued. + +### Tools to Track ETH Supply and Issuance: +- [Ultrasound Money](https://ultrasound.money) - Real-time tracking of ETH supply, issuance, and burn rates +- [Etherscan](https://etherscan.io) - Block explorer with supply metrics + +## Factors Influencing Future ETH Supply and Issuance + +Ethereum's future supply isn't fixed—it depends on several variables: + +1. **Staking Participation**: + - More validators joining the network means more ETH rewards are distributed. + - Fewer validators participating may decrease issuance. + - Learn more about [staking](/staking/). + +2. **Network Activity**: + - High transaction volumes lead to more ETH being burned, potentially offsetting or exceeding issuance. + - Read about [gas fees](/developers/docs/gas/) and how they affect burning. + +3. **Protocol Upgrades**: + - Future changes to Ethereum's code could adjust staking rewards or burning mechanisms, further shaping supply dynamics. + - Stay updated with the [Ethereum roadmap](/roadmap/). + +## Recap: ETH Supply, Issuance, and What's Next + +Here's a quick summary of what you need to know about ETH supply and issuance: + +- **ETH Supply**: Dynamic and constantly changing, trackable in real-time through tools like [Ultrasound Money](https://ultrasound.money) +- **Issuance Under PoS**: Significantly reduced compared to PoW, with rewards going to validators. See current rates on [Ultrasound Money](https://ultrasound.money) +- **EIP-1559's Role**: ETH burning can make the network deflationary during periods of high activity +- **Future Trends**: Staking participation, network demand, and protocol updates will all shape ETH supply + +Understanding ETH issuance helps demystify the value of Ethereum and its potential as a deflationary, decentralized asset. For more detailed information about how The Merge impacted ETH supply, check out our [detailed breakdown](/roadmap/merge/issuance/). Curious about the future of ETH? Dive deeper with tools like [Ultrasound Money](https://ultrasound.money) or explore our [staking guides](/staking/). + +--- + +# Foundation + +## Foundation + +# About the Ethereum Foundation + + + +The [Ethereum Foundation](http://ethereum.foundation/) (EF) is a non-profit organization dedicated to supporting [Ethereum](/what-is-ethereum/) and related technologies. + +The EF is not a company, or even a traditional non-profit. Their role is not to control or lead Ethereum, nor are they the only organization that funds critical development of Ethereum-related technologies. The EF is one part of a much larger [ecosystem](/community/). + +## Ethereum Foundation Initiatives + +### Ecosystem Support Program + +The [Ecosystem Support Program](https://esp.ethereum.foundation/) exists to provide both financial and non-financial support to projects and entities within the greater Ethereum community, in order to accelerate the growth of the ecosystem. The Ecosystem Support Program is an expansion of the original Ethereum Grants Program which mainly focused on financial support. + +Learn more about the Ecosystem Support Program, past grant recipients, and the grant application process at [esp.ethereum.foundation](https://esp.ethereum.foundation/). You can also view the [Ecosystem Support Program Blog](https://blog.ethereum.org/category/ecosystem-support-program/) or follow [@EF_ESP](https://twitter.com/EF_ESP) for their latest news and announcements. + +### Devcon + +Since 2014, the Ethereum Foundation has organized Devcon, the annual conference for all Ethereum developers, researchers, thinkers, and makers. + +You can access video content of conference presentations for every year since its inception at [archive.devcon.org](https://archive.devcon.org/). + +Learn more at [devcon.org](https://devcon.org/), check out the [Devcon Blog](https://devcon.org/en/blogs/), or follow [@efdevcon](https://twitter.com/EFDevcon) for the latest announcements. + +### Fellowship Program + +The [Ethereum Foundation Fellowship Program](https://fellowship.ethereum.foundation/) is an initiative to help address gaps in representation across cultures, nationalities, and economic classes. The Fellowship Program is about bridging these gaps by identifying and supporting unique and talented individuals helping to enable Ethereum’s relevance, and breaking down barriers to entry for those underrepresented people and communities who will become the future of Web3. + +[Learn more at fellowship.ethereum.foundation](https://fellowship.ethereum.foundation/). + + + +For more on the Foundation and their work, visit [ethereum.foundation](http://ethereum.foundation/), or check out the [Ethereum Foundation Blog](https://blog.ethereum.org/) for the EF's latest news and announcements. + +--- + +# Glossary + +## Glossary + +# Glossary + +## \# + + + + + +## A + + + + + + + + + + + + + + + + + + + + + +## B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## E + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## F + + + + + + + + + + + + + + + + + + + +## G + + + + + + + + + + + + + + + +## H + + + + + + + + + + + + + +## I + + + + + + + + + + + + + +## K + + + + + + + + + + + +## L + + + + + + + + + + + + + + + + + +## M + + + + + + + + + + + + + + + + + + + + + + + + + +## N + + + + + + + + + + + + + +## O + + + + + + + + + + + + + +## P + + + + + + + + + + + + + + + + + + + + + + + + + + + +## R + + + + + + + + + + + + + + + +## S + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## T + + + + + + + + + + + + + + + + + + + +## V + + + + + + + + + + + + + +## W + + + + + + + + + + + +## Z + + + + + + + + + +## Sources + +_Provided in part by [Mastering Ethereum](https://github.com/ethereumbook/ethereumbook) by [Andreas M. Antonopoulos, Gavin Wood](https://ethereumbook.info) under CC-BY-SA_ + + + +## Contribute to this page + +Did we miss something? Is something incorrect? Help us improve by contributing to this glossary on GitHub! + +[Learn more about how to contribute](/contributing/adding-glossary-terms) + +--- + +# Governance + +## Governance + +# Introduction to Ethereum governance + +_If no one owns Ethereum, how are decisions about past and future changes to Ethereum made? Ethereum governance refers to the process that allows such decisions to be made._ + + + +## What is governance? + +Governance is the systems in place that allow decisions to be made. In a typical organizational structure, the executive team or a board of directors may have the final say in decision-making. Or perhaps shareholders vote on proposals to enact change. In a political system, elected officials may enact legislation that attempts to represent their constituents' desires. + +## Decentralized governance + +No one person owns or controls the Ethereum protocol, but decisions still need to be made about implementing changes to best ensure the longevity and prosperity of the network. This lack of ownership makes traditional organizational governance an incompatible solution. + +## Ethereum Governance + +Ethereum governance is the process by which protocol changes are made. It's important to point out that this process isn't related to how people and applications use the protocol - Ethereum is permissionless. Anyone from anywhere in the world can participate in onchain activities. There are no rules set for who can or cannot build an application or send a transaction. However, there is a process to propose changes to the core protocol, which decentralized applications run on top of. Since so many people depend on Ethereum's stability, there is a very high coordination threshold for core changes, including social and technical processes, to ensure any changes to Ethereum are secure and widely supported by the community. + +### Onchain vs offchain governance + +Blockchain technology allows for new governance capabilities, known as onchain governance. Onchain governance is when proposed protocol changes are decided by a stakeholder vote, usually by holders of a governance token, and voting happens on the blockchain. With some forms of onchain governance, the proposed protocol changes are already written in code and implemented automatically if the stakeholders approve the changes via signing a transaction. + +The opposite approach, offchain governance, is where any protocol change decisions happen through an informal process of social discussion, which, if approved, would be implemented in code. + +**Ethereum governance happens offchain** with a wide variety of stakeholders involved in the process. + +_Whilst at the protocol level Ethereum governance is offchain, many use cases built on top of Ethereum, such as DAOs, use onchain governance._ + + + More on DAOs + + + + +## Who is involved? + +There are various stakeholders in the [Ethereum community](/community/), each playing a role in the governance process. Starting from the stakeholders furthest from the protocol and zooming in, we have: + +- **Ether holders**: these people hold an arbitrary amount of ETH. [More on ETH](/eth/). +- **Application Users**: these people interact with applications on the Ethereum blockchain. +- **Application/Tooling Developers**: these people write applications that run on the Ethereum blockchain (e.g. DeFi, NFTs, etc.) or build tooling to interact with Ethereum (e.g. wallets, test suites, etc.). [More on dapps](/dapps/). +- **Node Operators**: these people run nodes that propagate blocks and transactions, rejecting any invalid transaction or block that they come across. [More on nodes](/developers/docs/nodes-and-clients/). +- **EIP Authors**: these people propose changes to the Ethereum protocol, in the form of Ethereum Improvement Proposals (EIPs). [More on EIPs](/eips/). +- **Validators**: these people run nodes that can add new blocks to the Ethereum blockchain. +- **Protocol Developers** (a.k.a. "Core Developers" ): these people maintain the various Ethereum implementations (e.g. go-ethereum, Nethermind, Besu, Erigon, Reth at the execution layer or Prysm, Lighthouse, Nimbus, Teku, Lodestar, Grandine at the consensus layer). [More on Ethereum clients](/developers/docs/nodes-and-clients/). + +_Note: any individual can be part of multiple of these groups (e.g. a protocol developer could champion an EIP, and run a beacon chain validator, and use DeFi applications). For conceptual clarity, it is easiest to distinguish between them, though._ + + + +## What is an EIP? + +One important process used in Ethereum governance is the proposal of **Ethereum Improvement Proposals (EIPs)**. EIPs are standards specifying potential new features or processes for Ethereum. Anyone within the Ethereum community can create an EIP. If you're interested in writing an EIP or participating in peer-review and/or governance, see: + + + More on EIPs + + + + +## The formal process + +The formal process for introducing changes to the Ethereum protocol is as follows: + +1. **Propose a Core EIP**: as described in [EIP-1](https://eips.ethereum.org/EIPS/eip-1#core-eips), the first step to formally proposing a change to Ethereum is to detail it in a Core EIP. This will act as the official specification for an EIP that Protocol Developers will implement if accepted. + +2. **Present your EIP to Protocol Developers**: once you have a Core EIP for which you've gathered community input, you should present it to Protocol Developers. You can do so by proposing it for discussion on an [AllCoreDevs call](https://github.com/ethereum/execution-specs/tree/master/network-upgrades#getting-the-considered-for-inclusion-cfi-status). It is likely some discussions will have already happened asynchronously on the [Ethereum Magician's forum](https://ethereum-magicians.org/) or in the [Ethereum R&D Discord](https://discord.gg/mncqtgVSVw). + +> Potential outcomes of this stage are: + +> - The EIP will be considered for a future network upgrade +> - Technical changes will be requested +> - It may be rejected if it is not a priority or the improvement is not large enough relative to the development effort + +3. **Iterate towards a final proposal:** after receiving feedback from all relevant stakeholders, you will likely need to make changes to your initial proposal to improve its security or better meet the needs of various users. Once your EIP has incorporated all the changes you believe are necessary, you will need to present it again to Protocol Developers. You will then move to the next step of this process, or new concerns will emerge, requiring another round of iterations on your proposal. + +4. **EIP Included in Network Upgrade**: assuming the EIP is approved, tested and implemented, it gets scheduled as part of a network upgrade. Given the high coordination costs of network upgrades (everyone needs to upgrade simultaneously), EIPs are generally bundled together in upgrades. + +5. **Network Upgrade Activated**: after the network upgrade is activated, the EIP will be live on the Ethereum network. _Note: network upgrades are usually activated on testnets before being activated on the Ethereum Mainnet._ + +This flow, while very simplified, gives an overview of the significant stages for a protocol change to be activated on Ethereum. Now, let's look at the informal factors at play during this process. + +## The informal process + +### Understanding prior work + +EIP Champions should familiarise themselves with prior work and proposals before creating an EIP which can be seriously considered for deployment on the Ethereum Mainnet. This way, the EIP hopefully brings something new which hasn't been rejected before. The three main places to research this are the [EIP repository](https://github.com/ethereum/EIPs), [Ethereum Magicians](https://ethereum-magicians.org/) and [ethresear.ch](https://ethresear.ch/). + +### Working groups + +The initial draft of an EIP is unlikely to be implemented on the Ethereum Mainnet without edits or changes. Generally, EIP Champions will work with a subset of Protocol Developers to specify, implement, test, iterate, and finalize their proposal. Historically, these working groups have required several months (and sometimes years!) of work. Similarly, EIP Champions for such changes should involve relevant Application/Tooling Developers early in their efforts to gather end-user feedback and mitigate any deployment risks. + +### Community consensus + +While some EIPs are straightforward technical improvements with minimal nuance, some are more complex and come with tradeoffs which will affect different stakeholders in different ways. This means some EIPs are more contentious within the community than others. + +There is no clear playbook on how to handle contentious proposals. This is a result of Ethereum's decentralized design whereby no single stakeholder group can coerce the other through brute force: protocol developers can choose not to implement code changes; node operators can choose not to run the latest Ethereum client; application teams and users can choose not to transact on the chain. Since Protocol Developers have no way to force people to adopt network upgrades, they will generally avoid implementing EIPs where the contentiousness outweighs the benefits to the broader community. + +EIP Champions are expected to solicit feedback from all relevant stakeholders. If you find yourself the champion of a contentious EIP, you should try and address objections to build consensus around your EIP. Given the size and diversity of the Ethereum community, there isn't a single metric (e.g. a coin vote) that can be used to gauge community consensus, and EIP Champions are expected to adapt to the circumstances of their proposal. + +Beyond the security of the Ethereum network, significant weight has historically been placed by Protocol Developers on what Application/Tooling Developers and Application Users value, given that their using and developing on Ethereum is what makes the ecosystem attractive for other stakeholders. Additionally, EIPs need to be implemented across all client implementations, which are managed by distinct teams. Part of this process usually means convincing multiple teams of Protocol Developers that a particular change is valuable and that it helps end-users or solves a security issue. + + + +## Handling disagreements + +Having many stakeholders with different motivations and beliefs means that disagreements are not uncommon. + +Generally, disagreements are handled with long-form discussion in public forums to understand the root of the problem and allow anyone to weigh in. Typically, one group concedes, or a happy medium is achieved. If one group feels strongly enough, forcing through a particular change could result in a chain split. A chain split is when some stakeholders protest implementing a protocol change resulting in different, incompatible versions of the protocol operating, from which two distinct blockchains emerge. + +### The DAO fork + +Forks are when major technical upgrades or changes need to be made to the network and change the "rules" of the protocol. [Ethereum clients](/developers/docs/nodes-and-clients/) must update their software to implement the new fork rules. + +The DAO fork was in response to the [2016 DAO attack](https://www.coindesk.com/learn/understanding-the-dao-attack) where an insecure [DAO](/glossary/#dao) contract was drained of over 3.6 million ETH in a hack. The fork moved the funds from the faulty contract to a new contract allowing anyone who lost funds in the hack to recover them. + +This course of action was voted on by the Ethereum community. Any ETH holder was able to vote via a transaction on [a voting platform](https://web.archive.org/web/20170620030820/http://v1.carbonvote.com/). The decision to fork reached over 85% of the votes. + +It's important to note that whilst the protocol did fork to revert the hack, the weight the vote carried in deciding to fork is debatable for a few reasons: + +- The turnout to vote was incredibly low +- Most people didn't know the vote was happening +- The vote only represented ETH holders, not any of the other participants in the system + +A subset of the community refused to fork, largely because they felt the DAO incident wasn't a defect in the protocol. They went on to form [Ethereum Classic](https://ethereumclassic.org/). + +Today, the Ethereum community has adopted a policy of non-intervention in cases of contract bugs or lost funds to maintain the credible neutrality of the system. + +Watch more on the DAO hack: + + + + + +### The utility of forking + +The Ethereum/Ethereum Classic fork is an excellent example of a healthy fork. We had two groups who disagreed strongly enough with each other on some core values to feel it was worth the risks involved to pursue their specific courses of action. + +The ability to fork in the face of significant political, philosophical or economic differences plays a large part in the success of Ethereum governance. Without the ability to fork the alternative was ongoing in-fighting, forced reluctant participation for those who eventually formed Ethereum Classic and an increasingly differing vision of how success for Ethereum looks. + + + +## Beacon Chain governance + +The Ethereum governance process often trades off speed and efficiency for openness and inclusivity. In order to accelerate the development of the Beacon Chain, it was launched separately from the proof-of-work Ethereum network and followed its own governance practices. + +While the specification and development implementations have always been fully open source, the formal processes used to propose updates described above weren't used. This allowed changes to be specified and agreed upon quicker by researchers and implementers. + +When the Beacon Chain merged with the Ethereum execution layer on September 15th, 2022 The Merge was complete as part of the [Paris network upgrade](/history/#paris). The proposal [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675) was changed from 'Last Call' to 'Final', completing the transition to proof-of-stake. + + + More on The Merge + + + + +## How can I get involved? + +- [Propose an EIP](/eips/#participate) +- [Discuss current proposals](https://ethereum-magicians.org/) +- [Get involved in R&D discussion](https://ethresear.ch/) +- [Join the Ethereum R&D discord](https://discord.gg/mncqtgVSVw) +- [Run a node](/developers/docs/nodes-and-clients/run-a-node/) +- [Contribute to client development](/developers/docs/nodes-and-clients/#execution-clients) +- [Core Developer Apprenticeship Program](https://blog.ethereum.org/2021/09/06/core-dev-apprenticeship-second-cohort/) + +## Further reading + +Governance in Ethereum isn’t rigidly defined. Various community participants have diverse perspectives on it. Here are a few of them: + +- [Notes on Blockchain Governance](https://vitalik.eth.limo/general/2017/12/17/voting.html) - _Vitalik Buterin_ +- [How does Ethereum Governance work?](https://cryptotesters.com/blog/ethereum-governance) – _Cryptotesters_ +- [How Ethereum governance works](https://medium.com/coinmonks/how-ethereum-governance-works-71856426b63a) – _Micah Zoltu_ +- [What is an Ethereum core developer?](https://hudsonjameson.com/2020-06-22-what-is-an-ethereum-core-developer/) - _Hudson Jameson_ +- [Governance, Part 2: Plutocracy Is Still Bad](https://vitalik.eth.limo/general/2018/03/28/plutocracy.html) - _Vitalik Buterin_ +- [Moving beyond coin voting governance](https://vitalik.eth.limo/general/2021/08/16/voting3.html) - _Vitalik Buterin_ +- [Understanding Blockchain Governance](https://research.2077.xyz/understanding-blockchain-governance) - _2077 Research_ +- [The Ethereum Government](https://www.galaxy.com/insights/research/ethereum-governance/) - _Christine Kim_ + +--- + +# Guides + +## Guides > How To Create An Ethereum Account + +# How to create an Ethereum account + +**Anyone can create an Ethereum account for free.** You just need to install a crypto wallet app. Wallets create and manage your Ethereum account. They can send transactions, check your balances and connect you to other apps built on Ethereum. + +With a wallet you can also log into any token exchange, games, [NFT](/glossary/#nft) marketplaces instantly. There is no need for individual registration, one account is shared for all apps built on Ethereum. + +## Step 1: Choose a wallet + +A wallet is an app that helps you manage your Ethereum account. There are dozens of different wallets to choose from: mobile, desktop, or even browser extensions. + + + + List of wallets + + +If you are new, you can select the “New to crypto” filter on the "find a wallet" page to identify wallets that should include all necessary features suitable for beginners. + +![Filter selection on 'find a wallet' page](./wallet-box.png) + +There are also other profile filters to cater to your needs. These are examples of commonly used wallets - you should do your own research before trusting any software. + +## Step 2: Download and install your wallet app + +Once you have decided on a specific wallet, visit their official website or app store, download and install it. All of them should be free. + +## Step 3: Open the app and create your Ethereum account + +The first time you open your new wallet you might be asked to choose between creating a new account or importing an existing one. Click on the new account creation. **This is the step during which the wallet software generates your Ethereum account.** + +## Step 4: Store your recovery phrase + +Some apps will request you to save a secret "recovery phrase" (sometimes called a "seed phrase" or a "mnemonic"). Keeping this phrase safe is extremely important! This is used to generate your Ethereum account and can be used to submit transactions. + +**Any person who knows the phrase can take control of all funds.** Never share this with anyone. This phrase should contain 12 to 24 randomly generated words (the order of the words matters). + + + + Wallet installed?Learn how to use it. + + How to use a wallet + + + + +Interested in other guides? Check out our: [Step by step guides](/guides/) + +## Frequently asked questions + +### Are my wallet and my Ethereum account the same? + +No. The wallet is a management tool that helps you to manage accounts. A single wallet might access several accounts, and a single account can be accessed by multiple wallets. The recovery phrase is used to create accounts and gives permission to a wallet app to manage assets. + +### Can I send bitcoin to an Ethereum address, or ether to a Bitcoin address? + +No, you cannot. Bitcoin and ether exist on two separate networks (i.e. different blockchains), each with their own bookkeeping and address formats. There have been various attempts to bridge the two different networks, of which the most active one is currently [Wrapped Bitcoin or WBTC](https://www.bitcoin.com/get-started/what-is-wbtc/). This is not an endorsement, as WBTC is a custodial solution (meaning a single group of people controls certain critical functions) and is provided here for informational purposes only. + +### If I own an ETH address, do I own the same address on other blockchains? + +You can use the same [address](/glossary/#address) on all blockchains that use similar underlying software to Ethereum (known as 'EVM-compatible'). This [list](https://chainlist.org/) will show you which blockchains you can use with the same address. Some blockchains, like Bitcoin, implement a completely separate set of network rules and you will need a different address with a different format. If you have a smart contract wallet you should check its product website for more info on which blockchains are supported because usually those have limited but more secure scope. + +### Is having my own wallet safer than keeping my funds on an exchange? + +Having your own wallet means you take responsibility for the security of your assets. There are unfortunately many examples of failed exchanges that lost their customers' money. Owning a wallet (with a recovery phrase) removes the risk associated with trusting some entity to hold your assets. However, you have to secure it on your own and avoid phishing scams, accidentally approving transactions or exposing recovery phrase, interacting with fake websites and other self-custody risks. The risks and benefits are different. + +### If I lose my phone/hardware wallet, do I need to use the same wallet app again to recover the lost funds? + +No, you can use a different wallet. As long as you have the seed phrase you can enter it into most wallets and they will restore your account. Be careful if you ever need to do this: it is best to make sure you are not connected to the internet when recovering your wallet so that your seed phrase is not accidentally leaked. It is often impossible to recover lost funds without the recovery phrase. + +--- + +## Guides > How To Id Scam Tokens + +# How to identify scam tokens + +One of the most common uses for Ethereum is for a group to create a tradable token, in a sense their own currency. These tokens typically follow a standard, [ERC-20](/developers/docs/standards/tokens/erc-20/). However, anywhere there are legitimate use cases that bring value, there are also criminals who try to steal that value for themselves. + +There are two ways in which they are likely to deceive you: + +- **Selling you a scam token**, which may look like the legitimate token you want to purchase, but are issued by the scammers and worth nothing. +- **Tricking you into signing bad transactions**, usually by directing you into their own user interface. They might try to get you into giving their contracts an allowance on your ERC-20 tokens, exposing sensitive information that gives them access to your assets, etc. These user interfaces might be near-perfect clones of honest sites, but with hidden tricks. + +To illustrate what scam tokens are, and how to identify them, we are going to look at an example of one: [`wARB`](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82). This token attempts to look like the legitimate [`ARB`](https://etherscan.io/address/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1) token. + + + +Arbitrum is an organization that develops and manages optimistic rollups. Initially, Arbitrum was organized as a for-profit company, but then took steps to decentralize. As part of that process, they issued a tradeable governance token. + + + + + +There is a convention in Ethereum that when an asset is not ERC-20 compliant we create a "wrapped" version of it with the name starting with "w". So, for example, we have wBTC for bitcoin and wETH for ether. + +It does not make sense to create a wrapped version of an ERC-20 token that is already on Ethereum, but scammers rely on the appearance of legitimacy rather than the underlying reality. + + + +## How do scam tokens work? + +The whole point of Ethereum is decentralization. This means that there is no central authority that can confiscate your assets or prevent you from deploying a smart contract. But it also means that scammers can deploy any smart contract they wish. + + + +Smart contracts are the programs that run on top of the Ethereum blockchain. Every ERC-20 token, for example, is implemented as a smart contract. + + + +Specifically, Arbitrum deployed a contract that uses the symbol `ARB`. But that doesn't stop other people from also deploying a contract that uses the exact same symbol, or a similar one. Whoever writes the contract gets to set what the contract will do. + +## Appearing legitimate + +There are several tricks that scam token creators do to appear legitimate. + +- **Legitimate name and symbol**. As mentioned before, ERC-20 contracts can have the same symbol and name as other ERC-20 contracts. You cannot count on those fields for security. + +- **Legitimate owners**. Scam tokens often airdrop significant balances to addresses that can be expected to be legitimate holders of the real token. + + For example, let's look at `wARB` again. [About 16% of the tokens](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82?a=0x1c8db745abe3c8162119b9ef2c13864cd1fdd72f) are held by an address whose public tag is [Arbitrum Foundation: Deployer](https://etherscan.io/address/0x1c8db745abe3c8162119b9ef2c13864cd1fdd72f). This is _not_ a fake address, it really is the address that [deployed the real ARB contract on Ethereum mainnet](https://etherscan.io/tx/0x242b50ab4fe9896cb0439cfe6e2321d23feede7eeceb31aa2dbb46fc06ed2670). + + Because the ERC-20 balance of an address is part of the ERC-20 contract's storage, it can be specified by the contract to be whatever the contract developer wishes. It is also possible for a contract to forbid transfers so the legitimate users won't be able to get rid of those scam tokens. + +- **Legitimate transfers**. _Legitimate owners wouldn't pay to transfer a scam token to others, so if there are transfers it must be legitimate, right?_ **Wrong**. `Transfer` events are produced by the ERC-20 contract. A scammer can easily write the contract in such a way it will produce those actions. + +## Scammy websites + +Scammers can also produce very convincing websites, sometimes even precise clones of authentic sites with identical UIs, but with subtle tricks. Examples might be external links that seem legitimate actually sending the user to an external scam site, or incorrect instructions that guide the user to exposing their keys or sending funds to an attacker's address. + +The best practice for avoiding this is to carefully check the URL for the sites you visit, and save addresses for known authentic sites in your bookmarks. Then, you can access the real site through your bookmarks without accidentally making spelling errors or relying on external links. + +## How can you protect yourself? + +1. **Check the contract address**. Legitimate tokens come from legitimate organizations, and you can see the contract addresses on the organization's website. For example, [for `ARB` you can see the legitimate addresses here](https://docs.arbitrum.foundation/deployment-addresses#token). + +2. **Real tokens have liquidity**. Another option is to look at liquidity pool size on [Uniswap](https://uniswap.org/), one of the most common token swapping protocols. This protocol works using liquidity pools, into which investors deposit their tokens in hope of a return from trading fees. + +Scam tokens typically have tiny liquidity pools, if any, because the scammers don't want to risk real assets. For example, the `ARB`/`ETH` Uniswap pool holds about a million dollars ([see here for the up to date value](https://info.uniswap.org/#/pools/0x755e5a186f0469583bd2e80d1216e02ab88ec6ca)) and buying or selling a small amount is not going to change the price: + +![Buying a legitimate token](./uniswap-real.png) + +But when you try to buy the scam token `wARB`, even a tiny purchase would change the price by over 90%: + +![Buying a scam token](./uniswap-scam.png) + +This is another piece of evidence that shows us `wARB` is not likely to be a legitimate token. + +3. **Look in Etherscan**. A lot of scam tokens have already been identified and reported by the community. Such tokens are [marked in Etherscan](https://info.etherscan.com/etherscan-token-reputation/). While Etherscan is not an authoritative source of truth (it is the nature of decentralized networks that there can't be an authoritative source for legitimacy), tokens that are identified by Etherscan as scams are likely to be scams. + + ![Scam token in Etherscan](./etherscan-scam.png) + +## Conclusion + +As long as there is value in the world, there are going to be scammers who attempt to steal it for themselves, and in a decentralized world there is nobody to protect you except for yourself. Hopefully, you remember these points to help tell the legitimate tokens from the scams: + +- Scam tokens impersonate legitimate tokens, they can use the same name, symbol, etc. +- Scam tokens _cannot_ use the same contract address. +- The best source for the address of the legitimate token is the organization whose token it is. +- Failing that, you can use popular, trusted applications such as [Uniswap](https://app.uniswap.org/#/swap) and [Etherscan](https://etherscan.io/). + +--- + +## Guides > How To Revoke Token Access + +# How to revoke smart contract access to your crypto funds + +This guide will teach you how to view a list of all [smart contracts](/glossary/#smart-contract) you have allowed access to your funds and how to cancel them. + +Sometimes malicious developers build backdoors into smart contracts that allow access to the funds of unaware users who interact with the smart contract. What often happens is that such platforms ask the user for permission to spend an **unlimited number of tokens** in an attempt to save small amounts of [gas](/glossary/#gas) in the future, but this comes with increased risk. + +Once a platform has unlimited access rights to a token on your [wallet](/glossary/#wallet), they can spend all those tokens even if you have withdrawn your funds from their platform into your wallet. Malicious actors can still access your funds and withdraw them into their wallets with no recovery option left for you. + +The only protections are to refrain from using untested new projects, only approve what you need, or regularly revoke access. So, how do you do that? + +## Step 1: Use revoke access tools + +Several websites let you view and revoke smart contracts connected to your address. Visit the website and connect your wallet: + +- [Ethallowance](https://ethallowance.com/) (Ethereum) +- [Etherscan](https://etherscan.io/tokenapprovalchecker) (Ethereum) +- [Blockscout](https://eth.blockscout.com/apps/revokescout) (Ethereum) +- [Cointool](https://cointool.app/approve/eth) (multiple networks) +- [Revoke](https://revoke.cash/) (multiple networks) +- [Unrekt](https://app.unrekt.net/) (multiple networks) +- [EverRevoke](https://everrise.com/everrevoke/) (multiple networks) + +## Step 2: Connect your wallet + +Once you are on the website, click on “Connect wallet”. The website should prompt you to connect your wallet. + +Make sure you use the same network in your wallet and website. You will only see smart contracts related to the network selected. For example, if you connect to Ethereum Mainnet, you will only see Ethereum contracts, not contracts from other chains such as Polygon. + +## Step 3: Select a smart contract you wish to revoke + +You should see all the contracts that are allowed access to your tokens and their spending limit. Find the one you wish to terminate. + +If you do not know which contract to choose, you can revoke all of them. It won't create any problems for you, but you will have to grant a new set of permissions the next time you interact with any of these contracts. + +## Step 4: Revoke access to your funds + +Once you click on revoke, you should see a new transaction suggestion in your wallet. This is to be expected. You will have to pay the fee for the cancellation to be successful. Depending on the network this can take from a minute to several to be processed. + +We advise you to refresh the revoking tool after a few minutes and connect your wallet again to double check if the revoked contract has disappeared from the list. + +We recommend you never allow projects unlimited access to your tokens and revoke all token allowance access regularly. Revoking token access should never result in a loss of funds, especially if you use the tools listed above. + + + + + Want to learn more? + + See our other guides + + + +## Frequently asked questions + +### Does revoking token access also terminate staking, pooling, lending etc? + +No, it will not affect any of your [DeFi](/glossary/#defi) strategies. You will remain in your positions and keep getting rewards etc. + +### Is disconnecting a wallet from a project the same as removing permission to use my funds? + +No, if you disconnect your wallet from the project, but you've granted token allowance permissions, they can still use those tokens. You need to revoke that access. + +### When will the contract permission expire? + +There are no expiration dates on contract permissions. If you grant contract permissions, they can be used, even years after they're granted. + +### Why do projects set unlimited token allowance? + +Projects often do this to minimize the number of requests required, meaning the user only has to approve once and pay the transaction fee only once. While convenient, this can be dangerous for users to approve carelessly, on sites that are not proven with time or audited. Some wallets allow you to manually restrict the amount of tokens being approved to limit your risk. Check with your wallet provider for more information. + +--- + +## Guides > How To Swap Tokens + +# How to swap tokens + +Are you tired of searching for an exchange that lists all your favorite tokens? You can swap most of the tokens using [decentralized exchanges](/glossary/#dex). + +A token swap involves the exchange of two different assets that exist on the Ethereum network, for example swapping ETH for DAI (an [ERC-20](/glossary/#erc-20) token). The process is very fast and cheap. You will need to have a crypto wallet to swap tokens. + +**Prerequisite:** + +- have a [crypto wallet](/glossary/#wallet); if you don't, you can follow this guide on [how to create an Ethereum account](/guides/how-to-create-an-ethereum-account/) +- add funds to your wallet + +## 1. Connect your wallet to the decentralized exchange (DEX) of your choice + +Some popular exchanges are: + +- [Uniswap](https://app.uniswap.org/#/swap) +- [Sushiswap](https://www.sushi.com/swap) +- [1Inch](https://app.1inch.io/#/1/unified/swap/ETH/DAI) +- [Curve](https://www.curve.finance/dex/ethereum/swap/) + +Interesting? Learn more about what [decentralised finance (DeFi)](/defi/) is and how these new kinds of exchanges work. + +## 2. Select the pair of tokens you wish to swap + +For example, ETH and DAI. Make sure you have funds in one of the two tokens. +![Common interface for swapping](./swap1.png) + +## 3. Enter the amount of tokens you want to trade and click swap + +The exchange will automatically calculate how many tokens you will get. + +![Common interface for swapping](./swap2.png) + +## 4. Confirm the transaction + +Review the details of the transaction. Check the exchange rate and any other fees to prevent ugly surprises. + +![Common interface for reviewing the transaction](./swap3.png) + +## 5. Wait for the transaction to be processed + +You can view the progress of the transaction on any blockchain explorer. This process should not take longer than 10 minutes. + +You will automatically receive the swapped tokens in your wallet once the transaction is processed. + + + + Want to learn more? + + See our other guides + + + +## Frequently asked questions + +### Can I swap ETH for BTC from my wallet? + +No, you can only swap tokens that are native to the Ethereum network, such as ETH, ERC-20 tokens or NFTs. You can only swap "wrapped" forms of Bitcoin that live on Ethereum. + +### What is slippage? + +It is the difference between your expected exchange rate and the actual rate. + +--- + +## Guides > How To Use A Bridge + +# How to bridge tokens to layer 2 + +If there is a lot of traffic on Ethereum, it can become expensive. One solution to this is to create new "layers": i.e. different networks which operate in similar ways to Ethereum itself. These so-called Layer 2s help reduce congestion and cost on Ethereum by processing many more transactions at lower fees, and only storing the result of these on Ethereum every so often. As such, these layers 2s enable us to transact with increased speed and decreased costs. Many popular crypto projects are moving to layer 2s because of these benefits. The simplest way to move tokens from Ethereum to layer 2 is to use a bridge. + +**Prerequisite:** + +- have a crypto wallet, you can follow this tutorial: [How to create an Ethereum account](/guides/how-to-create-an-ethereum-account/) +- add funds to your wallet + +## 1. Determine which layer 2 network you want to use + +You can learn more about the different projects and important links on our [layer 2 page](/layer-2/). + +## 2. Go to the selected bridge + +Some popular layer 2s are: + +- [Arbitrum bridge](https://bridge.arbitrum.io/?l2ChainId=42161) +- [Optimism bridge](https://app.optimism.io/bridge/deposit) +- [Boba network bridge](https://gateway.boba.network/) + +## 3. Connect to the bridge with your wallet + +Make sure your wallet is connected to the Ethereum Mainnet network. If it is not, the website will automatically prompt you to switch networks. + +![Common interface for bridging tokens](./bridge1.png) + +## 4. Specify the amount and move the funds + +Review the amount that you will get in return on the layer 2 network and the fees to avoid unpleasant surprises. + +![Common interface for bridging tokens](./bridge2.png) + +## 5. Confirm the transaction in your wallet + +You will have to pay a fee in form of ETH for processing the transaction. + +![Common interface for bridging tokens](./bridge3.png) + +## 6. Wait for your funds to be moved + +This process should not take more than 10 minutes. + +## 7. Add the selected layer 2 network to your wallet (optional) + +You can use [chainlist.org](http://chainlist.org) to find the network's RPC details. Once the network is added and transaction finished, you should see the tokens in your wallet. + + + + Want to learn more? + + See our other guides + + + +## Frequently asked questions + +### What if I have funds on an exchange? + +You might be able to withdraw to some layer 2s directly from an exchange. Check out “Move to layer 2” section of our [Layer 2 page](/layer-2/) for more information. + +### Can I go back to Ethereum mainnet after I bridge my tokens to L2? + +Yes, you can always move your funds back to the mainnet using the same bridge. + +--- + +## Guides > How To Use A Wallet + +# How to use a wallet + +Learn how to operate all the basic functions of a wallet. If you don’t have one yet, check out our [How to create an Ethereum account](/guides/how-to-create-an-ethereum-account/). + +## Open your wallet + +You should see a dashboard that will likely show your balance and contain buttons to send and receive tokens. + +## Receive cryptocurrency + +Do you want to receive crypto into your wallet? + +Each Ethereum account has its own receiving address which is a unique sequence of numbers and letters. The address functions like a bank account number. Ethereum addresses will always start with “0x”. You can share this address with anyone: it is safe to do so. + +Your address is like your home address: you need to tell people what it is so they can find you. It is safe to do this, because you can still lock your front door with another key only you control so that no-one can get in, even if they know where you live. + +You need to provide whoever wants to send you money with your public address. Many wallet apps let you copy your address or show a QR code to scan for easier usage. Avoid typing any Ethereum address manually. This can easily lead to clerical errors and lost funds. + +Different apps may vary or use different language, but they should take you through a similar process if you are trying to transfer funds. + +1. Open your wallet app. +2. Click on "Receive" (or similarly worded option). +3. Copy your Ethereum address to clipboard. +4. Provide the sender with your receiving Ethereum address. + +## Send cryptocurrency + +Would you like to send ETH to another wallet? + +1. Open your wallet app. +2. Get the receiving address and make sure you are connected to the same network as the recipient. +3. Enter the receiving address or scan a QR code with your camera so that you don’t have to write the address manually. +4. Click on a “Send” button in your wallet (or a similarly worded alternative). + +![Send field for crypto address](./send.png) + + +5. Many assets, like DAI or USDC, exist on multiple networks. When transferring crypto tokens, make sure that the recipient is using the same network as you are, since these are not interchangeable. +6. Ensure that your wallet has sufficient ETH to cover the transaction fee, which varies depending on network conditions. Most wallets will automatically add the suggested fee to the transaction which you can then confirm. +7. Once your transaction is processed, the corresponding crypto amount will show up in the recipient’s account. This might take anywhere from a few seconds to a few minutes depending on how much the network is currently being used. + +## Connecting to projects + +Your address will be the same in all Ethereum projects. You do not need to register individually on any project. Once you have a wallet, you can connect to any Ethereum project without any additional information. No emails or any other personal information are needed. + +1. Visit any project’s website. +2. If the project's landing page is just a static description of the project, you should be able to click on an "Open the App" button in the menu which will navigate you to the actual web app. +3. Once you are in the app click on “Connect”. + +![Button allowing user to connect to the website with a wallet](./connect1.png) + +4. Select your wallet from the provided options list. If you can't see your wallet, it may be hidden under the “WalletConnect” option. + +![Selecting from a list of wallets to connect with](./connect2.png) + +5. Confirm the signature request in your wallet to establish the connection. **Signing this message should not require spending any ETH**. +6. That's it! Start using the app. You can find some interesting projects on our [dApps page](/dapps/#explore). + + + + Want to learn more? + + See our other guides + + + +## Frequently asked questions + +### If I own an ETH address, do I own the same address on other blockchains? + +You can use the same address on all EVM compatible blockchains (if you have the type of wallet with a recovery phrase). This [list](https://chainlist.org/) will show you which blockchains you can use with the same address. Some blockchains, like Bitcoin, implement a completely separate set of network rules and you will need a different address with a different format. If you have a smart contract wallet you should check its product website for more info on which blockchains are supported. + +### Can I use the same address on multiple devices? + +Yes, you can use the same address on multiple devices. Wallets are technically only an interface to show you your balance and to make transactions, your account isn't stored inside the wallet, but on the blockchain. + +### I have not received the crypto, where can I check the status of a transaction? + +You can use [block explorers](/developers/docs/data-and-analytics/block-explorers/) to see the status of any transaction in real time. All you need to do is to search your wallet address or the ID of the transaction. + +### Can I cancel or return transactions? + +No, once a transaction is confirmed, you cannot cancel the transaction. + +--- + +## Guides + +# Ethereum guides + +Do you want to start your Ethereum journey? Our practical guides lead you step-by-step on getting started, and make it easier to navigate this new technology. + +## Getting started + +1. [How to "create" an Ethereum account](/guides/how-to-create-an-ethereum-account/) - Anyone can create a wallet for free. This guide will show you where to begin. + +2. [How to use a wallet](/guides/how-to-use-a-wallet/) - Learn how to send and receive tokens in your wallet and how to connect wallet to projects. + +## Security basics + +1. [How to revoke smart contract access to your crypto funds](/guides/how-to-revoke-token-access/) - If you suddenly see a transaction in your wallet that you did not initiate, this guide will teach you how to prevent that from happening again. + +2. [How to identify scam tokens](/guides/how-to-id-scam-tokens/) - What are scam tokens? How do they make themselves look legitimate, and how do you identify them to protect yourself and avoid being scammed? + +## Using Ethereum + +1. [How to bridge tokens to layer 2](/guides/how-to-use-a-bridge/) - Are Ethereum transactions too costly? Consider moving to Ethereum scaling solutions called layer 2s. + +2. [How to swap tokens](/guides/how-to-swap-tokens/) - Do you want to exchange your tokens for a different one? This simple guide will show you how to do that. + +--- + +# History + +## History + +# The history of Ethereum + +A timeline of all the major milestones, forks, and updates to the Ethereum blockchain. + + + +Forks are when major technical upgrades or changes need to be made to the network – they typically stem from Ethereum Improvement Proposals (EIPs) and change the "rules" of the protocol. + +When upgrades are needed in traditional, centrally-controlled software, the company will just publish a new version for the end-user. Blockchains work differently because there is no central ownership. Ethereum clients must update their software to implement the new fork rules. Plus block creators (miners in a proof-of-work world, validators in a proof-of-stake world) and nodes must create blocks and validate against the new rules. More on consensus mechanisms + +These rule changes may create a temporary split in the network. New blocks could be produced according to the new rules or the old ones. Forks are usually agreed upon ahead of time so that clients adopt the changes in unison and the fork with the upgrades becomes the main chain. However, in rare cases, disagreements over forks can cause the network to permanently split – most notably the creation of Ethereum Classic with the DAO fork. + + + + + +The software that underlies Ethereum is composed of two halves, known as the [execution layer](/glossary/#execution-layer) and the [consensus layer](/glossary/#consensus-layer). + +**Execution upgrade naming** + +Since 2021, upgrades to the **execution layer** are named according to the city names of [previous Devcon locations](https://devcon.org/en/past-events/) in chronological order: + +| Upgrade Name | Devcon Year | Devcon Number | Upgrade Date | +| ------------ | ----------- | ------------- | ------------ | +| Berlin | 2014 | 0 | Apr 15, 2021 | +| London | 2015 | I | Aug 5, 2021 | +| Shanghai | 2016 | II | Apr 12, 2023 | +| Cancun | 2017 | III | Mar 13, 2024 | +| **Prague** | 2018 | IV | TBD - Next | +| _Osaka_ | 2019 | V | TBD | +| _Bogota_ | 2022 | VI | TBD | +| _Bangkok_ | 2024 | VII | TBD | + +**Consensus upgrade naming** + +Since the launch of the [Beacon Chain](/glossary/#beacon-chain), upgrades to the **consensus layer** are named after celestial stars beginning with letters that proceed in alphabetical order: + +| Upgrade Name | Upgrade Date | +| ------------------------------------------------------------- | ------------ | +| Beacon Chain genesis | Dec 1, 2020 | +| [Altair](https://en.wikipedia.org/wiki/Altair) | Oct 27, 2021 | +| [Bellatrix](https://en.wikipedia.org/wiki/Bellatrix) | Sep 6, 2022 | +| [Capella](https://en.wikipedia.org/wiki/Capella) | Apr 12, 2023 | +| [Deneb](https://en.wikipedia.org/wiki/Deneb) | Mar 13, 2024 | +| [**Electra**]() | TBD - Next | +| [_Fulu_]() | TBD | + +**Combined naming** + +The execution and consensus upgrades were initially rolled out at different times, but after [The Merge](/roadmap/merge/) in 2022 these have been deployed simultaneously. As-such, colloquial terms have emerged to simplify references to these upgrades using a single conjoined term. This began with the _Shanghai-Capella_ upgrade, commonly referred to as "**Shapella**", and is continued with the _Cancun-Deneb_ (**Dencun**), and the _Prague-Electra_ (**Pectra**) upgrades. + +| Execution Upgrade | Consensus Upgrade | Short Name | +| ----------------- | ----------------- | ---------- | +| Shanghai | Capella | "Shapella" | +| Cancun | Deneb | "Dencun" | +| Prague | Electra | "Pectra" | +| Osaka | Fulu | "Fusaka" | + + + +Skip straight to information about some of the particularly important past upgrades: [The Beacon Chain](/roadmap/beacon-chain/); [The Merge](/roadmap/merge/); and [EIP-1559](#london) + +Looking for future protocol upgrades? [Learn about upcoming upgrades on the Ethereum roadmap](/roadmap/). + + + +## 2025 + +### Prague-Electra ("Pectra") + + + +The Prague-Electra ("Pectra") upgrade included several improvements to the Ethereum protocol aimed at enhancing the experience for all users, layer 2 networks, stakers and node operators. + +Staking got an upgrade with compounding validator accounts, and improved control over staked funds using the execution withdrawal address. EIP-7251 increased the max effective balance for a single validator to 2048, improving capital efficiency for stakers. EIP-7002 enabled an execution account to securely trigger validator actions, including exiting, or withdrawing portions of the funds, improving the experience for ETH stakers, while helping strengthen accountability for node operators. + +Other parts of the upgrade focused on improving the experience for regular users. EIP-7702 brought the ability for a regular non-smart-contract account ([EOA](/glossary/#eoa)) to execute code similar to a smart contract. This unlocked unbounded new functionality for traditional Ethereum accounts, such as transaction batching, gas sponsorship, alternative authentication, programmable spending controls, account recovery mechanisms and more. + + + +Better user experience: + + + EIP-7702 - Set EOA account code + EIP-7691 - Blob throughput increase + EIP-7623 - Increase calldata cost + EIP-7840 - Add blob schedule to EL config files + + +Better staking experience: + + + EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE + EIP-7002 - Execution layer triggerable exits + EIP-7685 - General purpose execution layer requests + EIP-6110 - Supply validator deposits on chain + + +Protocol efficiency and security improvements: + + + EIP-2537 - Precompile for BLS12-381 curve operations + EIP-2935 - Save historical block hashes in state + EIP-7549 - Move committee index outside Attestation + + + + +- [Pectra.wtf](https://pectra.wtf) +- [How Pectra will enhance the staking experience](https://www.kiln.fi/post/next-ethereum-upgrade-how-pectra-will-enhance-the-staking-experience) +- [Read the Electra upgrade specifications](https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/) +- [Prague-Electra ("Pectra") FAQ](/roadmap/pectra/) + + + +## 2024 + +### Cancun-Deneb ("Dencun") + + + +#### Cancun summary + +The Cancun upgrade contains a set of improvements to Ethereum's _execution_ aimed towards improving scalability, in tandem with the Deneb consensus upgrades. + +Notably this includes EIP-4844, known as **Proto-Danksharding**, which significantly decreases the cost of data storage for layer 2 rollups. This is achieved through the introduction of data "blobs" which enables rollups to post data to Mainnet for a short period of time. This results in significantly lower transaction fees for users of layer 2 rollups. + + + + + EIP-1153 - Transient storage opcodes + EIP-4788 - Beacon block root in the EVM + EIP-4844 - Shard blob transactions (Proto-Danksharding) + EIP-5656 - MCOPY - Memory copying instruction + EIP-6780 - SELFDESTRUCT only in same transaction + EIP-7516 - BLOBBASEFEE opcode + + + + +- [Layer 2 rollups](/layer-2/) +- [Proto-Danksharding](/roadmap/scaling/#proto-danksharding) +- [Danksharding](/roadmap/danksharding/) +- [Read the Cancun upgrade specification](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md) + +#### Deneb summary + +The Deneb upgrade contains a set of improvements to Ethereum's _consensus_ aimed towards improving scalability. This upgrade comes in tandem with the Cancun execution upgrades to enable Proto-Danksharding (EIP-4844), along with other improvements to the Beacon Chain. + +Pre-generated signed "voluntary exit messages" no longer expire, thus giving more control to users staking their funds with a third-party node operator. With this signed exit message, stakers can delegate node operation while maintaining the ability to safely exit and withdraw their funds at any time, without needing to ask permission from anyone. + +EIP-7514 brings a tightening to the issuance of ETH by capping the "churn" rate that validators can join the network to eight (8) per epoch. Since ETH issuance is proportional to total ETH staked, limiting the number of validators joining caps the _growth rate_ of newly issued ETH, while also reducing hardware requirements for node operators, helping decentralization. + + + + + EIP-4788 - Beacon block root in the EVM + EIP-4844 - Shard blob transactions + EIP-7044 - Perpetually valid signed voluntary exits + EIP-7045 - Increase max attestation inclusion slot + EIP-7514 - Add max epoch churn limit + + + + +- [Read the Deneb upgrade specifications](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/) +- [Cancun-Deneb ("Dencun") FAQ](/roadmap/dencun/) + + + +## 2023 + +### Shanghai-Capella ("Shapella") + + + +#### Shanghai summary + +The Shanghai upgrade brought staking withdrawals to the execution layer. In tandem with the Capella upgrade, this enabled blocks to accept withdrawal operations, which allows stakers to withdraw their ETH from the Beacon Chain to the execution layer. + + + + + EIP-3651 – Starts the COINBASE address warm + EIP-3855 – New PUSH0 instruction + EIP-3860 – Limit and meter initcode + EIP-4895 – Beacon chain push withdrawals as operations + EIP-6049 - Deprecate SELFDESTRUCT + + + + +- [Read the Shanghai upgrade specification](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md) + +#### Capella summary + +The Capella upgrade was the third major upgrade to the consensus layer (Beacon Chain) and enabled staking withdrawals. Capella occurred synchronously with the execution layer upgrade, Shanghai, and enabled staking withdrawal functionality. + +This consensus layer upgrade brought the ability for stakers who did not provide withdrawal credentials with their initial deposit to do so, thereby enabling withdrawals. + +The upgrade also provided automatic account sweeping functionality, which continuously processes validator accounts for any available rewards payments or full withdrawals. + +- [More on staking withdrawals](/staking/withdrawals/). +- [Read the Capella upgrade specifications](https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/) + + + +## 2022 + +### Paris (The Merge) + + + +#### Summary + +The Paris upgrade was triggered by the proof-of-work blockchain passing a [terminal total difficulty](/glossary/#terminal-total-difficulty) of 58750000000000000000000. This happened at block 15537393 on 15th September 2022, triggering the Paris upgrade the next block. Paris was [The Merge](/roadmap/merge/) transition - its major feature was switching off the [proof-of-work](/developers/docs/consensus-mechanisms/pow) mining algorithm and associated consensus logic and switching on [proof-of-stake](/developers/docs/consensus-mechanisms/pos) instead. Paris itself was an upgrade to the [execution clients](/developers/docs/nodes-and-clients/#execution-clients) (equivalent to Bellatrix on the consensus layer) that enabled them to take instruction from their connected [consensus clients](/developers/docs/nodes-and-clients/#consensus-clients). This required a new set of internal API methods, collectively known as the [Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md), to be activated. This was arguably the most significant upgrade in Ethereum history since [Homestead](#homestead)! + +- [Read the Paris upgrade specification](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md) + + + + + EIP-3675 – Upgrade consensus to Proof-of-Stake + EIP-4399 – Supplant DIFFICULTY opcode with PREVRANDAO + + + + +--- + +### Bellatrix + + + +#### Summary + +The Bellatrix upgrade was the second scheduled upgrade for the [Beacon Chain](/roadmap/beacon-chain), preparing the chain for [The Merge](/roadmap/merge/). It brings validator penalties to their full values for inactivity and slashable offenses. Bellatrix also includes an update to the fork choice rules to prepare the chain for The Merge and the transition from the last proof-of-work block to the first proof-of-stake block. This includes making consensus clients aware of the [terminal total difficulty](/glossary/#terminal-total-difficulty) of 58750000000000000000000. + +- [Read the Bellatrix upgrade specification](https://github.com/ethereum/consensus-specs/tree/dev/specs/bellatrix) + +--- + +### Gray Glacier + + + +#### Summary + +The Gray Glacier network upgrade pushed back the [difficulty bomb](/glossary/#difficulty-bomb) by three months. This is the only change introduced in this upgrade, and is similar in nature to the [Arrow Glacier](#arrow-glacier) and [Muir Glacier](#muir-glacier) upgrades. Similar changes have been performed on the [Byzantium](#byzantium), [Constantinople](#constantinople) and [London](#london) network upgrades. + +- [EF Blog - Gray Glacier Upgrade Announcement](https://blog.ethereum.org/2022/06/16/gray-glacier-announcement/) + + + + + EIP-5133 – delays the difficulty bomb until September 2022 + + + + + + +## 2021 + +### Arrow Glacier + + + +#### Summary + +The Arrow Glacier network upgrade pushed back the [difficulty bomb](/glossary/#difficulty-bomb) by several months. This is the only change introduced in this upgrade, and is similar in nature to the [Muir Glacier](#muir-glacier) upgrade. Similar changes have been performed on the [Byzantium](#byzantium), [Constantinople](#constantinople) and [London](#london) network upgrades. + +- [EF Blog - Arrow Glacier Upgrade Announcement](https://blog.ethereum.org/2021/11/10/arrow-glacier-announcement/) +- [Ethereum Cat Herders - Ethereum Arrow Glacier Upgrade](https://medium.com/ethereum-cat-herders/ethereum-arrow-glacier-upgrade-e8d20fa4c002) + + + + + EIP-4345 – delays the difficulty bomb until June 2022 + + + + +--- + +### Altair + + + +#### Summary + +The Altair upgrade was the first scheduled upgrade for the [Beacon Chain](/roadmap/beacon-chain). It added support for "sync committees"—enabling light clients, and increased validator inactivity and slashing penalties as development progressed towards The Merge. + +- [Read the Altair upgrade specification](https://github.com/ethereum/consensus-specs/tree/dev/specs/altair) + +#### Fun fact! + +Altair was the first major network upgrade that had an exact rollout time. Every upgrade prior had been based on a declared block number on the proof-of-work chain, where block times vary. The Beacon Chain does not require solving for proof-of-work, and instead works on a time-based epoch system consisting of 32 twelve-second "slots" of time where validators can propose blocks. This is why we knew exactly when we would hit epoch 74,240 and Altair became live! + +- [Block time](/developers/docs/blocks/#block-time) + +--- + +### London + + + +#### Summary + +The London upgrade introduced [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), which reformed the transaction fee market, along with changes to how gas refunds are handled and the [Ice Age](/glossary/#ice-age) schedule. + +#### What was the London Upgrade / EIP-1559? + +Before the London Upgrade, Ethereum had fixed-sized blocks. In times of high network demand, these blocks operated at full capacity. As a result, users often had to wait for demand to reduce to get included in a block, which led to a poor user experience. The London Upgrade introduced variable-sized blocks to Ethereum. + +The way transaction fees on the Ethereum network were calculated changed with [the London Upgrade](/history/#london) of August 2021. Before the London upgrade, fees were calculated without separating `base` and `priority` fees, as follows: + +Let's say Alice had to pay Bob 1 ETH. In the transaction, the gas limit is 21,000 units, and the gas price is 200 gwei. + +The total fee would have been: `Gas units (limit) * Gas price per unit` i.e `21,000 * 200 = 4,200,000 gwei` or 0.0042 ETH + +The implementation of [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) in the London Upgrade made the transaction fee mechanism more complex, but made gas fees more predictable, resulting in a more efficient transaction fee market. Users can submit transactions with a `maxFeePerGas` corresponding to how much they are willing to pay for the transaction to be executed, knowing that they will not pay more than the market price for gas (`baseFeePerGas`), and get any extra, minus their tip, refunded. + +This video explains EIP-1559 and the benefits it brings: [EIP-1559 Explained](https://www.youtube.com/watch?v=MGemhK9t44Q) + +- [Are you a dapp developer? Be sure to upgrade your libraries and tooling.](https://github.com/ethereum/execution-specs/blob/master/network-upgrades/london-ecosystem-readiness.md) +- [Read the Ethereum Foundation announcement](https://blog.ethereum.org/2021/07/15/london-mainnet-announcement/) +- [Read the Ethereum Cat Herder's explainer](https://medium.com/ethereum-cat-herders/london-upgrade-overview-8eccb0041b41) + + + + + EIP-1559 – improves the transaction fee market + EIP-3198 – returns the BASEFEE from a block + EIP-3529 - reduces gas refunds for EVM operations + EIP-3541 - prevents deploying contracts starting with 0xEF + EIP-3554 – delays the Ice Age until December 2021 + + + + +--- + +### Berlin + + + +#### Summary + +The Berlin upgrade optimized gas cost for certain EVM actions, and increases support for multiple transaction types. + +- [Read the Ethereum Foundation announcement](https://blog.ethereum.org/2021/03/08/ethereum-berlin-upgrade-announcement/) +- [Read the Ethereum Cat Herder's explainer](https://medium.com/ethereum-cat-herders/the-berlin-upgrade-overview-2f7ad710eb80) + + + + + EIP-2565 – lowers ModExp gas cost + EIP-2718 – enables easier support for multiple transaction types + EIP-2929 – gas cost increases for state access opcodes + EIP-2930 – adds optional access lists + + + + + + +## 2020 + +### Beacon Chain genesis + + + +#### Summary + +The [Beacon Chain](/roadmap/beacon-chain/) needed 16384 deposits of 32 staked ETH to ship securely. This happened on November 27, meaning the Beacon Chain started producing blocks on December 1, 2020. This is an important first step in achieving the [Ethereum vision](/roadmap/vision/). + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2020/11/27/eth2-quick-update-no-21/) + + + The Beacon Chain + + +--- + +### Staking deposit contract deployed + + + +#### Summary + +The staking deposit contract introduced [staking](/glossary/#staking) to the Ethereum ecosystem. Although a [Mainnet](/glossary/#mainnet) contract, it had a direct impact on the timeline for launching the [Beacon Chain](/roadmap/beacon-chain/), an important [Ethereum upgrade](/roadmap/). + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2020/11/04/eth2-quick-update-no-19/) + + + Staking + + +--- + +### Muir Glacier + + + +#### Summary + +The Muir Glacier fork introduced a delay to the [difficulty bomb](/glossary/#difficulty-bomb). Increases in block difficulty of the [proof-of-work](/developers/docs/consensus-mechanisms/pow/) consensus mechanism threatened to degrade the usability of Ethereum by increasing wait times for sending transactions and using dapps. + +- [Read the Ethereum Foundation announcement](https://blog.ethereum.org/2019/12/23/ethereum-muir-glacier-upgrade-announcement/) +- [Read the Ethereum Cat Herder's explainer](https://medium.com/ethereum-cat-herders/ethereum-muir-glacier-upgrade-89b8cea5a210) + + + + + EIP-2384 – delays the difficulty bomb for another 4,000,000 blocks, or ~611 days. + + + + + + +## 2019 + +### Istanbul + + + +#### Summary + +The Istanbul fork: + +- Optimised the [gas](/glossary/#gas) cost of certain actions in the [EVM](/developers/docs/ethereum-stack/#ethereum-virtual-machine). +- Improved denial-of-service attack resilience. +- Made [Layer 2 scaling](/developers/docs/scaling/#layer-2-scaling) solutions based on SNARKs and STARKs more performant. +- Enabled Ethereum and Zcash to interoperate. +- Allowed contracts to introduce more creative functions. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2019/11/20/ethereum-istanbul-upgrade-announcement/) + + + + + EIP-152 – allow Ethereum to work with privacy-preserving currency like Zcash. + EIP-1108 – cheaper cryptography to improve gas costs. + EIP-1344 – protects Ethereum against replay attacks by adding CHAINID opcode. + EIP-1884 – optimising opcode gas prices based on consumption. + EIP-2028 – reduces the cost of CallData to allow more data in blocks – good for Layer 2 scaling. + EIP-2200 – other opcode gas price alterations. + + + + +--- + +### Constantinople + + + +#### Summary + +The Constantinople fork: + +- Reduced block [mining](/developers/docs/consensus-mechanisms/pow/mining/) rewards from 3 to 2 ETH. +- Ensured the blockchain didn't freeze before [proof-of-stake was implemented](#beacon-chain-genesis). +- Optimised the [gas](/glossary/#gas) cost of certain actions in the [EVM](/developers/docs/ethereum-stack/#ethereum-virtual-machine). +- Added the ability to interact with addresses that haven't been created yet. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2019/02/22/ethereum-constantinople-st-petersburg-upgrade-announcement/) + + + + + EIP-145 – optimises cost of certain onchain actions. + EIP-1014 – allows you to interact with addresses that have yet to be created. + EIP-1052 – introduces the EXTCODEHASH instruction to retrieve the hash of another contract's code. + EIP-1234 – makes sure the blockchain doesn't freeze before proof-of-stake and reduces block reward from 3 to 2 ETH. + + + + + + +## 2017 + +### Byzantium + + + +#### Summary + +The Byzantium fork: + +- Reduced block [mining](/developers/docs/consensus-mechanisms/pow/mining/) rewards from 5 to 3 ETH. +- Delayed the [difficulty bomb](/glossary/#difficulty-bomb) by a year. +- Added ability to make non-state-changing calls to other contracts. +- Added certain cryptography methods to allow for [layer 2 scaling](/developers/docs/scaling/#layer-2-scaling). + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/) + + + + + EIP-140 – adds REVERT opcode. + EIP-658 – status field added to transaction receipts to indicate success or failure. + EIP-196 – adds elliptic curve and scalar multiplication to allow for ZK-Snarks. + EIP-197 – adds elliptic curve and scalar multiplication to allow for ZK-Snarks. + EIP-198 – enables RSA signature verification. + EIP-211 – adds support for variable length return values. + EIP-214 – adds STATICCALL opcode, allowing non-state-changing calls to other contracts. + EIP-100 – changes difficulty adjustment formula. + EIP-649 – delays difficulty bomb by 1 year and reduces block reward from 5 to 3 ETH. + + + + + + +## 2016 + +### Spurious Dragon + + + +#### Summary + +The Spurious Dragon fork was the second response to the denial of service (DoS) attacks on the network (September/October 2016) including: + +- tuning opcode pricing to prevent future attacks on the network. +- enabling “debloat” of the blockchain state. +- adding replay attack protection. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/) + + + + + EIP-155 – prevents transactions from one Ethereum chain from being rebroadcasted on an alternative chain, for example a testnet transaction being replayed on the main Ethereum chain. + EIP-160 – adjusts prices of EXP opcode – makes it more difficult to slow down the network via computationally expensive contract operations. + EIP-161 – allows for removal of empty accounts added via the DOS attacks. + EIP-170 – changes the maximum code size that a contract on the blockchain can have – to 24576 bytes. + + + + +--- + +### Tangerine whistle + + + +#### Summary + +The Tangerine Whistle fork was the first response to the denial of service (DoS) attacks on the network (September/October 2016) including: + +- addressing urgent network health issues concerning underpriced operation codes. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2016/10/18/faq-upcoming-ethereum-hard-fork/) + + + + + EIP-150 – increases gas costs of opcodes that can be used in spam attacks. + EIP-158 – reduces state size by removing a large number of empty accounts that were put in the state at very low cost due to flaws in earlier versions of the Ethereum protocol. + + + + +--- + +### DAO fork + + + +#### Summary + +The DAO fork was in response to the [2016 DAO attack](https://www.coindesk.com/learn/understanding-the-dao-attack/) where an insecure [DAO](/glossary/#dao) contract was drained of over 3.6 million ETH in a hack. The fork moved the funds from the faulty contract to a [new contract](https://eth.blockscout.com/address/0xbf4ed7b27f1d666546e30d74d50d173d20bca754) with a single function: withdraw. Anyone who lost funds could withdraw 1 ETH for every 100 DAO tokens in their wallets. + +This course of action was voted on by the Ethereum community. Any ETH holder was able to vote via a transaction on [a voting platform](https://web.archive.org/web/20170620030820/http://v1.carbonvote.com/). The decision to fork reached over 85% of the votes. + +Some miners refused to fork because the DAO incident wasn't a defect in the protocol. They went on to form [Ethereum Classic](https://ethereumclassic.org/). + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2016/07/20/hard-fork-completed/) + +--- + +### Homestead + + + +#### Summary + +The Homestead fork that looked to the future. It included several protocol changes and a networking change that gave Ethereum the ability to do further network upgrades. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2016/02/29/homestead-release/) + + + + + EIP-2 – makes edits to contract creation process. + EIP-7 – adds new opcode: DELEGATECALL + EIP-8 – introduces devp2p forward compatibility requirements + + + + + + +## 2015 + +### Frontier thawing + + + +#### Summary + +The frontier thawing fork lifted the 5,000 [gas](/glossary/#gas) limit per [block](/glossary/#block) and set the default gas price to 51 [gwei](/glossary/#gwei). This allowed for transactions – transactions require 21,000 gas. The [difficulty bomb](/glossary/#difficulty-bomb) was introduced to ensure a future hard-fork to [proof-of-stake](/glossary/#pos). + +- [Read the Ethereum Foundation announcement](https://blog.ethereum.org/2015/08/04/the-thawing-frontier/) +- [Read the Ethereum Protocol Update 1](https://blog.ethereum.org/2015/08/04/ethereum-protocol-update-1/) + +--- + +### Frontier + + + +#### Summary + +Frontier was a live, but barebone implementation of the Ethereum project. It followed the successful Olympic testing phase. It was intended for technical users, specifically developers. [Blocks](/glossary/#block) had a [gas](/glossary/#gas) limit of 5,000. This ‘thawing’ period enabled miners to start their operations and for early adopters to install their clients without having to ‘rush’. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2015/07/22/frontier-is-coming-what-to-expect-and-how-to-prepare/) + + + +## 2014 + +### Ether sale + + + +Ether officially went on sale for 42 days. You could buy it with BTC. + +[Read the Ethereum Foundation announcement](https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/) + +--- + +### Yellowpaper released + + + +The Yellow Paper, authored by Dr. Gavin Wood, is a technical definition of the Ethereum protocol. + +[View the Yellow Paper](https://github.com/ethereum/yellowpaper) + + + +## 2013 + +### Whitepaper released + + + +The introductory paper, published in 2013 by Vitalik Buterin, the founder of Ethereum, before the project's launch in 2015. + + + Whitepaper + +--- + +# Nft + +## Nft + +## What are NFTs? + +NFTs are tokens that are **individually unique**. Each NFT has different properties (non-fungible) and is provably scarce. This is different from tokens such as [ETH](/glossary/#ether) or other Ethereum based tokens like USDC where every token is identical and has the same properties ('fungible'). You don't care which specific dollar bill (or ETH) you have in your wallet, because they are all identical and worth the same. However, you _do_ care which specific NFT you own, because they all have individual properties that distinguish them from others ('non-fungible'). + +The uniqueness of each NFT enables tokenization of things like art, collectibles, or even real estate, where one specific unique NFT represents some specific unique real world or digital item. Ownership of an asset is publicly verifiable on Ethereum [blockchain](/glossary/#blockchain). + + + +## The internet of assets + +NFTs and Ethereum solve some of the problems that exist on the internet today. As everything becomes more digital, there's a need to replicate the properties of physical items like scarcity, uniqueness, and proof of ownership in a way that isn't controlled by a central organization. For example, with NFTs, you can own a music mp3 file across all Ethereum based apps and not be bound to one company's specific music app like Spotify or Apple Music. You can own a social media handle that you can sell or swap, but **can't be arbitrarily taken away from you** by a platform provider. + +Here's how an internet of NFTs compared to the internet most of us use today looks... + +### A comparison + +| An NFT internet | The internet today | +| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **You own your assets!** Only you can sell or swap them. | **You rent an asset** from some organization and it can be taken away from you. | +| NFTs are **digitally unique**, no two NFTs are the same. | **A copy often cannot be distinguished** from the original. | +| Ownership of an NFT is stored on the blockchain for anyone to **verify publicly**. | The access to ownership records of digital items is **controlled by institutions** – you must take their word for it. | +| NFTs are [smart contracts](/glossary/#smart-contract) on Ethereum. This means they **can easily be used in other smart contracts** and apps on Ethereum! | Companies with digital items usually **require their own "walled garden" infrastructure**. | +| Content **creators can sell their work anywhere** and can access a global market. | Creators rely on the infrastructure and distribution of the platforms they use. These are often subject to terms of use and **geographical restrictions**. | +| NFT creators **can retain ownership rights** over their own work, and program royalties directly into the NFT contract. | Platforms, such as music **streaming services, retain the majority of profits from sales**. | + +## What are NFTs used for? + +NFTs are used for many things, including: + +- proving that you attended an event +- certify that you completed a course +- ownable items for games +- digital art +- tokenizing real-world assets +- proving your online identity +- gating access to content +- ticketing +- decentralized internet domain names +- collateral in [decentralized finance](/glossary/#defi) + +Maybe you are an artist that wants to share their work using NFTs, without losing control and sacrificing your profits to intermediaries. You can create a new contract and specify the number of NFTs, their properties and a link to some specific artwork. As the artist, **you can program into the smart contract the royalties** you should be paid (e.g. transfer 5% of the sale price to the contract owner each time an NFT is transferred). You can also always prove that you created the NFTs because you own the [wallet](/glossary/#wallet) that deployed the contract. Your buyers can easily prove that they own an **authentic NFT** from your collection because their wallet [address](/glossary/#address) is associated with a token in your smart contract. They can use it across the Ethereum ecosystem, confident in its authenticity. + + + Explore, buy or create your own NFT art/collectibles... + + Explore NFT art + + + +Or consider a ticket to a sporting event. Just as an **organizer of an event can choose how many tickets to sell**, the creator of an NFT can decide how many replicas exist. Sometimes these are exact replicas, such as 5000 General Admission tickets. Sometimes several are minted that are very similar, but each slightly different, such as a ticket with an assigned seat. These can be bought and sold peer-to-peer without paying ticket handlers and the buyer always with assurance of the ticket authenticity by checking the contract address. + +On ethereum.org, **NFTs are used to demonstrate that people have meaningfully contributed** to our Github repository (programmed the website, written or modified an article...), translated our content, or attended our community calls, and we've even got our own NFT domain name. If you contribute to ethereum.org, you can claim a [POAP](/glossary/#poap) NFT. Some crypto meetups have used POAPs as tickets. [More on contributing](/contributing/#poap). + +![ethereum.org POAP](./poap.png) + +This website also has an alternative domain name powered by NFTs, **ethereum.eth**. Our `.org` address is centrally managed by a domain name system (DNS) provider, whereas ethereum`.eth` is registered on Ethereum via the Ethereum Name Service (ENS). And it's owned and managed by us. [Check our ENS record](https://app.ens.domains/name/ethereum.eth) + +[More on ENS](https://app.ens.domains) + + + +## How do NFTs work? + +NFTs, like any digital items on the Ethereum blockchain, are created through a special Ethereum based computer program called a "smart contract". These contracts follow certain rules, like the [ERC-721](/glossary/#erc-721) or [ERC-1155](/glossary/#erc-1155) standards, which determine what the contract can do. + +The NFT smart contract can do a few key things: + +- **Create NFTs:** It can make new NFTs. +- **Assign Ownership:** It keeps track of who owns which NFTs by linking them to specific Ethereum addresses. +- **Give Each NFT an ID:** Each NFT has a number that makes it unique. Additionally, there's usually some information (metadata) attached to it, describing what the NFT represents. + +When someone "creates" or "mints" an NFT, they're basically telling the smart contract to give them ownership of a particular NFT. This information is securely and publicly stored in the blockchain. + +Furthermore, the creator of the contract can add extra rules. They might limit how many of a certain NFT can be made or decide that they should get a small royalty fee whenever the NFT changes hands. + +### NFT security + +Ethereum's security comes from [proof-of-stake](/glossary/#pos). The system is designed to economically disincentivize malicious actions, making Ethereum tamper-proof. This is what makes NFTs possible. Once the [block](/glossary/#block) containing your NFT transaction becomes [finalized](/glossary/#finality) it would cost an attacker millions of ETH to change it. Anyone running Ethereum software would immediately be able to detect dishonest tampering with an NFT, and the bad actor would be economically penalized and ejected. + +Security issues relating to NFTs are most often related to phishing scams, smart contract vulnerabilities or user errors (such as inadvertently exposing private keys), making good wallet security critical for NFT owners. + + + More on security + + +## Further reading + +- [A beginner's guide to NFTs](https://linda.mirror.xyz/df649d61efb92c910464a4e74ae213c4cab150b9cbcc4b7fb6090fc77881a95d) – _Linda Xie, January 2020_ +- [EtherscanNFT tracker](https://etherscan.io/nft-top-contracts) +- [Blockscout NFT tracker](https://eth.blockscout.com/tokens?type=ERC-721,ERC-1155,ERC-404) +- [ERC-721 token standard](/developers/docs/standards/tokens/erc-721/) +- [ERC-1155 token standard](/developers/docs/standards/tokens/erc-1155/) +- [Popular NFT Apps and Tools](https://www.ethereum-ecosystem.com/blockchains/ethereum/nfts) + +## Other resources + +- [NFTScan](https://nftscan.com/) + +--- + +# Payments + +## Payments + +Every day, millions of people face the same challenge: moving money across borders is slow, expensive, and often frustrating. A freelancer in Bali waits days for payment to clear from their New York client. This particularly affects people in regions with limited banking infrastructure, making it difficult to participate in the global economy. + +This isn't a far-off dream – it's happening today on Ethereum. While traditional financial institutions have built robust payment systems over decades, they often remain constrained by borders, working hours, and legacy infrastructure. Ethereum offers a new paradigm: a global, 24/7 financial platform that enables near-instant, programmable transactions for anyone with internet access. + + + +![Ethereum logo on the computer screen](./computer.png) + + + +## Remittances: cheaper international transfers + +For millions of people working abroad, sending money back home is a regular necessity. Traditional remittance services often come with high fees and slow processing times. Ethereum offers a compelling alternative. + + + + + + + +## Access to Global Currencies + +In many countries, inflation is a pressing concern, often accompanied by limited access to foreign currencies. People in these situations struggle to preserve their wealth as they are forced to hold rapidly depreciating savings. + +The Ethereum community has created **a robust alternative financial system** that is independent of any nation’s monetary policies or control. + +Ethereum users can use **stablecoins—tokens typically tied to strong currencies like the US Dollar**. By earning and saving in cryptocurrency, people can protect themselves from high inflation in their country, helping to preserve or even grow their purchasing power. This also enables easier payments for goods and services, both locally and globally. + + + More on stablecoins + + +## Buying Goods and Payment for Services + +Many businesses are beginning to accept ether (ETH) and other cryptocurrencies as payment. For example: + +- **Newegg:** The popular electronics retailer accepts Ethereum for purchases in select countries. +- **Travala.com:** This travel booking platform allows users to pay for hotels and flights using Ethereum. +- **Shopify:** This popular E-commerce platform which serves as a platform for hosting businesses also accepts payments for goods and services using Ethereum. +- **Sotheby's:** This organisation trade fine and decorative art, jewellery, and collectibles and allows for payments using Ethereum and other cryptocurrencies. + +Countries like El Salvador and the Central African Republic have even adopted cryptocurrencies as legal tender, paving the way for wider acceptance of Ethereum payments in everyday transactions. + +In countries where their means of payment have been disconnected from the rest of the world, crypto-integrated payment solutions have been a huge relief. Payments of subscriptions for platforms like Netflix, Spotify, and educational courses have now been made easy through crypto payment platforms like Gnosis Pay and Paypal. + + + Create your Ethereum account with a wallet app today. + + Get started + + + +## Salary Payments + +Many forward-thinking companies are now offering employees the option to receive their salaries, or a portion of them, in cryptocurrencies like ether (ETH): + +- **Gipsybee:** is an organisation that deals in electronics, robotics, game creation and other services. They give employees the option to get paid in Ethereum. +- **SC5:** This Finnish company was one of the first to offer salaries in Bitcoin, paving the way for similar arrangements with Ethereum. +- **Blockchain startups:** Many companies in the blockchain space naturally offer cryptocurrency salary options to their employees. +- **DAOs:** Due to the peculiarity and diversity of contributors to DAOs, most contributions and salaries are rewarded in cryptocurrency. + +This trend particularly appeals to remote workers and digital nomads who can benefit from borderless payments and potentially favorable exchange rates. + + + +## Global relief efforts + +In February 2023, when devastating earthquakes struck Turkey and Syria, the global crypto community sprang into action. Various campaigns were launched to collect funds for relief efforts, showcasing the power of Ethereum in times of crisis. Despite crypto [not being a recognized form](https://www.reuters.com/technology/no-more-kebabs-bitcoins-turkeys-crypto-payment-ban-looms-2021-04-28/) of payment in Turkey, authorities made [exceptions](https://x.com/haluklevent/status/1622913175409623041) for some organizations to collect donations. Some examples are: + +- [Refik Anadol](https://x.com/refikanadol/status/1622623521104089090): is a renowned digital artist who initiated a fundraising campaign. +- DAO Power: [Anka Relief DAO](https://ankarelief.org/) and [Bankless DAO](https://x.com/banklessDAO) joined forces with [Giveth](https://x.com/Giveth/status/1623493672149843969) to raise funds. +- [Pak](https://cause.quest/), a prominent NFT artist, also contributed to the cause. +- Even Ethereum co-founder [Vitalik Buterin](https://cointelegraph.com/news/vitalik-buterin-donates-227k-to-help-earthquake-victims-in-turkey-syria) made personal donations to multiple campaigns. +The result of this? Over $6 million was raised in a matter of days, as tracked by a [Dune](https://dune.com/davy42/turkiye-earthquake-donations) Analytics dashboard. + +There were also similar response times for tragedies that happened in India and Ukraine. This rapid response highlights a crucial advantage of Ethereum payments, which is the ability to quickly mobilize global support without the hurdles of currency conversion, lengthy bank transfers, or exorbitant fees. + + +![Ethereum Robot Image](./eth_robot.png) + + + +## Ethereum vs fiat + +To truly appreciate the impact of Ethereum payments, it's worth comparing them to traditional fiat currencies: + +| | **Ethereum** | **Traditional banks** | +| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Speed** | Seconds to minutes | Hours to days | +| **Global Reach** | Borderless, 24/7 | Subject to international banking restrictions and work hours | +| **Transparency** | Fully transparent | Varies by institution | +| **Programmability** | Smart contracts enabled | Limited to basic transactions | +| **Inflation Control** | Predictable issuance | Subject to central bank policies | +| **Accessibility** | Anyone with internet | Subject to national and international restrictions | + +At its core, Ethereum is a decentralized platform that allows for secure, fast, and transparent transactions. However, many components set it apart from traditional payment methods. Let's dive into the benefits that make Ethereum payments a game-changer: + +### Programmability + +One of Ethereum's unique features is its ability to support smart contracts. Smart contracts are self-executing agreements with the terms directly written into code. This opens up a world of possibilities for automated, condition-based payments that can greatly improve transactions like: + +- Escrow services +- Recurring payments +- Performance-based compensation + +### Speed + +Do you remember the last time you waited days for an international bank transfer to clear? The long queue? And the multiple forms you had to fill? With Ethereum, those days are long gone. Transactions on the Ethereum network settle in minutes, regardless of where the sender and recipient are located. Due to Ethereum being permissionless, there is no regulatory bureaucracy when sending money. This speed is particularly crucial in time-sensitive situations, such as emergency relief efforts. + +### Lower Fees + +Traditional international money transfers fees sometimes eat up a significant portion of the amount sent, especially when dealing with transactions in the hundreds of dollars. Ethereum transactions, while not free, often come with lower fees. This means more of your money goes where you intend it to, rather than lining the pockets of intermediaries. + +### Transparency + +Every transaction on the Ethereum blockchain is recorded on a public ledger. This means anyone can verify the movement of funds, making it an excellent tool for: + +- Charitable organizations to demonstrate how donations are used +- Businesses to prove payments to suppliers or employees +- Individuals to keep track of their financial activities + +With Ethereum, everyone can see how money moves and how costs are implemented, unlike traditional organisations where most of these remain unknown. + + +![walking image](./walking.png) + + + +While fiat currencies have the advantage of widespread acceptance and stability, Ethereum offers unique benefits that make it an attractive option for certain types of transactions. + +From facilitating rapid disaster relief to empowering global workers, Ethereum payments are writing a new chapter in the long history of money. While challenges remain, the unique advantages offered by this technology make it an attractive option for a wide range of use cases. + + + Time to get your own Ethereum account. + + Get started + +--- + +# Prediction Markets + +## Prediction Markets + +Prediction markets use crowd wisdom and financial incentives to forecast events. They offer diverse, high-quality data and gained traction during the 2024 U.S. elections. + +## How prediction markets work + +Unlike traditional forecasting methods that rely on expert opinions, limited survey samples or historical data, prediction markets leverage **real-time financial incentives** and **crowd wisdom** to generate insights relating to a particular event—elections, crypto prices, sports outcomes—anything.  + +This allows anyone to signal support for a specific outcome with a financial commitment. +  +By enabling betting on real-world events and adjusting the prices as new information arises, informed opinions are valued higher, and accuracy can be rewarded.  + +In theory, because bettors stand to profit from being correct, prediction markets can forecast outcomes with great precision. Blockchain-based prediction markets are even more exciting, as virtually anyone can take part in the forecasting and earn stablecoin or cryptocurrency rewards. + +## Why does this matter? + +Unlike traditional forecasting, blockchain-based prediction markets are: + + + + + + + +Even as an observer of the market, you can assess valuable data that would be otherwise unavailable. Think of it like this: + +1. Predictions are tied to a specific event (e.g. Will Beam Chain deploy by 2030?). +2. Market participants buy and sell shares based on their confidence in any outcome. +3. Prices adjust as more participants stake their beliefs, reflecting real-time insights. +4. Anyone betting correctly earns proportionately to the amount staked.  +5. Market observers can leverage the open data to inform research or discussion. + +## Find a prediction market + +There are several Ethereum-based prediction markets available. These are some of the most well-known prediction markets today: + + + + + Stay mindful of the risks + Only bet what you can afford, and be aware of potential addictive behaviors. + + +## Challenges & Risks + +Prediction markets on the blockchain face few challenges that can impact fairness, legality, and accuracy. + +⚠️ **Market Manipulation** – Wealthy players can distort outcomes through wash trading. +💧 **Liquidity Issues** – Low participation ([thin liquidity](https://www.investopedia.com/terms/t/thinmarket.asp)) can reduce market reliability. +🏛 **Regulatory Uncertainty** – Governments have imposed restrictions on some platforms. + +To mitigate these issues, Ethereum developers are experimenting with solutions like futarchy (governance by prediction markets) and decentralized identity verification. + +## Experimenting with prediction markets + +Prediction markets are reshaping decision-making in the digital age. By leveraging Ethereum, they offer **fair, open, and rewarding ways to predict the future.** + +There are many ways to use forecasting tools outside of financial gain. For example, in a [DevCon Improvement Proposal](https://forum.devcon.org/t/futarchy-decision-markets-for-deciding-next-devcon/5305) (DIP) it was suggested that the organizers of DevCon use prediction markets to anticipate attendance for future events.  + +This would help the organizers determine which location would lead to the largest event, compared to which location would lead to the most internationally accessible. The benefits of this mean the organizers of DevCon can expedite the amount of time required to screen multiple +visa policies, airport access, and cost of living in the area while also gathering data on where prospective attendees would be excited to go. + +## Further reading + +[From prediction markets to info finance](https://vitalik.eth.limo/general/2024/11/09/infofinance.html) - Vitalik Buterin +[Decentralized Prediction Market Development on Ethereum](https://blockchain.oodles.io/dev-blog/decentralized-prediction-market-development-ethereum/) +[The Augur Project Whitepaper](https://github.com/AugurProject/whitepaper) + +--- + +# Privacy Policy + +## Privacy Policy + +# Privacy Policy + +**1. General information** + +Stiftung Ethereum, a Swiss Stiftung, located at Zeughausgasse 7a, 6300 Zug, Switzerland (the “Foundation”, “we”, or “us”) is the operator of any Website published by the Foundation, including, but not limited to, ethereum.org, ethereum.foundation, esp.ethereum.foundation, devcon.org, devconnect.org, and blog.ethereum.org (the “Websites”). + +As the operator of the Websites, we take the protection of your personal data very seriously. We collect, process, and use your personal data in accordance with this privacy policy and in compliance with the Swiss Federal Act on Data Protection (“FADP”), the Swiss Ordinance to the Federal Act on Data Protection (“OFADP”), and the General European Data Protection Regulation (“GDPR”). + +This privacy policy (“Privacy Policy”) will provide you with information about the collection, processing and use of your personal data when using the Websites. + +In case you provide us with the personal data of third persons (such as family members or work colleagues) you should make sure that these persons are familiar with this Privacy Policy and you should only share their personal data if you have permission to do so and ensure that his personal data is correct. + +**2. Responsible Person** + +For any matters, relating to data protection you may contact notices@ethereum.org in writing by e-mail or letter to the following address: + + Ethereum Foundation + Zeughausgasse 7A, + 6302 Zug, Switzerland + Email: notices@ethereum.org + +Our representative in the EU according to article 27 GDPR is: + + Ethereum Dev GmbH + Oranienstrasse 6, 10997 Berlin + Email: notices@ethereum.org + +**3. Data processing in connection with the Websites** + +**3.1 Visiting our Websites** + +When you visit our Websites, the hosting provider(s) of our Websites may automatically collect and store various information in server log files that your browser transmits to us. The information/data mentioned is neither assigned to specific persons nor linked to data from other sources. The following technical data may be recorded by us, as usual with every connection with a web server, without your intervention, and stored by us until automatic deletion after no later than two days: + +- Woocommerce cart data +- Unique identification code for Woocommerce customer +- Anonymized IP addresses + +Any collection and processing of this technical data is for the purpose of enabling the use of our Websites, continuously ensuring system security and stability, optimising our Websites, and for internal statistical purposes. This is our legitimate interest in the processing of data in the sense of Art. 6 Par. 1 lit. f GDPR. + +Furthermore, the IP addresses may be evaluated, together with other data, in case of attacks on the network infrastructure or other unauthorised use or misuse of the Websites, for the purpose of intelligence and protection, and if appropriate, used in criminal proceedings for identification and civil and criminal proceedings against the relevant users. This is our legitimate interest in the processing of data in the sense of Art. 6 Par. 1 lit. f GDPR. + +**3.2 Use of Website Cookies** + +The Websites may use cookies. Cookies are text files that are stored in a computer system via an Internet browser. More detailed information on cookies and how they work can be found at: http://www.allaboutcookies.org. + +Many Internet sites and servers use cookies. Many cookies contain a so-called cookie ID. A cookie ID is a unique identifier of the cookie. It consists of a character string through which Internet pages and servers can be assigned to the specific Internet browser in which the cookie was stored. This allows visited Internet sites and servers to differentiate the individual browser of the data subject from other Internet browsers that contain other cookies. A specific Internet browser can be recognized and identified using the unique cookie ID. + +Through the use of cookies, the Foundation may provide the users of the Websites with more user-friendly services that would not be possible without the cookie setting. + +Cookies may allow us, as previously mentioned, to recognize our Website users. The purpose of this recognition is to make it easier for users to utilize our Websites. The Website user that uses cookies, e.g. does not have to enter access data each time the Website is accessed, because this is taken over by the Website, and the cookie is thus stored on the user's computer system. + +You may, at any time, prevent the setting of cookies through our Websites by means of a corresponding setting of the Internet browser used, and may thus permanently deny the setting of cookies. Furthermore, previously set cookies may be deleted at any time via an Internet browser or other software programs. This is possible in all popular Internet browsers. If the data subject deactivates the setting of cookies in the Internet browser used, it may not be possible to use all the functions of our Websites. + +For detailed information on the cookies we use and the purposes for which we use them, see our Cookie Policy. + +**3.3 Matomo Analytics** + +The Websites may use Matomo, an open source web analytics platform ("Matomo Analytics"). Where this is true, the information generated by the cookies about your use of the Websites (including your automatically anonymized IP address) may be stored on the servers of our hosting provider(s) in the United States. For more information about Matomo Analytics, you can access a demo version at: https://demo.matomo.cloud. + +Before the data is stored, the IP address will be abbreviated by activating IP anonymization (anonymizeIP) on this Website. + +In addition to the data listed in section 3.1, we may receive the following information because of Matomo Analytics: + +- Usage data; +- Navigation path; +- Length of stay on the Website; +- Returning or new user; and/or +- End device. + +We may use this technical data to analyze your use of the Websites by compiling reports on Website activity for the understanding and/or optimizing of our Websites and/or for internal statistical purposes. We do not use the information and personal data collected by Matomo to identify individuals unless we become aware of specific indications of illegal use. + +Any processing of this technical personal data helps us to identify what is working and what is not on our Websites and how we may improve our Websites. Without any data thus received, we may not be able to provide you the service we are currently offering to you. Your data will be used only to improve the user experience on our Websites and help you find the information you are looking for. This is our legitimate interest in the processing of data in the sense of Art. 6 Par. 1 lit. f GDPR. + + + +**3.4 Opening an account for the Ethereum Web Forum** + +To access our forums at https://forum.ethereum.org/ you must set up an account and provide us with your username, e-mail address, skype name, and password. + +The collected data, which you have voluntarily provided, is used for the purpose of providing your password-protected access to your base data we have stored. The legal basis for processing the data for this purpose lies in the consent you have provided in accordance with Art. 6 Par. 1 lit. a GDPR. + +**3.5 Contact possibility via the Websites** + +You may contact us via our Websites’ contact page or by e-mail to the following e-mail address: support@ethereum.org. For this, we require the following information: Name, Subject, E-Mail address, message. + +We use this data, which you may give voluntarily, only in order to answer your contact question or to reply to your e-mail in the best possible manner. Therefore, the processing of this data is in our legitimate interest in accordance with Art. 6 Par. 1 lit. f GDPR and you have provided consent in accordance with Art. 6 Par. 1 lit. a GDPR. + +**3.6 Registration for our newsletter (if relevant)** + +The receipt of our newsletter requires registration. For this you must provide your name and e-mail address. By registering, you give us your consent to process the given data in order to periodically send the newsletter to the address you have given. This consent constitutes the legal basis for our processing of your e-mail address in the sense of Art. 6 Par. 1 lit. a GDPR. All information gathered this way will never be passed on or sold to any third party. + +At the end of each newsletter a link is provided by means of which you can unsubscribe at any time. After unsubscribing your personal data will be deleted. + +**3.7 Social Media** + +We may use plug-ins from social networks such as Blog, GitHub, YouTube, Reddit, Gitter, Twitter, StackExchange, Facebook, or Meetups on our Websites. When you activate them by clicking on them, the operators of the respective social networks may record that you are on our Websites and may use this information. This processing of your personal data lays in the responsibility of these individual social media platforms and occurs according to their privacy policy. Please check with these individual social media platforms regarding their privacy policies. The Foundation is not responsible for data collected by these individual social media platforms. We only use these platforms to inform our community of updates and answer user questions. + +**3.8 Event Registration** + +To register for any event organized by the Foundation through our Websites, we may require the following registration data: First and last name, language, company affiliation, company title, credit card information, e-mail address. + +We may use this information as well as other information you voluntarily provide (e.g. preferences, comments) only in order to execute the reservation agreement, unless otherwise stated in this Privacy Policy or you have not specifically consented thereto. + +We may process the data by name in order to record your reservation as you have requested, to contact you in case of a question or problem and to ensure correct payment. + +The legal basis for the data processing for this purpose lies in the fulfillment of an agreement in accordance with Art. 6 Par. 1 lit. b GDPR. + +**4. Other parties who have access to information we collect** + +With the exception of the provider(s) of our Websites, we do not make your personal data available to third parties unless you have expressly consented to it, if we are legally obligated to, or if this is necessary to enforce our rights concerning a contractual relationship. + +Personal data collected via the Websites may be passed on to and/or accessed by the Website service provider(s). The Websites may be hosted on servers in the US. The transfer of data is for the purpose of providing and maintaining the functionality of our Websites. This is our legitimate interest in the sense of Art. 6 Par. 1 lit f GDPR. + +If you pay by credit card through the Websites, we may forward your credit card information to the credit card issuer and the credit card acquirer. If you choose to pay by credit card, you may be asked to provide all the necessary information. The legal basis for passing on the data lies in the fulfillment of an agreement in the sense of Art. 6 Par. Lit. b GDPR. + +**5. International transfer of personal data** + +We are entitled to transfer your personal data to third parties abroad for the purposes of the data processing described in this Privacy Policy. This concerns especially the following receiver(s): + +- Our Websites service providers; and/or +- E-commerce providers such as payment solution providers to assist us in the processing of your online payments. + +They are obliged to protect data privacy to the same extent as we ourselves. If the level of data protection in a given country does not correspond to the Swiss and European data protection level, we contractually ensure that the protection of your personal data corresponds to that in Switzerland and the EU at all times by concluding agreements using the standard contractual clauses and complying with the GDPR. + +**6. Data security** + +We use appropriate technical and organizational security measures to protect your stored personal data against manipulation, partial or complete loss, and unauthorized access by third parties. Our security measures are continuously being improved in line with technical developments. + +Please note that any data transmission on the Internet (e.g. communication by e-mail) is generally not secure and we accept no liability for data transmitted to us via the Internet. Unfortunately, absolute protection is not technically possible. + +This information does not apply to the Websites of third parties and the corresponding links given on our Websites. The Foundation assumes no responsibility and liability for these. + +**7. Your Rights regarding your data** + +**7.1 Right to confirmation** + +You have the right to obtain confirmation from the Foundation as to whether or not personal data concerning you is being processed. If you wish to avail yourself of this right of confirmation, you may, at any time, contact the responsible person as stated in section 1 of this Privacy Policy. + +**7.2 Right to access** + +You have the right to obtain from the Foundation free information about your personal data stored at any time and a copy of this information. Furthermore, you will have access to the following information: + +- the purposes of the processing; +- the categories of personal data concerned; +- the recipients or categories of recipients to whom the personal data have been or will be disclosed, in particular recipients in third countries or international organizations; +- where possible, the envisaged period for which the personal data will be stored, or, if not possible, the criteria used to determine that period; +- the existence of the right to request from the Foundation rectification or erasure of personal data, or restriction of processing of personal data concerning you, or to object to such processing; +- the existence of the right to lodge a complaint with a supervisory authority; +- where the personal data are not collected directly from you, any available information as to their source; and +- the existence of automated decision-making, including profiling, referred to in Article 22(1) and (4) of the GDPR and, at least in those cases, meaningful information about the logic involved, as well as the significance and envisaged consequences of such processing for you. + +If you wish to avail yourself of this right of access, you may at any time contact the responsible person as stated in section 1 of this Privacy Policy. + +**7.3 Right to rectification** + +You have the right to obtain from the Foundation, without undue delay, the rectification of inaccurate personal data concerning you. Taking into account the purposes of the processing, you shall have the right to have incomplete personal data completed, including by means of providing a supplementary statement. If you wish to exercise this right to rectification, you may, at any time, contact the responsible person as stated in section 1 of this Privacy Policy. + +**7.4 Right to erasure (right to be forgotten)** + +You have the right to obtain from the Foundation the erasure of personal data concerning you as soon as possible, and the Foundation shall have the obligation to erase personal data without undue delay where one of the following grounds applies: + +- The personal data is no longer necessary in relation to the purposes for which they were collected or otherwise processed; +- You withdraw consent to which the processing is based according to point (a) of Article 6(1) of the GDPR, or point (a) of Article 9(2) of the GDPR, and where there is no other legal ground for the processing; +- The data subject objects to the processing pursuant to Article 21(1) of the GDPR and there are no overriding legitimate grounds for the processing, or the data subject objects to the processing pursuant to Article 21(2) of the GDPR; +- The personal data has been unlawfully processed; +- The personal data must be erased for compliance with a legal obligation in accordance with the applicable law to which the Foundation is subject; and/or +- The personal data has been collected in relation to the offer of information society services referred to in Article 8(1) of the GDPR. + +If any one of the aforementioned reasons applies, and you wish to request the erasure of personal data stored by the Foundation, you may at any time contact the responsible person as stated in section 1 of this Privacy Policy. The responsible person at the Foundation shall promptly ensure that the erasure request is complied with as soon as possible. + +**7.5 Right to restriction of processing** + +You have the right to obtain from the Foundation restriction of processing where one of the following applies: + +- the accuracy of the personal data is contested by you, for a period enabling the Foundation to verify the accuracy of the personal data; +- the processing is unlawful and you oppose the erasure of the personal data and requests instead the restriction of their use instead; +- the Foundation no longer needs the personal data for the purposes of the processing, but they are required by you for the establishment, exercise or defense of legal claims; and/or +- the data subject has objected to processing pursuant to Article 21(1) of the GDPR pending the verification whether the legitimate grounds of the Foundation override those of the data subject. + +If any one of the aforementioned conditions is met, and you wish to request the restriction of the processing of personal data stored by the Foundation, you may at any time contact the Foundation's responsible person. The responsible person will arrange the restriction of the processing. + +**7.6 Right to object** + +You have the right to object, on grounds relating to your particular situation, at any time, to the processing of personal data concerning you, which is based on point (e) or (f) of Article 6(1) of the GDPR. This also applies to profiling based on these provisions. + +The Foundation shall no longer process the personal data in the event of the objection, unless the Foundation can demonstrate reasonable grounds for the processing, which override the interests, rights and freedoms of you, or for the establishment, exercise or defense of legal claims. In order to exercise the right to object, you may directly contact the responsible person. + +**7.7 Automated individual decision-making, including profiling** + +You have the right not to be subject to a decision based solely on automated processing, including profiling, which produces legal effects concerning you, or similarly significantly affects you, as long as the decision (1) is not necessary for entering into, or the performance of, a contract between you and the Foundation, or (2) is not authorized by the applicable law and which also lays down suitable measures to safeguard your rights and freedoms and legitimate interests, or (3) is not based on your explicit consent. + +If the decision (1) is necessary for entering into, or the performance of, a contract between you and the Foundation, or (2) it is based on your explicit consent, the Foundation shall implement suitable measures to safeguard your rights and freedoms and legitimate interests, at least the right to obtain human intervention on the part of the controller, to express their point of view and contest the decision. + +Please note that the Foundation does not use automatic decision-making but we may use profiling according to these Privacy Policy rules. + +**7.8 Right to withdraw data protection consent** + +You have the right to withdraw your consent to processing of your personal data at any time. +If you wish to exercise the right to withdraw the consent, you may at any time directly contact the responsible person as stated in section 1. + +**8. Duration of the storage** + +The Foundation will process and store the personal data of the data subject only for the period necessary to achieve the purpose of storage, or as far as this is granted by the applicable laws or regulations. If the storage purpose is not applicable, or if a storage period prescribed by the applicable laws expires, the personal data is routinely erased in accordance with the legal requirements. + +**9. Minors** + +The Foundation does not knowingly collect or use any personal data from minors. A minor may be able to willingly share personal information with others, depending on the products and/or media channels used. If a minor provides us with their information without the consent of their parent or guardian, we will ask the parent or guardian to contact us for the purpose of deleting that information. + +**10. Updates to our Privacy Policy** + +The Foundation may update this Privacy Policy from time to time and inform you on the Websites that the policy has been amended. The current version of the Privacy Policy, as published on our Website, is applicable. With each update to our policies, we will note which sections have been updated. + +**11. More information about privacy regulations** + +For more information on applicable privacy regulations, you may refer +to: + +- EU General Data Protection Regulation: + https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=uriserv:OJ.L_.2016.119.01.0001.01.ENG +- Swiss Federal Act on Data Protection: + https://www.admin.ch/opc/en/classified-compilation/19920153/index.html +- Swiss Ordinance to the Federal Act on Data Protection: + https://www.admin.ch/opc/en/classified-compilation/19930159/index.html + +Please do not hesitate to contact us if you have any questions regarding +this Privacy Policy by contacting us at [support@ethereum.org](mailto:support@ethereum.org). + +--- + +# Real World Assets + +## Real World Assets + +Real-world assets (RWAs) are tokens representing existing forms of wealth, such as real estate, gold, stocks, art, machinery or collectibles. Tokenizing these items translates them into digital form, allowing them to be divided between multiple owners and making it easier to trade them. + +## What are RWAs? + +Some RWAs are tangible—items you can see and touch, such as gold bars or commercial buildings. Others are intangible, such as government debt, intellectual property, or equity in a company. + +When tokenized, these assets are turned into units of value. Tokenized gold is a good example of how this works. The company [Paxos](https://www.paxos.com/) translates 400-ounce gold bars into 400 tokens on the Ethereum blockchain, each backed by one ounce of gold. Token-holders can redeem their tokens for gold at any point. That’s also the case for tokens purchased from another RWA company, [Tether Gold](https://gold.tether.to/). + +Each token can be divided into even smaller fractions. Tether Gold tokens, for instance, can be split into parts as small as 0.000001. + +RWA tokens don’t have any intrinsic value. Rather, they reflect the value of the item that they represent, and so the token’s value changes along with the item’s value. + +## What are the benefits of RWAs? + + + + + + + + + + +## How do RWAs work? + +Let’s look at a few examples from across the RWA ecosystem: real estate, traditional financial products, and fine art. + +### Investing in real estate + +Say that you’d like to invest in real estate, but purchasing an entire property is out of reach. Instead, you could buy RWAs through a project such as [RealT](https://realt.co/). Its tokens represent shares in a limited liability company (LLC) created to hold a property’s deed. Token-holders receive rental income in the form of stablecoins according to the fraction they hold; RealT says it has so far returned $15 million USD in net rental income to investors. + +Another project along the same lines, [LABS Group](https://x.com/labsgroupio), allows people to buy into tokenized real estate with amounts as small as $100 USD. + +### Investing in financial products + +Several projects bridge the world of traditional finance and decentralized finance (DeFi) by bringing securities, stocks, bonds and other financial instruments onto the blockchain. + +For example, the Ethereum-based company [Securitize](https://securitize.io/) specializes in tokenizing traditional financial products. In 2024, it partnered with BlackRock to launch a RWA fund. BlackRock says it plans to eventually tokenize $10 trillion USD of its assets: its CEO, Larry Fink, called tokenization “the next generation for markets”. + +### Investing in fine art + +There are a few different mechanisms for fine-art investment. [Masterworks](https://www.masterworks.com/) buys artwork, securitizes each piece, and sells shares in the form of tokens. It plans to later sell the artwork and distribute the profits to token-holders. + +Art owners looking to capitalize on their collection can sell up to 49 per cent of an artwork’s value on the platform [Maecenas](https://www.maecenas.co/), provided the piece is valued at more than $1 million USD. + +In both cases, token-holders don’t control the storage or future sale of the artwork. Rather, they’re in charge of how long they hold onto their tokens, which rise and fall with the value of the art. + +Meanwhile, the blockchain-based digital art registry [Artory](https://www.artory.com/) verifies the authenticity of artworks and records past ownership. + +### Investing in collectibles + +So far, most of these examples demonstrate how tokenization allows partial ownership of various types of wealth. Another benefit of tokenization is that it enables the trade of valuable items, such as collectibles, on the global market. + +One example of this is [Courtyard](https://courtyard.io/), which tokenizes trading cards–think of baseball cards, football cards or Pokemon cards. Card owners ship their cards to a secure storage facility in the USA. The cards are minted as digital tokens and added to the owners’ wallets for trading on Courtyard’s marketplace. Courtyard only accepts graded cards: that’s where a third party has certified a card’s authenticity and awarded it a score based on its condition, whether dilapidated or pristine. + +Courtyard also offers a type of royalty scheme. Each time a card is sold, the person who tokenized it receives one percent of the revenue. Only card originators are rewarded in this way. At any point, an owner can swap their digital cards for physical cards, no matter where they are located in the world. + +## What are the limitations of RWAs? + +One of the challenges of RWAs, at this early stage, involves ensuring the connection between real-life objects and their digital representations. + +A green flag is when RWA projects supply investors with proof of reserves–the guarantee that they are the legal owners of the physical objects backing digital tokens. Think of Paxos, Tether Gold, or Courtyard, mentioned earlier, all of which hold their assets in secure storage and offer owners the option of swapping a token for its physical equivalent at any point. + +Another limitation is whether token ownership is recognised by legal systems around the world. In other words, are smart contracts enforceable in a court of law, or can the holder of a RWA token claim ownership of the real-life item? + +Some of the frontrunners in terms of setting up legal frameworks specifically to recognise tokenization include Singapore, the United Arab Emirates, Hong Kong, and Switzerland, which introduced legislation in 2021 nicknamed the ‘Blockchain Act’ to regulate technologies such as tokenization. The European Union has begun the process of regulating RWAs, while in the United States, the Securities and Exchange Commission is expected to issue guidance on RWAs at some point. + +## Learn more + +Dive into [smart contracts](/smart-contracts/) or find out more about a different token class, [non-fungible tokens (NFT)](/nft/). + +## Further reading + +- [What is asset tokenization?](https://www.britannica.com/money/real-world-asset-tokenization) on Britannica +- [How tokenization is transforming global finance and investment](https://www.weforum.org/stories/2024/12/tokenization-blockchain-assets-finance/) on the World Economic Forum +- [What crypto investors need to know about tokenizing real-world assets](https://www.forbes.com/sites/irinaheaver/2024/03/14/what-crypto-investors-need-to-know-about-tokenizing-real-world-assets/) on Forbes +- [How smart contracts work with blockchain](https://www.britannica.com/money/how-smart-contracts-work) on Britannica +- [How tokenized real-world assets are transforming DeFi](https://medium.com/coinmonks/how-tokenized-real-world-assets-are-transforming-defi-4e040f28732a) on Medium +- [What is RWA in crypto? Its blockchain role explained](https://www.bitdegree.org/crypto/tutorials/what-is-rwa-in-crypto) on BitDegree +- [Top real-world assets (RWAs) coins today by market cap](https://www.forbes.com/digital-assets/categories/real-world-assets-rwa/) on Forbes + +--- + +# Refi + +## Refi + +## What is ReFi? + +**Regenerative finance (ReFi)** is a set of tools and ideas built on top of [blockchains](/glossary/#blockchain), that aim to create economies which are regenerative, rather than extractive or exploitative. Eventually, extractive systems deplete the resources available and collapse; without regenerative mechanisms, they lack resilience. ReFi operates on the assumption that the creation of monetary value must be decoupled from the unsustainable extraction of resources from our planet and communities. + +Instead, ReFi aims to solve environmental, communal, or social problems by creating regenerative cycles. These systems create value for participants while simultaneously benefiting ecosystems and communities. + +One of the foundations of ReFi is the concept of regenerative economics pioneered by John Fullerton of the Capital Institute. He proposed [eight interconnected principles](https://capitalinstitute.org/8-principles-regenerative-economy/) that underlie systemic health: + +![Eight interconnected principles](refi-regenerative-economy-diagram.png) + +ReFi projects realize these principles using [smart contracts](/glossary/#smart-contract) and [decentralized finance (DeFi)](/glossary/#defi) applications to incentivize regenerative behaviors, e.g. restoring degraded ecosystems, and facilitate large-scale collaboration on global issues such as climate change and biodiversity loss. + +ReFi also overlaps with the [decentralized science (DeSci)](/desci/) movement, which uses Ethereum as a platform to finance, create, review, credit, store, and disseminate scientific knowledge. DeSci tools could become useful for developing verifiable standards and practices for implementing and monitoring regenerative activities like planting trees, removing plastic from the ocean, or restoring a degraded ecosystem. + + + +## Tokenization of carbon credits + +The **[voluntary carbon market (VCM)](https://climatefocus.com/so-what-voluntary-carbon-market-exactly/)** is a mechanism for funding projects that make a verified positive impact on carbon emissions, either reducing ongoing emissions, or removing greenhouse gases already emitted from the atmosphere. These projects receive an asset called "carbon credits" after they are verified, which they can sell to individuals and organizations who want to support climate action. + +In addition to the VCM, there are also several government-mandated carbon markets (‘compliance markets’) that aim to establish a carbon price via laws or regulations within a particular jurisdiction (e.g. country or region), controlling the supply of permits to be distributed. Compliance markets incentivize polluters within their jurisdiction to reduce emissions, but they are not capable of removing greenhouse gases which have already been emitted. + +Despite its development over recent decades, the VCM continues to suffer from a variety of issues: + +1. Highly fragmented liquidity +2. Opaque transaction mechanisms +3. High fees +4. Very slow trading speed +5. Lack of scalability + +Transitioning the VCM to the new blockchain-based **digital carbon market (DCM)** might be an opportunity to upgrade the existing technology for validating, transacting and consuming carbon credits. Blockchains allow for publicly verifiable data, access for a broad range of users, and more liquidity. + +ReFi projects employ blockchain technology to alleviate many of the problems of the traditional market: + +- **Liquidity is concentrated in a small number of liquidity pools** that can be freely traded by anyone. Large organizations as well as individual users can use these pools without manual searches for sellers/buyers, participation fees, or prior registration. +- **All transactions are recorded on public blockchains**. The path each carbon credit takes due to trading activity is traceable forever as soon as it is made available in the DCM. +- **Transaction speed is nearly instant**. Securing large amounts of carbon credits via the legacy markets can take days or weeks, but this can be achieved in a few seconds in the DCM. +- **Trading activity occurs without intermediaries**, which charge high fees. Digital carbon credits represent a significant cost reduction compared to traditional credits. +- **The DCM is scalable** and can meet the demands of individuals and multinational corporations alike. + +### Key components of the DCM + +Four major components make up the current landscape of the DCM: + +1. Registries such as [Verra](https://verra.org/project/vcs-program/registry-system/) and [Gold Standard](https://www.goldstandard.org/) make sure that projects creating carbon credits are reliable. They also operate the databases in which digital carbon credits originate and can be transferred or used up (retired). + +There is a new wave of innovative projects being built on blockchains that are attempting to disrupt incumbents in this sector. + +2. Carbon bridges, a.k.a. tokenizers, provide technology to represent or transfer carbon credits from traditional registries into the DCM. Notable examples include [Toucan Protocol](https://toucan.earth/), [C3](https://c3.app/), and [Moss.Earth](https://moss.earth/). +3. Integrated services offer carbon avoidance and/or removal credits to end-users so they can claim the environmental benefit of a credit and share their support of climate action with the world. + +Some such as [Klima Infinity](https://www.klimadao.finance/infinity) and [Senken](https://senken.io/) offer a wide variety of projects developed by third parties and issued under established standards like Verra; others like [Nori](https://nori.com/) only offer specific projects developed under their own carbon credit standard, which they issue and for which they have their own dedicated marketplace. + +4. The underlying rails and infrastructure that facilitate the scaling up of the impact and efficiency of the carbon market’s entire supply chain. [KlimaDAO](http://klimadao.finance/) supplies liquidity as a public good (allowing anyone to buy or sell carbon credits at a transparent price), incentivizes increased throughput of carbon markets and retirements with rewards, and provides user-friendly interoperable tooling to access data about, as well as acquire and retire, a wide variety of tokenized carbon credits. + +## ReFi beyond carbon markets + +Although there is currently a strong emphasis on carbon markets in general and transitioning the VCM to the DCM in particular within the space, the term “ReFi” is not strictly limited to carbon. Other environmental assets beyond carbon credits can be developed and tokenized, which will mean other negative externalities can also be priced within the base layers of future economic systems. Moreover, the regenerative aspect of this economic model can be applied to other areas, such as the funding of public goods via quadratic funding platforms like [Gitcoin](https://gitcoin.co/). Organizations that are built on the idea of open participation and equitable distribution of resources empower everyone to funnel money to open-source software projects, as well as educational, environmental, and community-driven projects. + +By shifting the direction of capital away from extractive practices toward a regenerative flow, projects and companies that provide social, environmental, or communal benefits—and which might fail to achieve funding in traditional finance—can get off the ground and generate positive externalities for society much more quickly and easily. Transitioning to this model of funding also opens the door to much more inclusive economic systems, where people of all demographics can become active participants rather than merely passive observers. ReFi offers a vision of Ethereum as a mechanism for coordinating action on existential challenges facing our species and all life on our planet—as the base layer of a new economic paradigm, enabling a more inclusive and sustainable future for centuries to come. + +## Additional reading on ReFi + +- [A high-level overview of carbon currencies and their place in the economy](https://www.klimadao.finance/blog/the-vision-of-a-carbon-currency) +- [The Ministry for the Future, a novel depicting the role of a carbon-backed currency in fighting climate change](https://en.wikipedia.org/wiki/The_Ministry_for_the_Future) +- [A detailed report by the Taskforce for Scaling Voluntary Carbon Markets](https://www.iif.com/Portals/1/Files/TSVCM_Report.pdf) +- [Kevin Owocki and Evan Miyazono’s CoinMarketCap Glossary entry on ReFi](https://coinmarketcap.com/alexandria/glossary/regenerative-finance-refi) + +--- + +# Roadmap + +## Roadmap > Account Abstraction + +# Account abstraction + +Most existing users interact with Ethereum using **[externally owned accounts (EOAs)](/glossary/#eoa)**. This limits how users can interact with Ethereum. For example, it makes it difficult to do batches of transactions and requires users to always keep an ETH balance to pay transaction fees. + +Account abstraction is a way to solve these problems by allowing users to flexibly program more security and better user experiences into their accounts. This can happen by [upgrading EOAs](https://eips.ethereum.org/EIPS/eip-7702) (EIP-7702) so they can be controlled by smart contracts. There is also another path involving adding a [second, separate transaction system](https://eips.ethereum.org/EIPS/eip-4337) (EIP-4337) to run in parallel to the existing protocol. Regardless of the route, the outcome is access to Ethereum via smart contract wallets, either natively supported as part of the existing protocol or via an add-on transaction network. + +Smart contract wallets unlock many benefits for the user, including: + +- define your own flexible security rules +- recover your account if you lose the keys +- share your account security across trusted devices or individuals +- pay someone else's gas, or have someone else pay yours +- batch transactions together (e.g., approve and execute a swap in one go) +- more opportunities for dapps and wallet developers to innovate on user experiences + +These benefits are not natively supported today because only externally-owned accounts ([EOAs](/glossary/#eoa)) can start transactions. EOAs are simply public-private key pairs. They work like this: + +- if you have the private key you can do _anything_ within the rules of the Ethereum Virtual Machine (EVM) +- if you do not have the private key you can do _nothing_. + +If you lose your keys they can't be recovered, and stolen keys give thieves instant access to all the funds in an account. + +Smart contract wallets are the solution to these problems, but today they are difficult to program because in the end, any logic they implement has to be translated into a set of EOA transactions before they can be processed by Ethereum. Account abstraction enables smart contracts to initiate transactions themselves, so that any logic that the user wishes to implement can be coded into the smart contract wallet itself and executed on Ethereum. + +Ultimately, account abstraction improves support for smart contract wallets, making them easier to build and safer to use. With account abstraction, users can enjoy all the benefits of Ethereum without needing to understand the underlying technology. + +## Beyond seed phrases + +Today's accounts are secured using private keys that are calculated from seed phrases. Anyone with access to a seed phrase can easily discover the private key protecting an account and gain access to all the assets it protects. If a private key and seed phrase are lost, the assets are permanently inaccessible. Securing these seed phrases is awkward, even for expert users, and seed phrase phishing is one of the most common scams. + +Account abstraction solves this by using a smart contract to hold assets and authorize transactions. Smart contracts can include custom logic tailored for maximum security and usability. Users still use private keys to control access, but with enhanced safety measures. + +For example, backup keys can be added to a wallet, enabling key replacement if the primary key is compromised. Each key can be secured differently or distributed among trusted individuals, significantly increasing security. Additional wallet rules can mitigate damage from key exposure, such as requiring multiple signatures for high-value transactions or restricting transactions to trusted addresses. + +## Better user experience + +Account abstraction greatly enhances the user experience and security by supporting smart contract wallets at the protocol level. Developers can innovate freely, improving transaction bundling for speed and efficiency. Simple swaps can become one-click operations, significantly improving ease of use. + +Gas management improves considerably. Applications can pay users' gas fees or allow payment in tokens other than ETH, eliminating the need to maintain an ETH balance. + +## How will account abstraction be implemented? + +Currently, smart contract wallets are challenging to implement as they rely on complex code wrapping standard transactions. Ethereum can change this by allowing smart contracts to directly initiate transactions, embedding logic in Ethereum smart contracts rather than relying on external relayers. + +### EIP-4337: Account abstraction without protocol changes + +EIP-4337 enables native smart contract wallet support without modifying Ethereum's core protocol. It introduces `UserOperation` objects collected into transaction bundles by validators, simplifying wallet development. The EIP-4337 EntryPoint contract was deployed to Ethereum Mainnet on 1st March 2023 and has facilitated the creation of over 26 million smart wallets and 170 million UserOperations. + +## Current progress + +As part of Ethereum's Pectra upgrade, EIP-7702 is scheduled for May 7, 2025. EIP-4337 has been widely adopted, [with over 26 million smart accounts deployed and more than 170 million UserOperations processed](https://www.bundlebear.com/overview/all). + +## Further reading + +- [erc4337.io](https://www.erc4337.io/) +- [EIP-4337 documentation](https://eips.ethereum.org/EIPS/eip-4337) +- [EIP-7702 documentation](https://eips.ethereum.org/EIPS/eip-7702) +- [ERC-4337 adoption dashboard](https://www.bundlebear.com/overview/all) +- [Vitalik's "Road to Account Abstraction"](https://notes.ethereum.org/@vbuterin/account_abstraction_roadmap#Transaction-inclusion-lists) +- [Vitalik's blog on social recovery wallets](https://vitalik.eth.limo/general/2021/01/11/recovery.html) +- [Awesome Account Abstraction](https://github.com/4337Mafia/awesome-account-abstraction) + +--- + +## Roadmap > Beacon Chain + +The Beacon Chain shipped on December 1, 2020, and formalized proof-of-stake as Ethereum's consensus mechanism with The Merge upgrade on September 15, 2022. + + +## What is the Beacon Chain? + +The Beacon Chain is the name of the original proof-of-stake blockchain that was launched in 2020. It was created to ensure the proof-of-stake consensus logic was sound and sustainable before enabling it on Ethereum Mainnet. Therefore, it ran alongside the original proof-of-work Ethereum. The Beacon Chain was a chain of 'empty' blocks, but switching off proof-of-work and switching on proof-of-stake on Ethereum required instructing the Beacon Chain to accept transaction data from execution clients, bundle them into blocks and then organize them into a blockchain using a proof-of-stake-based consensus mechanism. At the same moment, the original Ethereum clients turned off their mining, block propagation and consensus logic, handing that all over to the Beacon Chain. This event was known as [The Merge](/roadmap/merge/). Once The Merge happened, there were no longer two blockchains. Instead, there was just one proof-of-stake Ethereum, which now requires two different clients per node. The Beacon Chain is now the consensus layer, a peer-to-peer network of consensus clients that handles block gossip and consensus logic, while the original clients form the execution layer, which is responsible for gossiping and executing transactions, and managing Ethereum's state. The two layers can communicate with one another using the Engine API. + +## What does the Beacon Chain do? + +The Beacon Chain is the name given to a ledger of accounts that conducted and coordinated the network of Ethereum [stakers](/staking/) before those stakers started validating real Ethereum blocks. It does not process transactions or handle smart contract interactions though because that is being done in the execution layer. +The Beacon Chain is responsible for things like block and attestation handling, running the fork choice algorithm, and managing rewards and penalties. +Read more on our [node architecture page](/developers/docs/nodes-and-clients/node-architecture/#node-comparison). + +## Beacon Chain impact + +### Introducing staking + +The Beacon Chain introduced [proof-of-stake](/developers/docs/consensus-mechanisms/pos/) to Ethereum. This keeps Ethereum secure and earns validators more ETH in the process. In practice, staking involves staking ETH in order to activate validator software. As a staker, you run the software that creates and validates new blocks in the chain. + +Staking serves a similar purpose that [mining](/developers/docs/consensus-mechanisms/pow/mining/) used to, but is different in many ways. Mining required large up-front expenditures in the form of powerful hardware and energy consumption, resulting in economies of scale, and promoting centralization. Mining also did not come with any requirement to lock up assets as collateral, limiting the protocol's ability to punish bad actors after an attack. + +The transition to proof-of-stake made Ethereum significantly more secure and decentralized by comparison to proof-of-work. The more people that participate in the network, the more decentralized and safe from attacks it becomes. + +And using proof-of-stake as consensus mechanism is a foundational component for [the secure, environmentally friendly and scalable Ethereum we have now](/roadmap/vision/). + + + If you're interested in becoming a validator and helping secure Ethereum, learn more about staking. + + +### Setting up for sharding + +Since the Beacon Chain merged with the original Ethereum Mainnet, the Ethereum community started looking to scaling the network. + +Proof-of-stake has the advantage of having a registry of all approved block producers at any given time, each with ETH at stake. This registry sets the stage for the ability to divide and conquer but reliably split up specific network responsibilities. + +This responsibility is in contrast to proof-of-work, where miners have no obligation to the network and could stop mining and turn their node software off permanently in an instant without repercussion. There is also no registry of known block proposers and no reliable way to split network responsibilities safely. + +[More on sharding](/roadmap/danksharding/) + +## Relationship between upgrades + +The Ethereum upgrades are all somewhat interrelated. So let’s recap how the Beacon Chain affects the other upgrades. + +### Beacon Chain and The Merge + +At first, The Beacon Chain existed separately from Ethereum Mainnet, but they were merged in 2022. + + + The Merge + + +### Shards and the Beacon Chain + +Sharding can only safely enter the Ethereum ecosystem with a proof-of-stake consensus mechanism in place. The Beacon Chain introduced staking, which 'merged' with Mainnet, paving the way for sharding to help further scale Ethereum. + + + Shard chains + + +## Further Reading + +- [More on Ethereum's future upgrades](/roadmap/vision) +- [More on node architecture](/developers/docs/nodes-and-clients/node-architecture) +- [More of proof-of-stake](/developers/docs/consensus-mechanisms/pos) + +--- + +## Roadmap > Danksharding + +# Danksharding + +**Danksharding** is how Ethereum becomes a truly scalable blockchain, but there are several protocol upgrades required to get there. **Proto-Danksharding** is an intermediate step along the way. Both aim to make transactions on Layer 2 as cheap as possible for users and should scale Ethereum to >100,000 transactions per second. + +## What is Proto-Danksharding? + +Proto-Danksharding, also known as [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), is a way for [rollups](/layer-2/#rollups) to add cheaper data to blocks. The name comes from the two researchers who proposed the idea: Protolambda and Dankrad Feist. Historically, rollups had been limited in how cheap they can make user transactions by the fact that they post their transactions in `CALLDATA`. + +This is expensive because it is processed by all Ethereum nodes and lives onchain forever, even though rollups only need the data for a short time. Proto-Danksharding introduces data blobs that can be sent and attached to blocks. The data in these blobs is not accessible to the EVM and is automatically deleted after a fixed time period (set to 4096 epochs at time of writing, or about 18 days). This means rollups can send their data much more cheaply and pass the savings on to end users in the form of cheaper transactions. + + + +Rollups are a way to scale Ethereum by batching transactions offchain and then posting the results to Ethereum. A rollup is essentially composed of two parts: data and execution check. The data is the full sequence of transactions that is being processed by a rollup to produce the state change being posted to Ethereum. The execution check is the re-execution of those transactions by some honest actor (a "prover") to ensure that the proposed state change is correct. To perform the execution check, the transaction data has to be available for long enough for anyone to download and check. This means any dishonest behavior by the rollup sequencer can be identified and challenged by the prover. However, it does not need to be available forever. + + + + + +Rollups post commitments to their transaction data onchain and also make the actual data available in data blobs. This means provers can check the commitments are valid or challenge data they think is wrong. At the node-level, the blobs of data are held in the consensus client. The consensus clients attest that they have seen the data and that it has been propagated around the network. If the data was kept forever, these clients would bloat and lead to large hardware requirements for running nodes. Instead, the data is automatically pruned from the node every 18 days. The consensus client attestations demonstrate that there was a sufficient opportunity for provers to verify the data. The actual data can be stored offchain by rollup operators, users or others. + + + +### How is blob data verified? + +Rollups post the transactions they execute in data blobs. They also post a "commitment" to the data. They do this by fitting a polynomial function to the data. This function can then be evaluated at various points. For example, if we define an extremely simple function `f(x) = 2x-1` then we can evaluate this function for `x = 1`, `x = 2`, `x = 3` giving the results `1, 3, 5`. A prover applies the same function to the data and evaluates it at the same points. If the original data is changed, the function will not be identical, and therefore neither are the values evaluated at each point. In reality, the commitment and proof are more complicated because they are wrapped in cryptographic functions. + +### What is KZG? + +KZG stands for Kate-Zaverucha-Goldberg - the names of the three [original authors](https://link.springer.com/chapter/10.1007/978-3-642-17373-8_11) of a scheme that reduces a blob of data down to a small [cryptographic "commitment"](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html). The blob of data submitted by a rollup has to be verified to ensure the rollup is not misbehaving. This involves a prover re-executing the transactions in the blob to check that the commitment was valid. This is conceptually the same as the way execution clients check the validity of Ethereum transactions on layer 1 using Merkle proofs. KZG is an alternative proof that fits a polynomial equation to the data. The commitment evaluates the polynomial at some secret data points. A prover would fit the same polynomial over the data and evaluate it at the same values, checking that the result is the same. This is a way to verify the data that is compatible with zero-knowledge techniques used by some rollups and eventually other parts of the Ethereum protocol. + +### What was the KZG Ceremony? + +The KZG ceremony was a way for many people from across the Ethereum community to collectively generate a secret random string of numbers that can be used to verify some data. It is very important that this string of numbers is not known and cannot be recreated by anyone. To ensure this, each person that participated in the ceremony received a string from the previous participant. They then created some new random values (e.g. by allowing their browser to measure the movement of their mouse) and mix it in with the previous value. They then sent the value on to the next participant and destroyed it from their local machine. As long as one person in the ceremony did this honestly, the final value will be unknowable to an attacker. + +The EIP-4844 KZG ceremony was open to the public and tens of thousands of people participated to add their own entropy (randomness). In total there were over 140,000 contributions, making it the world's largest ceremony of its kind. For the ceremony to be undermined, 100% of those participants would have to be actively dishonest. From the perspective of the participants, if they know they were honest, there is no need to trust anyone else because they know that they secured the ceremony (they individually satisfied the 1-out-of-N honest participant requirement). + + + +When a rollup posts data in a blob, they provide a "commitment" that they post onchain. This commitment is the result of evaluating a polynomial fit to the data at certain points. These points are defined by the random numbers generated in the KZG ceremony. Provers can then evaluate the polynomial at the same points in order to verify the data - if they arrive at the same values then the data is correct. + + + + + +If someone knows the random locations used for the commitment, it is easy for them to generate a new polynomial that fits at those specific points (i.e. a "collision"). This means they could add or remove data from the blob and still provide a valid proof. To prevent this, instead of giving provers the actual secret locations, they actually receive the locations wrapped in a cryptographic "black box" using elliptic curves. These effectively scramble the values in such a way that the original values cannot be reverse-engineered, but with some clever algebra provers and verifiers can still evaluate polynomials at the points they represent. + + + + + Neither Danksharding nor Proto-Danksharding follow the traditional "sharding" model that aims to split the blockchain into multiple parts. Shard chains are no longer part of the roadmap. Instead, Danksharding uses distributed data sampling across blobs to scale Ethereum. This is much simpler to implement. This model has sometimes been referred to as "data-sharding". + + +## What is Danksharding? + +Danksharding is the full realization of the rollup scaling that began with Proto-Danksharding. Danksharding will bring massive amounts of space on Ethereum for rollups to dump their compressed transaction data. This means Ethereum will be able to support hundreds of individual rollups with ease and make millions of transactions per second a reality. + +The way this works is by expanding the blobs attached to blocks from six (6) in Proto-Danksharding, to 64 in full Danksharding. The rest of the changes required are all updates to the way consensus clients operate to enable them to handle the new large blobs. Several of these changes are already on the roadmap for other purposes independent of Danksharding. For example, Danksharding requires proposer-builder separation to have been implemented. This is an upgrade that separates the tasks of building blocks and proposing blocks across different validators. Similarly, data availability sampling is required for Danksharding, but it is also required for the development of very lightweight clients that do not store much historical data ("stateless clients"). + + + +Proposer-builder separation is required to prevent individual validators from having to generate expensive commitments and proofs for 32MB of blob data. This would put too much strain on home stakers and require them to invest in more powerful hardware, which hurts decentralization. Instead, specialized block builders take responsibility for this expensive computational work. Then, they make their blocks available to block proposers to broadcast. The block proposer simply chooses the block that is most profitable. Anyone can verify the blobs cheaply and quickly, meaning any normal validator can check that the block builders are behaving honestly. This allows the large blobs to be processed without sacrificing decentralization. Misbehaving block builders could simply be ejected from the network and slashed - others will step into their place because block building is a profitable activity. + + + + + +Data availability sampling is required for validators to quickly and efficiently verify blob data. Using data availability sampling, the validators can be very certain that the blob data was available and correctly committed. Every validator can randomly sample just a few data points and create a proof, meaning no validator has to check the entire blob. If any data is missing, it will be identified quickly and the blob rejected. + + + +### Current progress + +Full Danksharding is several years away. In the meantime, the KZG ceremony has concluded with over 140,000 contributions, and the [EIP](https://eips.ethereum.org/EIPS/eip-4844) for Proto-Danksharding has matured. This proposal has been fully implemented in all testnets, and went live on Mainnet with the Cancun-Deneb ("Dencun") network upgrade in March 2024. + +### Further reading + +- [Proto-Danksharding notes](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq) - _Vitalik Buterin_ +- [Dankrad's notes on Danksharding](https://notes.ethereum.org/@dankrad/new_sharding) +- [Dankrad, Proto and Vitalik discuss Danksharding](https://www.youtube.com/watch?v=N5p0TB77flM) +- [The KZG ceremony](https://ceremony.ethereum.org/) +- [Carl Beekhuizen's Devcon talk on trusted setups](https://archive.devcon.org/archive/watch/6/the-kzg-ceremony-or-how-i-learnt-to-stop-worrying-and-love-trusted-setups/?tab=YouTube) +- [More on data availability sampling for blobs](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) +- [Dankrad Feist on KZG commitments and proofs](https://youtu.be/8L2C6RDMV9Q) +- [KZG polynomial commitments](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html) + +--- + +## Roadmap > Dencun + +# Cancun-Deneb (Dencun) + +Cancun-Deneb (Dencun) is an upgrade to the Ethereum network, which activates **Proto-Danksharding (EIP-4844)**, introducing temporary data **blobs** for cheaper [layer 2 (L2)](/glossary/#layer-2) rollup storage. + +A new transaction type enables rollup providers to store data more cost-effectively in what are known as "blobs." Blobs are guaranteed to be available to the network for around 18 days (more precisely, 4096 [epochs](/glossary/#epoch)). After this period, blobs are pruned from the network, but applications can still verify the validity of their data using proofs. + +This significantly reduces the cost of rollups, limits chain growth, and helps to support more users while maintaining security and a decentralized set of node operators. + +## When do we expect rollups to reflect lower fees due to Proto-Danksharding? + +- This upgrade activated at epoch 269568, on **13-Mar-2024 at 13:55PM (UTC)** +- All major rollup providers, such as Arbitrum or Optimism, have signalled that blobs will be supported immediately following the upgrade +- The timeline for individual rollup support may vary, as each provider must update their systems to take advantage of the new blob space + +## How can ETH be converted after the hard fork? + +- **No Action Required for Your ETH**: Following the Ethereum Dencun upgrade, there is no need to convert or upgrade your ETH. Your account balances will remain the same, and the ETH you currently hold will remain accessible in its existing form after the hard fork. +- **Beware of Scams!**  **anyone instructing you to "upgrade" your ETH is trying to scam you.** There is nothing you need to do in relation to this upgrade. Your assets will stay completely unaffected. Remember, staying informed is the best defense against scams. + +[More on recognizing and avoiding scams](/security/) + +## What problem is the Dencun network upgrade solving? + +Dencun primarily addresses **scalability** (handling more users and more transactions) with **affordable fees**, while **maintaining decentralization** of the network. + +The Ethereum community has been taking a "rollup-centric" approach to its growth, which places layer 2 rollups as the primary means to safely support more users. + +Rollup networks handle the _processing_ (or "execution") of transactions separate from Mainnet and then publish a cryptographic proof and/or compressed transaction data of the results back to Mainnet for record keeping. Storing these proofs carries an expense (in the form of [gas](/glossary/#gas)), which, before Proto-Danksharding, had to be stored permanently by all network node operators, making it an expensive task. + +The introduction of Proto-Danksharding in the Dencun upgrade adds cheaper data storage for these proofs by only requiring node operators to store this data for about 18 days, after which data can be safely removed to prevent expansion of hardware requirements. Because rollups typically have a withdrawal period of 7 days, their security model is unchanged as long as blobs are available on L1 for this duration. The 18-day pruning window provides a significant buffer for this period. + +[More on scaling Ethereum](/roadmap/scaling/) + +## How is old blob data accessed? + +While regular Ethereum nodes will always hold the _current state_ of the network, historical blob data can be discarded approximately 18 days after its introduction. Before discarding this data, Ethereum ensures that it has been made available to all network participants, allowing time for: + +- Interested parties to download and store the data. +- Completion of all rollup challenge periods. +- Finalization of the rollup transactions. + +_Historical_ blob data may be desired for a variety of reasons and can be stored and accessed using several decentralized protocols: + +- **Third-party indexing protocols**, such as The Graph, store this data through a decentralized network of node operators incentivized by crypto-economic mechanisms. +- **BitTorrent** is a decentralized protocol where volunteers can hold and distribute this data to others. +- **[Ethereum portal network](/developers/docs/networking-layer/portal-network/)** aims to provide access to all Ethereum data through a decentralized network of node operators by distributing data among participants akin to BitTorrent. +- **Individual users** are always free to store their own copies of any data they wish for historical reference. +- **Rollup providers** are incentivized to store this data to enhance the user experience of their rollup. +- **Block explorers** typically run archival nodes that index and store all this information for easy historical reference, accessible to users via a web interface. + +It is important to note that recovering historical state operates on a **1-of-N trust model**. This means that you only need data from _a single trustworthy source_ to verify its correctness using the current state of the network. + +## How does this upgrade contribute to the broader Ethereum roadmap? + +Proto-Danksharding sets the stage for the full implementation of [Danksharding](/roadmap/danksharding/). Danksharding is designed to distribute the storage of rollup data across node operators, so each operator only needs to handle a small part of the total data. This distribution will increase the number of data blobs per block, which is essential for scaling Ethereum to handle more users and transactions. + +This scalability is crucial to [supporting billions of users on Ethereum](/roadmap/scaling/) with affordable fees and more advanced applications, while maintaining a decentralized network. Without these changes, the hardware demands for node operators would escalate, leading to the need for increasingly expensive equipment. This could price out smaller operators, resulting in a concentration of network control among a few large operators, which would go against the principle of decentralization. + +## Does this upgrade affect all Ethereum consensus and validator clients? + +Yes, Proto-Danksharding (EIP-4844) requires updates to both execution clients and consensus clients. All main Ethereum clients have released versions supporting the upgrade. To maintain synchronization with the Ethereum network post-upgrade, node operators must ensure they are running a supported client version. Note that the information about client releases is time-sensitive, and users should refer to the latest updates for the most current details. [See details on supported client releases](https://blog.ethereum.org/2024/02/27/dencun-mainnet-announcement#client-releases). + +The consensus clients handle the _Validator_ software, which has all been updated to accommodate the upgrade. + +## How does Cancun-Deneb (Dencun) affect Ethereum testnets? + +- Devnets, Sepolia and Holesky have all undergone the Dencun upgrade and have Proto-Danksharding fully functioning +- Rollup developers can use these networks for EIP-4844 testing +- Most users will be completely unaffected by this change to each testnet + +## Will all transactions on L2s now use temporary blob space, or will you be able to choose? + +Rollup transactions on Layer 2 (L2) of Ethereum have the option of using two types of data storage: temporary blob space or permanent smart contract calldata. Blob space is an economical choice, providing temporary storage at a lower cost. It guarantees data availability for all necessary challenge periods. On the other hand, smart contract calldata offers permanent storage but is more expensive. + +The decision between using blob space or calldata is primarily made by rollup providers. They base this decision on the current demand for blob space. If blob space is in high demand, rollups may opt for calldata to ensure the data is posted in a timely manner. + +While it's theoretically possible for users to choose their preferred storage type, rollup providers typically manage this choice. Offering this option to users would add complexity, particularly in cost-effective bundling transactions. For specific details on this choice, users should refer to the documentation provided by individual rollup providers. + +## Will 4844 reduce L1 gas? + +Not significantly. A new gas market is introduced exclusively for blob space, for use by rollup providers. _Although fees on L1 may be reduced by off-loading rollup data to blobs, this upgrade primarily focuses on the reduction of L2 fees. Reduction of fees on L1 (Mainnet) may occur as a second-order effect to a lesser extent._ + +- L1 gas reduction will be proportional to adoption/usage of blob data by rollup providers +- L1 gas is likely to remain competitive from non-rollup related activity +- Rollups that adopt the use of blob space will demand less L1 gas, helping push L1 gas fees downward in the near-term +- Blob space is still limited, so if blobs within a block are saturated/full, then rollups may be required to post their data as permanent data in the meantime, which would drive L1 and L2 gas prices up + +## Will this reduce fees on other EVM layer 1 blockchains? + +No. The benefits of Proto-Danksharding are specific to Ethereum layer 2 rollups that store their proofs on layer 1 (Mainnet). + +Simply being compatible with the Ethereum Virtual Machine (EVM) does not mean that a network will see any benefit from this upgrade. Networks that operate independently of Ethereum (whether EVM compatible or not) do not store their data on Ethereum and will not see any benefit from this upgrade. + +[More about layer 2 rollups](/layer-2/) + +## More of a visual learner? + + + +_Unlocking Ethereum's Scaling, EIP-4844 — Finematics _ + + + +_Blobspace 101 with Domothy — Bankless_ + +## Further reading + +- [EIP4844.com](https://www.eip4844.com/) +- [EIP-4844: Shard blob transactions (Proto-Danksharding)](https://eips.ethereum.org/EIPS/eip-4844) +- [Dencun Mainnet Announcement](https://blog.ethereum.org/2024/02/27/dencun-mainnet-announcement) - _Ethereum Foundation blog_ +- [The Hitchhiker's Guide to Ethereum: Proto-Danksharding](https://members.delphidigital.io/reports/the-hitchhikers-guide-to-ethereum/#proto-danksharding-eip-4844) - _Jon Charbonneau_ +- [Proto-Danksharding FAQ](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq) - _Vitalik Buterin_ +- [An In-depth Explanation of EIP-4844: The Core of the Cancun Upgrade](https://medium.com/@ebunker.io/an-in-depth-explanation-of-eip-4844-the-core-of-the-cancun-upgrade-de7b13761d2c) - _Ebunker_ +- [AllCoreDevs Update 016](https://tim.mirror.xyz/HzH5MpK1dnw7qhBSmzCfdCIxpwpD6DpwlfxtaAwEFro) - _Tim Beiko_ + +--- + +## Roadmap > Future Proofing + +Some parts of the roadmap are not necessarily required for scaling or securing Ethereum in the near-term, but set Ethereum up for stability and reliability far into the future. + +## Quantum resistance + +Some of the [cryptography](/glossary/#cryptography) securing present-day Ethereum will be compromised when quantum computing becomes a reality. Although quantum computers are probably decades away from being a genuine threat to modern cryptography, Ethereum is being built to be secure for centuries to come. This means making [Ethereum quantum resistant](https://consensys.net/blog/developers/how-will-quantum-supremacy-affect-blockchain/) as soon as possible. + +The challenge facing Ethereum developers is that the current [proof-of-stake](/glossary/#pos) protocol relies upon a very efficient signature scheme known as BLS to aggregate votes on valid [blocks](/glossary/#block). This signature scheme is broken by quantum computers, but the quantum resistant alternatives are not as efficient. + +The [“KZG” commitment schemes](/roadmap/danksharding/#what-is-kzg) used in several places across Ethereum to generate cryptographic secrets are known to be quantum-vulnerable. Currently, this is circumvented using “trusted setups” (for which the main setup ceremony completed successfully in 2023), where many users generated randomness that cannot be reverse-engineered by a quantum computer. However, the ideal long-term solution would be to incorporate quantum safe cryptography instead. There are two leading approaches that could become efficient replacements for the BLS scheme: [STARK-based](https://hackmd.io/@vbuterin/stark_aggregation) and [lattice-based](https://medium.com/asecuritysite-when-bob-met-alice/so-what-is-lattice-encryption-326ac66e3175) signing. **These are still being actively researched and prototyped**. + +[Read about KZG and trusted setups](/roadmap/danksharding#what-is-kzg) + +## Simpler and more efficient Ethereum + +Complexity creates opportunities for bugs or vulnerabilities that can be exploited by attackers. Therefore, part of the roadmap is simplifying Ethereum and removing or modifying code that has hung around through various upgrades but is no longer needed or can now be improved upon. A leaner, simpler codebase is easier for developers to maintain and reason about. + +To make the [Ethereum Virtual Machine (EVM)](/developers/docs/evm) simpler and more efficient, improvements are continuously researched and implemented. This involves both addressing legacy components and introducing optimizations. + +**Recent Changes Implemented:** + +- **Gas Calculation Overhaul:** The way [gas](/glossary/#gas) is calculated was significantly improved with **EIP-1559 (implemented in the London upgrade, 2021)**, introducing a base fee and burn mechanism for more predictable transaction pricing. +- **`SELFDESTRUCT` Restriction:** The `SELFDESTRUCT` opcode, while rarely used, posed potential risks. Its functionality was heavily **restricted in the Dencun upgrade (March 2024) via EIP-6780** to mitigate dangers, especially concerning state management. +- **Modernized Transaction Types:** New transaction formats have been introduced (e.g., via **EIP-2718** and **EIP-4844** for blobs in the Dencun upgrade) to support new features and improve efficiency over legacy types. + +**Ongoing and future goals:** + +- **Further `SELFDESTRUCT` Handling:** While restricted, the **potential complete removal** of the `SELFDESTRUCT` opcode is still considered for future upgrades to further simplify the EVM state. ([More context on SELFDESTRUCT issues](https://hackmd.io/@vbuterin/selfdestruct)). +- **Phasing Out Legacy Transactions:** Although [Ethereum clients](/glossary/#consensus-client) still support older transaction types for backward compatibility, the goal is to encourage migration to newer types and **potentially deprecate or fully remove support for the oldest formats** in the future. +- **Continued Gas Efficiency Research:** Exploration continues into **further refinements for gas calculation**, potentially including concepts like multi-dimensional gas to better reflect resource usage. +- **Optimized Cryptographic Operations:** Efforts are ongoing to **bring in more efficient methods for the arithmetic** underpinning cryptographic operations used within the EVM. + +Similarly, there are updates that can be made to other parts of present-day Ethereum clients. One example is that current execution and consensus clients use a different type of data compression. It will be much easier and more intuitive to share data between clients when the compression scheme is unified across the whole network. This remains an area of exploration. + +## Current progress + +Many of the long-term future-proofing upgrades, particularly **full quantum resistance for core protocols, are still in the research phase and may be several years away** from being implemented. + +However, **significant progress has already been made on simplification efforts.** For example, key changes like the **restriction of `SELFDESTRUCT` (EIP-6780)** and the introduction of **blob-carrying transactions (EIP-4844)** were implemented in the **Dencun upgrade (March 2024)**. Work on harmonizing client compression schemes and other efficiency improvements also continues. + +**Further reading** + +- [Gas](/developers/docs/gas) +- [EVM](/developers/docs/evm) +- [Data structures](/developers/docs/data-structures-and-encoding) + +--- + +## Roadmap > Merge + +The Merge was executed on September 15, 2022. This completed Ethereum's transition to proof-of-stake consensus, officially deprecating proof-of-work and reducing energy consumption by ~99.95%. + + +## What was The Merge? + +The Merge was the joining of the original execution layer of Ethereum (the Mainnet that has existed since [genesis](/history/#frontier)) with its new proof-of-stake consensus layer, the Beacon Chain. It eliminated the need for energy-intensive mining and instead enabled the network to be secured using staked ETH. It was a truly exciting step in realizing the Ethereum vision—more scalability, security, and sustainability. + + + +Initially, the [Beacon Chain](/roadmap/beacon-chain/) shipped separately from [Mainnet](/glossary/#mainnet). Ethereum Mainnet - with all its accounts, balances, smart contracts, and blockchain state - continued to be secured by [proof-of-work](/developers/docs/consensus-mechanisms/pow/), even while the Beacon Chain ran in parallel using [proof-of-stake](/developers/docs/consensus-mechanisms/pos/). The Merge was when these two systems finally came together, and proof-of-work was permanently replaced by proof-of-stake. + +Imagine Ethereum is a spaceship that launched before it was quite ready for an interstellar voyage. With the Beacon Chain, the community built a new engine and a hardened hull. After significant testing, it became time to hot-swap the new engine for the old one mid-flight. This merged the new, more efficient engine into the existing ship enabling it to put in some serious light years and take on the universe. + +## Merging with Mainnet + +Proof-of-work secured Ethereum Mainnet from genesis until The Merge. This allowed the Ethereum blockchain we're all used to come into existence in July 2015 with all its familiar features—transactions, smart contracts, accounts, etc. + +Throughout Ethereum's history, developers prepared for an eventual transition away from proof-of-work to proof-of-stake. On December 1, 2020, the Beacon Chain was created as a separate blockchain to Mainnet, running in parallel. + +The Beacon Chain was not originally processing Mainnet transactions. Instead, it was reaching consensus on its own state by agreeing on active validators and their account balances. After extensive testing, it became time for the Beacon Chain to reach consensus on real world data. After The Merge, the Beacon Chain became the consensus engine for all network data, including execution layer transactions and account balances. + +The Merge represented the official switch to using the Beacon Chain as the engine of block production. Mining is no longer the means of producing valid blocks. Instead, the proof-of-stake validators have adopted this role and are now responsible for processing the validity of all transactions and proposing blocks. + +No history was lost in The Merge. As Mainnet merged with the Beacon Chain, it also merged the entire transactional history of Ethereum. + + +This transition to proof-of-stake changed the way ether is issued. Learn more about ether issuance before and after The Merge. + + +### Users and holders + +**The Merge did not change anything for holders/users.** + +_This bears repeating_: As a user or holder of ETH or any other digital asset on Ethereum, as well as non-node-operating stakers, **you do not need to do anything with your funds or wallet to account for The Merge.** ETH is just ETH. There is no such thing as "old ETH"/"new ETH" or "ETH1"/"ETH2" and wallets work exactly the same after The Merge as they did before—people telling you otherwise are likely scammers. + +Despite swapping out proof-of-work, the entire history of Ethereum since genesis remained intact and unaltered by the transition to proof-of-stake. Any funds held in your wallet before The Merge are still accessible after The Merge. **No action is required to upgrade on your part.** + +[More on Ethereum security](/security/#eth2-token-scam) + +### Node operators and dapp developers + + + +Key action items include: + +1. Run _both_ a consensus client and an execution client; third-party endpoints to obtain execution data no longer work since The Merge. +2. Authenticate both execution and consensus clients with a shared JWT secret so they can securely communicate. +3. Set a `fee recipient` address to receive your earned transaction fee tips/MEV. + +Not completing the first two items above will result in your node being seen as "offline" until both layers are synced and authenticated. + +Not setting a `fee recipient` will still allow your validator to behave as usual, but you will miss out on unburnt fee tips and any MEV you would have otherwise earned in blocks your validator proposes. + + + + +Up until The Merge, an execution client (such as Geth, Erigon, Besu or Nethermind) was enough to receive, properly validate, and propagate blocks being gossiped by the network. _After The Merge_, the validity of transactions contained within an execution payload now also depends on the validity of the "consensus block" it is contained within. + +As a result, a full Ethereum node now requires both an execution client and a consensus client. These two clients work together using a new Engine API. The Engine API requires authentication using a JWT secret, which is provided to both clients allowing secure communication. + +Key action items include: + +- Install a consensus client in addition to an execution client +- Authenticate execution and consensus clients with a shared JWT secret so they can securely communicate with one another. + +Not completing the above items will result in your node appearing to be "offline" until both layers are synced and authenticated. + + + + + +The Merge came with changes to consensus, which also includes changes related to: + + + block structure + slot/block timing + opcode changes + sources of onchain randomness + concept of safe head and finalized blocks + + +For more information, check out this blog post by Tim Beiko on How The Merge Impacts Ethereum’s Application Layer. + + + +## The Merge and energy consumption + +The Merge marked the end of proof-of-work for Ethereum and started the era of a more sustainable, eco-friendly Ethereum. Ethereum's energy consumption dropped by an estimated 99.95%, making Ethereum a green blockchain. Learn more about [Ethereum energy consumption](/energy-consumption/). + +## The Merge and scaling + +The Merge also set the stage for further scalability upgrades not possible under proof-of-work, bringing Ethereum one step closer to achieving the full scale, security and sustainability outlined in its [Ethereum vision](/roadmap/vision/). + +## Misconceptions about The Merge + + + +There are two types of Ethereum nodes: nodes that can propose blocks and nodes that don't. + +Nodes that propose blocks are only a small number of the total nodes on Ethereum. This category includes mining nodes under proof-of-work (PoW) and validator nodes under proof-of-stake (PoS). This category requires committing economic resources (such as GPU hash power in proof-of-work or staked ETH in proof-of-stake) in exchange for the ability to occasionally propose the next block and earn protocol rewards. + +The other nodes on the network (i.e. the majority) are not required to commit any economic resources beyond a consumer-grade computer with 1-2 TB of available storage and an internet connection. These nodes do not propose blocks, but they still serve a critical role in securing the network by holding all block proposers accountable by listening for new blocks and verifying their validity on arrival according to the network consensus rules. If the block is valid, the node continues propagating it through the network. If the block is invalid for whatever reason, the node software will disregard it as invalid and stop its propagation. + +Running a non-block-producing node is possible for anyone under either consensus mechanism (proof-of-work or proof-of-stake); it is strongly encouraged for all users if they have the means. Running a node is immensely valuable for Ethereum and gives added benefits to any individual running one, such as improved security, privacy and censorship resistance. + +The ability for anyone to run their own node is absolutely essential to maintaining the decentralization of the Ethereum network. + +More on running your own node + + + + + +Gas fees are a product of network demand relative to the capacity of the network. The Merge deprecated the use of proof-of-work, transitioning to proof-of-stake for consensus, but did not significantly change any parameters that directly influence network capacity or throughput. + +With a rollup-centric roadmap, efforts are being focused on scaling user activity at layer 2, while enabling layer 1 Mainnet as a secure decentralized settlement layer optimized for rollup data storage to help make rollup transactions exponentially cheaper. The transition to proof-of-stake is a critical precursor to realizing this. More on gas and fees. + + + + +A transaction's "speed" can be measured in a few ways, including time to be included in a block and time to finalization. Both of these changes slightly, but not in a way that users will notice. + +Historically, on proof-of-work, the target was to have a new block every ~13.3 seconds. Under proof-of-stake, slots occur precisely every 12 seconds, each of which is an opportunity for a validator to publish a block. Most slots have blocks, but not necessarily all (i.e. a validator is offline). In proof-of-stake, blocks are produced ~10% more frequently than on proof-of-work. This was a fairly insignificant change and is unlikely to be noticed by users. + +Proof-of-stake introduced the transaction finality concept that did not previously exist. In proof-of-work, the ability to reverse a block gets exponentially more difficult with every passing block mined on top of a transaction, but it never quite reaches zero. Under proof-of-stake, blocks are bundled into epochs (6.4 minute spans of time containing 32 chances for blocks) which validators vote on. When an epoch ends, validators vote on whether to consider the epoch 'justified'. If validators agree to justify the epoch, it gets finalized in the next epoch. Undoing finalized transactions is economically inviable as it would require obtaining and burning over one-third of the total staked ETH. + + + + + +Initially after The Merge, stakers could only access fee tips and MEV that were earned as a result of block proposals. These rewards are credited to a non-staking account controlled by the validator (known as the fee recipient), and are available immediately. These rewards are separate from protocol rewards for performing validator duties. + +Since the Shanghai/Capella network upgrade, stakers can now designate a withdrawal address to start receiving automatic payouts of any excess staking balance (ETH over 32 from protocol rewards). This upgrade also enabled the ability for a validator to unlock and reclaim its entire balance upon exiting from the network. + +More on staking withdrawals + + + + +Since the Shanghai/Capella upgrade enabled withdrawals, validators are incentivized to withdraw their staking balance above 32 ETH, as these funds do not add to yield and are otherwise locked. Depending on the APR (determined by total ETH staked), they may be incentivized to exit their validator(s) to reclaim their entire balance or potentially stake even more using their rewards to earn more yield. + +An important caveat here, full validator exits are rate limited by the protocol, and only so many validators may exit per epoch (every 6.4 minutes). This limit fluctuates depending on the number of active validators, but comes out to approximately 0.33% of total ETH staked can be exited from the network in a single day. + +This prevents a mass exodus of staked funds. Furthermore, it prevents a potential attacker with access to a large portion of the total ETH staked from committing a slashable offense and exiting/withdrawing all of the offending validator balances in the same epoch before the protocol can enforce the slashing penalty. + +The APR is also intentionally dynamic, allowing a market of stakers to balance how much they're willing to be paid to help secure the network. If the rate is too low, then validators will exit at a rate limited by the protocol. Gradually this will raise the APR for everyone who remains, attracting new or returning stakers yet again. + + +## What happened to 'Eth2'? + +The term 'Eth2' has been deprecated. After merging 'Eth1' and 'Eth2' into a single chain, there is no longer any need to +distinguish between two Ethereum networks; there is just Ethereum. + +To limit confusion, the community has updated these terms: + +- 'Eth1' is now the 'execution layer', which handles transactions and execution. +- 'Eth2' is now the 'consensus layer', which handles proof-of-stake consensus. + +These terminology updates only change naming conventions; this does not alter Ethereum's goals or roadmap. + +[Learn more about the 'Eth2' renaming](https://blog.ethereum.org/2022/01/24/the-great-eth2-renaming/) + +## Relationship between upgrades + +The Ethereum upgrades are all somewhat interrelated. So let’s recap how The Merge relates to the other upgrades. + +### The Merge and the Beacon Chain + +The Merge represents the formal adoption of the Beacon Chain as the new consensus layer to the original Mainnet execution layer. Since The Merge, validators are assigned to secure Ethereum Mainnet, and mining on [proof-of-work](/developers/docs/consensus-mechanisms/pow/) is no longer a valid means of block production. + +Blocks are instead proposed by validating nodes that have staked ETH in return for the right to participate in consensus. These upgrades set the stage for future scalability upgrades, including sharding. + + + The Beacon Chain + + +### The Merge and the Shanghai upgrade + +In order to simplify and maximize focus on a successful transition to proof-of-stake, The Merge upgrade did not include certain anticipated features such as the ability to withdraw staked ETH. This functionality was enabled separately with the Shanghai/Capella upgrade. + +For those curious, learn more about [What Happens After The Merge](https://youtu.be/7ggwLccuN5s?t=101), presented by Vitalik at the April 2021 ETHGlobal event. + +### The Merge and sharding + +Originally, the plan was to work on sharding before The Merge to address scalability. However, with the boom of [layer 2 scaling solutions](/layer-2/), the priority shifted to swapping proof-of-work to proof-of-stake first. + +Plans for sharding are rapidly evolving, but given the rise and success of layer 2 technologies to scale transaction execution, sharding plans have shifted to finding the most optimal way to distribute the burden of storing compressed calldata from rollup contracts, allowing for exponential growth in network capacity. This would not be possible without first transitioning to proof-of-stake. + + + Sharding + + +## Further reading + +--- + +## Roadmap > Merge > Issuance + +# How The Merge impacted ETH supply + +The Merge represented the Ethereum network's transition from proof-of-work to proof-of-stake which occurred in September 2022. The way ETH was issued underwent changes at time of that transition. Previously, new ETH was issued from two sources: the execution layer (i.e. Mainnet) and the consensus layer (i.e. Beacon Chain). Since The Merge, issuance on the execution layer is now zero. Let's break this down. + +## Components of ETH issuance + +We can break the supply of ETH into two primary forces: issuance and burn. + +The **issuance** of ETH is the process of creating ETH that did not previously exist. The **burning** of ETH is when existing ETH gets destroyed, removing it from circulation. The rate of issuance and burning gets calculated on several parameters, and the balance between them determines the resulting inflation/deflation rate of ether. + + + +- Before transitioning to proof-of-stake, miners were issued approximately 13,000 ETH/day +- Stakers are issued approximately 1,700 ETH/day, based on about 14 million total ETH staked +- The exact staking issuance fluctuates based on the total amount of ETH staked +- **Since The Merge, only the ~1,700 ETH/day remains, dropping total new ETH issuance by ~88%** +- The burn: This fluctuates according to network demand. _If_ an average gas price of at least 16 gwei is observed for a given day, this effectively offsets the ~1,700 ETH that is issued to validators and brings net ETH inflation to zero or less for that day. + + + +## Pre-merge (historical) + +### Execution layer issuance + +Under proof-of-work, miners only interacted with the execution layer and were rewarded with block rewards if they were the first miner to solve the next block. Since the [Constantinople upgrade](/history/#constantinople) in 2019 this reward was 2 ETH per block. Miners were also rewarded for publishing [ommer](/glossary/#ommer) blocks, which were valid blocks that didn't end up in the longest/canonical chain. These rewards maxed out at 1.75 ETH per ommer, and were _in addition to_ the reward issued from the canonical block. The process of mining was an economically intensive activity, which historically required high levels of ETH issuance to sustain. + +### Consensus layer issuance + +The [Beacon Chain](/history/#beacon-chain-genesis) went live in 2020. Instead of miners, it is secured by validators using proof-of-stake. This chain was bootstrapped by Ethereum users depositing ETH one-way into a smart contract on Mainnet (the execution layer), which the Beacon Chain listens to, crediting the user with an equal amount of ETH on the new chain. Until The Merge happened, the Beacon Chain's validators were not processing transactions and were essentially coming to consensus on the state of the validator pool itself. + +Validators on the Beacon Chain are rewarded with ETH for attesting to the state of the chain and proposing blocks. Rewards (or penalties) are calculated and distributed at each epoch (every 6.4 minutes) based on validator performance. Validator rewards are **significantly** less than the mining rewards that were previously issued under proof-of-work (2 ETH every ~13.5 seconds), as operating a validating node is not as economically intense and thus does not require or warrant as high a reward. + +### Pre-merge issuance breakdown + +Total ETH supply: **~120,520,000 ETH** (at time of The Merge in September 2022) + +**Execution layer issuance:** + +- Was estimated at 2.08 ETH per 13.3 seconds\*: **~4,930,000** ETH issued in a year +- Resulted in an inflation rate of **approximately 4.09%** (4.93M per year / 120.5M total) +- \*This includes the 2 ETH per canonical block, plus an average of 0.08 ETH over time from ommer blocks. Also uses 13.3 seconds, the baseline block time target without any influence from a [difficulty bomb](/glossary/#difficulty-bomb). ([See source](https://bitinfocharts.com/ethereum/)) + +**Consensus layer issuance:** + +- Using 14,000,000 total ETH staked, the rate of ETH issuance is approximately 1700 ETH/day ([See source](https://ultrasound.money/)) +- Results in **~620,500** ETH issued in a year +- Resulted in inflation rate of **approximately 0.52%** (620.5K per year / 119.3M total) + + +Total annualized issuance rate (pre-merge): ~4.61% (4.09% + 0.52%) +~88.7% of the issuance was going to miners on the execution layer (4.09 / 4.61 * 100) +~11.3% was being issued to stakers on the consensus layer (0.52 / 4.61 * 100) + + +## Post-merge (present day) + +### Execution layer issuance + +Execution layer issuance since The Merge is zero. Proof-of-work is no longer a valid means of block production under the upgraded rules of consensus. All execution layer activity is packaged into "beacon blocks", which are published and attested to by proof-of-stake validators. Rewards for attesting-to and publishing beacon blocks are accounted for separately on the consensus layer. + +### Consensus layer issuance + +Consensus layer issuance continues today as before The Merge, with small rewards for validators who attest to and propose blocks. Validator rewards continue to accrue to _validator balances_ that are managed within the consensus layer. Unlike the current accounts ("execution" accounts), which can transact on Mainnet, these are separate Ethereum accounts cannot transact freely with other Ethereum accounts. Funds in these accounts can only be withdrawn to a single specified execution address. + +Since the Shanghai/Capella upgrade that took place in April 2023, these withdraws have been enabled for stakers. Stakers are incentivized to remove their _earnings/rewards (balance over 32 ETH)_ as these funds are otherwise not contributing to their stake weight (which maxes at 32). + +Stakers may also choose to exit and withdraw their entire validator balance. To ensure Ethereum is stable, the number of validators leaving simultaneously is capped. + +Approximately 0.33% of the total validator count may exit in a given day. By default, four (4) validators may exit per epoch (every 6.4 minutes, or 900 per day). An additional one (1) validator is permitted to exit for every 65,536 (216) additional validators over 262,144 (218). For example, with over 327,680 validators, five (5) may leave per epoch (1,125 per day). Six (6) will be permitted with a total active validator count over 393,216, and so forth. + +As more validators withdraw, the maximum number of exiting validators will gradually be reduced to a minimum of four to intentionally prevent large destabilizing amounts of staked ETH from being withdrawn concurrently. + +### Post-merge inflation breakdown + +- Total ETH supply: **~120,520,000 ETH** (at time of The Merge in September 2022) +- Execution layer issuance: **0** +- Consensus layer issuance: Same as above, **~0.52%** annualized issuance rate (with 14 million total ETH staked) + + +Total annualized issuance rate: ~0.52% +Net reduction in annual ETH issuance: ~88.7% ((4.61% - 0.52%) / 4.61% * 100) + + +##  The burn + +The opposite force to ETH issuance is the rate at which ETH is burned. For a transaction to execute on Ethereum, a minimum fee (known as a "base fee") must be paid, which fluctuates continuously (block-to-block) depending on network activity. The fee is paid in ETH and is _required_ for the transaction to be considered valid. This fee gets _burned_ during the transaction process, removing it from circulation. + + +Fee burning went live with the London upgrade in August 2021, and remains unchanged since The Merge. + + +On top of the fee burn implemented by the London upgrade, validators can also incur penalties for being offline, or worse, they can be slashed for breaking specific rules that threaten network security. These penalties result in a reduction of ETH from that validator's balance, which is not directly rewarded to any other account, effectively burning/removing it from circulation. + +### Calculating average gas price for deflation + +As discussed above, the amount of ETH issued in a given day is dependent upon the total ETH staked. At time of writing, this is approximately 1700 ETH/day. + +To determine the average gas price required to completely offset this issuance in a given 24-hour period, we'll start by calculating the total number of blocks in a day, given a block time of 12 seconds: + +- `(1 block / 12 seconds) * (60 seconds/minute) = 5 blocks/minute` +- `(5 blocks/minute) * (60 minutes/hour) = 300 blocks/hour` +- `(300 blocks/hour) * (24 hours/day) = 7200 blocks/day` + +Each block targets `15x10^6 gas/block` ([more on gas](/developers/docs/gas/)). Using this, we can solve for the average gas price (in units of gwei/gas) required to offset issuance, given a total daily ETH issuance of 1700 ETH: + +- `7200 blocks/day * 15x10^6 gas/block * `**`Y gwei/gas`**` * 1 ETH/ 10^9 gwei = 1700 ETH/day` + +Solving for `Y`: + +- `Y = (1700(10^9))/(7200 * 15(10^6)) = (17x10^3)/(72 * 15) = 16 gwei` (rounding to only two significant digits) + +Another way to rearrange this last step would be to replace `1700` with a variable `X` that represents the daily ETH issuance, and to simplify the rest to: + +- `Y = (X(10^3)/(7200 * 15)) = X/108` + +We can simplify and write this as a function of `X`: + +- `f(X) = X/108` where `X` is daily ETH issuance, and `f(X)` represents the gwei/gas price required to offset all of the newly issued ETH. + +So, for example, if `X` (daily ETH issuance) rises to 1800 based on total ETH staked, `f(X)` (gwei required to offset all of the issuance) would then be `17 gwei` (using 2 significant digits) + +## Further reading + +- [The Merge](/roadmap/merge/) +- [Ultrasound.money](https://ultrasound.money/) - _Dashboards available to visualize ETH issuance and burn in real-time_ +- [Charting Ethereum Issuance](https://www.attestant.io/posts/charting-ethereum-issuance/) - _Jim McDonald 2020_ + +--- + +## Roadmap > Pbs + +# Proposer-builder separation + +Present-day Ethereum validators create _and_ broadcast blocks. They bundle together transactions that they have heard about through the gossip network and package them into a block that is sent out to peers on the Ethereum network. **Proposer-builder separation (PBS)** splits these tasks across multiple validators. Block builders become responsible for creating blocks and offering them to the block proposer in each slot. The block proposer cannot see the contents of the block, they simply choose the most profitable one, paying a fee to the block builder before sending the block to its peers. + +This is an important upgrade for several reasons. First, it creates opportunities to prevent transaction censorship at the protocol level. Second, it prevents hobbyist validators from being out-competed by institutional players that can better optimize the profitability of their block building. Third, it helps with scaling Ethereum by enabling the Danksharding upgrades. + +## PBS and censorship resistance + +Separating out block builders and block proposers makes it much harder for block builders to censor transactions. This is because relatively complex inclusion criteria can be added that ensure no censorship has taken place before the block is proposed. As the block proposer is a separate entity from the block builder, it can take on the role of protector against censoring block builders. + +For example, inclusion lists can be introduced so that when validators know about transactions but don't see them included in blocks, they can impose them as must-haves in the next block. The inclusion list is generated from the block proposers local mempool (the list of transactions it is aware of) and sent to their peers just before a block is proposed. If any of the transactions from the inclusion list are missing, the proposer could either reject the block, add the missing transactions before proposing it, or propose it and let it get rejected by other validators when they receive it. There is also a potentially more efficient version of this idea that asserts that builders must fully utilize the available block space and if they don't transactions are added from the proposer's inclusion list. This is still an area of active research and the optimal configuration for the inclusion lists has not yet been determined. + +[Encrypted mempools](https://www.youtube.com/watch?v=fHDjgFcha0M&list=PLpktWkixc1gUqkyc1-iE6TT0RWQTBJELe&index=3) could also make it impossible for builders and proposers to know which transactions they are including in a block until after the block was already broadcast. + + + +Powerful organizations can pressure validators to censor transactions to or from certain addresses. Validators comply with this pressure by detecting blacklisted addresses in their transaction pool and omitting them from the blocks they propose. After PBS this will no longer be possible because block proposers will not know which transactions they are broadcasting in their blocks. It might be important for certain individuals or apps to comply with censorship rules, for example when it is made law in their region. In these cases, compliance happens at the application level, while the protocol remains permissionless and censorship free. + + + +## PBS and MEV + +**Maximum extractable value (MEV)** refers to validators maximizing their profitability by favorably ordering transactions. Common examples include arbitraging swaps on decentralized exchanges (e.g. frontrunning a large sale or purchase) or identifying opportunities to liquidate DeFi positions. Maximizing MEV requires sophisticated technical know-how and custom software appended to normal validators, making it much more likely that institutional operators outperform individuals and hobbyist validators at MEV extraction. This means staking returns are likely to be higher with centralized operators, creating a centralizing force that disincentivizes home staking. + +PBS solves this problem by reconfiguring the economics of MEV. Instead of the block proposer doing their own MEV searching, they simply pick a block from many offered to them by block builders. The block builders might have done sophisticated MEV extraction, but the reward for it goes to the block proposer. This means that even if a small pool of specialized block builders dominate MEV extraction, the reward for it could go to any validator on the network, including individual home stakers. + + + +Individuals could be incentivized to stake with pools rather than on their own due to the enhanced rewards offered by sophisticated MEV strategies. Separating the block building from the block proposal means that the MEV extracted will be distributed over more validators rather than centralizing with the most effective MEV searcher. At the same time, allowing specialized block builders to exist takes the burden of block building away from individuals, and also prevents individuals from stealing MEV for themselves, while maximizing the number of individual, independent validators that can check the blocks are honest. The important concept is "prover-verifier asymmetry" which refers to the idea that centralized block production is fine as long as there is a robust and maximally decentralized network of validators able to prove the blocks are honest. Decentralization is a means, not an end goal - what we want are honest blocks. + + +## PBS and Danksharding + +Danksharding is the way Ethereum will scale to >100,000 transactions per second and minimize fees for rollup users. It relies upon PBS because it adds to the workload for block builders, who will have to compute proofs for up to 64 MB of rollup data in less than 1 second. This will probably require specialized builders that can dedicate fairly substantial hardware to the task. However, in the current situation block building could become increasingly centralized around more sophisticated and powerful operators anyway due to MEV extraction. Proposer-builder separation is a way to embrace this reality and prevent it from exerting centralizing force on block validation (the important part) or the distribution of staking rewards. A great side-benefit is that the specialized block builders are also willing and able to compute the necessary data proofs for Danksharding. + +## Current progress + +PBS is in an advanced stage of research, but there are still some important design questions that need to be resolved before it can be prototyped in Ethereum clients. There is no finalized specification yet. This means PBS is likely a year away or more. Check the latest [state of the research](https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance). + +## Further Reading + +- [State of research: censorship resistance under PBS](https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance) +- [PBS-friendly fee market designs](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) +- [PBS and censorship resistance](https://notes.ethereum.org/@fradamt/H1TsYRfJc#Secondary-auctions) +- [Inclusion lists](https://notes.ethereum.org/@fradamt/H1ZqdtrBF) + +--- + +## Roadmap > Pectra > 7702 + +# Pectra 7702 + +## Abstract + +EIP 7702 defines a mechanism to add code to an EOA. This proposal allows EOAs, the legacy ethereum accounts, to receive short-term functionality improvements, increasing the usability of applications. This is done by setting a pointer to already deployed code using a new transaction type: 4. + +This new transaction type introduces an authorization list. Each authorization tuple in the list is defined as + +``` +[ chain_id, address, nonce, y_parity, r, s ] +``` + +**address** is the delegation (already deployed bytecode that'll be used by the EOA) +**chain_id** locks the authorization to a specific chain (or 0 for all chains) +**nonce** locks the authorization to a specific account nonce +(**y_parity, r, s**) is the signature of the authorization tuple, defined as keccak(0x05 || rlp ([chain_id ,address, nonce])) by the private key of EOA to which the authorization applies (also called the authority) + +A delegation can be reset by delegating to the null address. + +The private key of the EOA retains full control over the account after the delegation. For example delegating to a Safe doesn't make the account a multisig because there's still a single key that can bypass any signing policy. Going forward, developers should design with the assumption that any participant in the system could be a smart contract. For smart contract developers, it’s no longer safe to assume that `tx.origin` refers to an EOA. + +## Best practices + +**Account Abstraction**: A delegation contract should align with Ethereum’s broader account abstraction (AA) standards to maximize compatibility. In particular, it should ideally be ERC-4337 compliant or compatible. + +**Permissionless and Censorship-Resistant Design**: Ethereum values permissionless participation. A delegation contract MUST NOT hard-code or rely on any single “trusted” relayer or service. This would brick the account if the relayer goes offline. Features like batching (e.g. approve+transferFrom) can by used by the EOA itself without a relayer. For application developers that want to use advanced features enabled by 7702 (Gas Abstraction, Privacy-Preserving Withdrawals) you’ll need a relayer. While there are different relayer architectures, our recommendation is to use [4337 bundlers](https://www.erc4337.io/bundlers) pointing at least [entry point 0.8](https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.8.0) because: + +- They provide standardized interfaces for relaying +- Include built-in paymaster systems +- Ensure forward compatibility +- Can support censorship resistance through a [public mempool](https://notes.ethereum.org/@yoav/unified-erc-4337-mempool) +- Can require the init function to only be called from [EntryPoint](https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.8.0) + +In other words, anyone should be able to act as the transaction sponsor/relayer as long as they provide the required valid signature or UserOperation from the account. This ensures censorship resistance: if no custom infrastructure is required, a user’s transactions cannot be arbitrarily blocked by a gatekeeping relay. For example, [MetaMask’s Delegation Toolkit](https://github.com/MetaMask/delegation-framework/releases/tag/v1.3.0) explicitly works with any ERC-4337 bundler or paymaster on any chain, rather than requiring a MetaMask-specific server. + +**dApps Integration via Wallet Interfaces**: + +Given that wallets will whitelist specific delegation contracts for EIP-7702, dApps should not expect to directly request 7702 authorizations. Instead, integration should occur through standardized wallet interfaces: + +- **ERC-5792 (`wallet_sendCalls`)**: Enables dApps to request wallets to execute batched calls, facilitating functionalities like transaction batching and gas abstraction. + +- **ERC-6900**: Allows dApps to leverage modular smart account capabilities, such as session keys and account recovery, through wallet-managed modules. + +By utilizing these interfaces, dApps can access smart account functionalities provided by EIP-7702 without directly managing delegations, ensuring compatibility and security across different wallet implementations. + +> Note: There is no standardized method for dApps to request 7702 authorization signatures directly. DApps must rely on specific wallet interfaces like ERC-6900 to take advantage of EIP-7702 features. + +For more information: + +- [ERC-5792 specification](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-5792.md) +- [ERC-6900 specification](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6900.md) + +**Avoiding Vendor Lock-In**: In line with the above, a good implementation is vendor-neutral and interoperable. This often means adhering to emerging standards for smart accounts. For instance, [Alchemy’s Modular Account](https://github.com/alchemyplatform/modular-account) uses the ERC-6900 standard for modular smart accounts and is designed with “permissionless interoperable usage” in mind. + +**Privacy Preservation**: While onchain privacy is limited, a delegation contract should strive to minimize data exposure and linkability. This can be achieved by supporting features like gas payments in ERC-20 tokens (so users need not maintain a public ETH balance, which improves privacy and UX) and one-time session keys (which reduce reliance on a single long-term key). For example, EIP-7702 enables paying gas in tokens via sponsored transactions, and a good implementation will make it easy to integrate such paymasters without leaking more information than necessary. Additionally, off-chain delegation of certain approvals (using signatures that are verified onchain) means fewer onchain transactions with the user’s primary key, aiding privacy. Accounts that require using a relayer force users to reveal their IP addresses. PublicMempools improves this, when a transaction/UserOp propagates through the mempool you can't tell whether it originated from the IP that sent it, or just relayed through it via the p2p protocol. + +**Extensibility and Modular Security**: Account implementations should be extensible so they can evolve with new features and security improvements. Upgradability is inherently possible with EIP-7702 (since an EOA can always delegate to a new contract in the future to upgrade its logic). Beyond upgradability, a good design allows modularity – e.g. plug-in modules for different signature schemes or spending policies – without needing to redeploy entirely. Alchemy’s Account Kit is a prime example, allowing developers to install validation modules (for different signature types like ECDSA, BLS, etc.) and execution modules for custom logic. To achieve greater flexibility and security in EIP-7702-enabled accounts, developers are encouraged to delegate to a proxy contract rather than directly to a specific implementation. This approach allows for seamless upgrades and modularity without requiring additional EIP-7702 authorizations for each change. + +Benefits of the Proxy Pattern: + +- **Upgradability**: Update the contract logic by pointing the proxy to a new implementation contract. + +- **Custom Initialization Logic**: Incorporate initialization functions within the proxy to set up necessary state variables securely. + +For instance, the [SafeEIP7702Proxy](https://docs.safe.global/advanced/eip-7702/7702-safe) demonstrates how a proxy can be utilized to securely initialize and manage delegations in EIP-7702-compatible accounts. + +Cons of the Proxy Pattern: + +- **Reliance on external actors**: You have to rely on an external team to not upgrade to an unsafe contract. + +## Security Considerations + +**Reentrancy guard**: With the introduction of EIP-7702 delegation, a user’s account can dynamically switch between an Externally Owned Account (EOA) and a Smart Contract (SC). This flexibility enables the account to both initiate transactions and be the target of calls. As a result, scenarios where an account calls itself and makes external calls will have `msg.sender` equal to `tx.origin`, which undermines certain security assumptions that previously relied on `tx.origin` always being an EOA. + +For smart contract developers, it's no longer safe to assume that `tx.origin` refers to an EOA. Likewise, using `msg.sender == tx.origin` as a safeguard against reentrancy attacks is no longer a reliable strategy. + +Going forward, developers should design with the assumption that any participant in the system could be a smart contract. Alternatively they could implement explicit reentrancy protection using reentrancy guards with a `nonReentrant` modifier patterns. We recommend following an audited modifier e.g [Open Zeppelin's Reentrancy Guard](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol). They could also use a [transient storage variable](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html). + +**Initialization Security Considerations** + +Implementing EIP-7702 delegation contracts introduces specific security challenges, particularly concerning the initialization process. A critical vulnerability arises when the initialization function (`init`) is atomically coupled with the delegation process. In such cases, a frontrunner could intercept the delegation signature and execute the `init` function with altered parameters, potentially taking control of the account. + +This risk is especially pertinent when attempting to use existing Smart Contract Account (SCA) implementations with EIP-7702 without modifying their initialization mechanisms. + +**Solutions to Mitigate Initialization Vulnerabilities** + +- Implement `initWithSig` + Replace the standard `init` function with an `initWithSig` function that requires the user to sign the initialization parameters. This approach ensures that the initialization can only proceed with explicit user consent, thereby mitigating unauthorized initialization risks. + +- Utilize ERC-4337's EntryPoint + Require that the initialization function be called exclusively from the ERC-4337 EntryPoint contract. This method leverages the standardized validation and execution framework provided by ERC-4337, adding an additional layer of security to the initialization process. + _(See: [Safe Docs](https://docs.safe.global/advanced/eip-7702/7702-safe))_ + +By adopting these solutions, developers can enhance the security of EIP-7702 delegation contracts, safeguarding against potential frontrunning attacks during the initialization phase. + +**Storage Collisions** Delegating code does not clear existing storage. When migrating from one delegation contract to another, the residual data from the previous contract remains. If the new contract utilizes the same storage slots but interprets them differently, it can cause unintended behavior. For instance, if the initial delegation was to a contract where a storage slot represents a `bool`, and the subsequent delegation is to a contract where the same slot represents a `uint`, the mismatch can lead to unpredictable outcomes. + +**Phishing risks** With the implementation of EIP-7702 delegation, the assets in a user's account may be entirely controlled by smart contracts. If a user unknowingly delegates their account to a malicious contract, an attacker could easily gain control and steal funds. When using `chain_id=0` the delegation is applied to all chain ids. Only delegate to an immutable contract (never delegate to a proxy), and only to contracts that were deployed using CREATE2 (with standard initcode - no metamorphic contracts) so the deployer can't deploy something different to the same address elsewhere. Otherwise your delegation puts your account at risk on all other EVM chains. + +When users perform delegated signatures, the target contract receiving the delegation should be clearly and prominently displayed to help mitigate phishing risks. + +**Minimal Trusted Surface & Security**: While offering flexibility, a delegation contract should keep its core logic minimal and auditable. The contract is effectively an extension of the user’s EOA, so any flaw can be catastrophic. Implementations should follow best practices from the smart contract security community. For instance, constructor or initializer functions must be carefully secured – as highlighted by Alchemy, if using a proxy pattern under 7702, an unprotected initializer could let an attacker take over the account. Teams should aim to keep the onchain code simple: Ambire’s 7702 contract is only ~200 lines of Solidity, deliberately minimizing complexity to reduce bugs. A balance must be struck between feature-rich logic and the simplicity that eases auditing. + +### Known implementations + +Due to the nature of EIP 7702, it is recommended wallets use caution when helping users delegate to a 3rd party contract. Listed below is a collection of known implementations that have been audited: + +| Contract address | Source | Audits | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0x000000009B1D0aF20D8C6d0A44e162d11F9b8f00 | [Uniswap/calibur](https://github.com/Uniswap/calibur) | [audits](https://github.com/Uniswap/calibur/tree/main/audits) | +| 0x69007702764179f14F51cdce752f4f775d74E139 | [alchemyplatform/modular-account](https://github.com/alchemyplatform/modular-account) | [audits](https://github.com/alchemyplatform/modular-account/tree/develop/audits) | +| 0x5A7FC11397E9a8AD41BF10bf13F22B0a63f96f6d | [AmbireTech/ambire-common](https://github.com/AmbireTech/ambire-common/blob/feature/eip-7702/contracts/AmbireAccount7702.sol) | [audits](https://github.com/AmbireTech/ambire-common/tree/feature/eip-7702/audits) | +| 0x63c0c19a282a1b52b07dd5a65b58948a07dae32b | [MetaMask/delegation-framework](https://github.com/MetaMask/delegation-framework) | [audits](https://github.com/MetaMask/delegation-framework/tree/main/audits) | +| 0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9 | [Ethereum Foundation AA team](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/accounts/Simple7702Account.sol) | [audits](https://github.com/eth-infinitism/account-abstraction/blob/develop/audits/SpearBit%20Account%20Abstraction%20Security%20Review%20-%20Mar%202025.pdf) | + +## Hardware wallet guidelines + +Hardware wallets shouldn't expose arbitrary delegation. The consensus in the Hardware wallet space is to use a list of trusted delegator contracts. We suggest to allow known implementations listed above and to consider others on a case by case basis. As delegating your EOA to a contract gives control over all the assets, hardware wallets should be cautious with the way they implement 7702. + +### Integration scenarios for companion apps + +#### Lazy + +As the EOA still operates as usual, there's nothing to do. + +Note : some assets could be automatically rejected by the delegation code, such as ERC 1155 NFTs, and support should be aware of it. + +#### Aware + +Notify the user that a delegation is in place for the EOA by checking its code, and optionally offer to remove the delegation. + +#### Common delegation + +Hardware provider whitelists known delegation contracts and implements their support in software companion. It is recommended to choose a contract with full ERC 4337 support. + +EOAs delegated to a different one will be handled as standard EOAs. + +#### Custom delegation + +Hardware provider implements its own delegation contract and adds it to the lists implements its support in softaware companion. It is recommended to build a contract with full ERC 4337 support. + +EOAs delegated to a different one will be handled as standard EOAs. + +--- + +## Roadmap > Pectra + +# Pectra + +Pectra is an upcoming Ethereum protocol upgrade that brings new functionality and changes to the Ethereum network. Following [Dencun](/roadmap/dencun/), this is another major upgrade to both the execution and consensus layer of Ethereum. The shortened name Pectra is a combination of Prague and Electra, which are the respective names for the execution and consensus layer specification changes. Together, these changes bring a number of improvements to Ethereum users, developers and validators. + + +Pectra upgrade is only a single step in Ethereum's long-term development goals. Learn more about the protocol roadmap and previous upgrades. + + +## Improvements in Pectra + +Pectra brings the biggest number of [EIPs](https://eips.ethereum.org/) of any previous upgrades! There are many minor changes but also some significant new features. The full list of changes and technical details can be found in the individual included EIPs. + +### EOA account code + +[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) represents a major step toward widespread [account abstraction](/roadmap/account-abstraction/). With this feature, users can set their address ([EOA](/glossary/#eoa)) to be extended with a smart contract. The EIP introduces a new type of transaction with a specific function - to allow address owners to sign an authorization that sets their address to mimic a chosen smart contract. + +With this EIP, users can opt in to programmable wallets that allow new features like transaction bundling, gasless transacting and custom asset access for alternative recovery schemes. This hybrid approach combines the simplicity of EOAs with the programmability of contract-based accounts. + +Read a deeper dive on 7702 [here](/roadmap/pectra/7702/) + +### Increase the max effective balance + +The current effective balance of the validator is exactly 32 ETH. It's the minimum necessary amount to participate in the consensus but at the same time the maximum a single validator can stake. + +[EIP-7251](https://eips.ethereum.org/EIPS/eip-7251) raises the maximum possible effective balance to 2048 ETH, meaning that a single validator can now stake between 32 and 2048 ETH. Instead of multiples of 32, stakers can now choose an arbitrary amount of ETH to stake and receive rewards on every 1 ETH above the minimum. For example, if a validator's balance grows with their rewards to 33 ETH, the extra 1 ETH is also considered part of the effective balance and receives rewards. + +But the benefit of a better reward system for validators is only a part of this improvement. [Stakers](/staking/) running multiple validators can now aggregate them into a single one, which enables easier operation and reduces network overhead. Because every validator in Beacon Chain submits a signature in every epoch, the bandwidth requirements grow with more validators and a large number of signatures to propagate. Aggregating validators will take load off of the network and open new scaling options while keeping the same economic security. + +Read a deeper dive on maxEB [here](/roadmap/pectra/maxeb/) + +### Blob throughput increase + +Blobs provide [data availability](/developers/docs/data-availability/#data-availability-and-layer-2-rollups) for L2s. They were introduced in the [the previous network upgrade](/roadmap/dencun/). + +Currently, network targets an average 3 blobs per block with a maximum of 6 blobs. With [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691), the average blob count will be increased to 6, with a maximum of 9 per block, resulting in increased capacity for Ethereum rollups. This EIP helps bridge the gap until [PeerDAS](https://eips.ethereum.org/EIPS/eip-7594) enables even higher blob counts. + +### Increase calldata cost + +Before the introduction of [blobs in Dencun upgrade](/roadmap/danksharding), L2s were using [calldata](/docs/data-availability/blockchain-data-storage-strategies/#calldata) to store their data in Ethereum. Both blobs and calldata affect Ethereum's bandwidth usage. While most blocks only use a minimal amount of calldata, data-heavy blocks that also contain many blobs can be harmful to Ethereum's p2p network. + +To address this, [EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) increases calldata pricing, but only for data-heavy transactions. This bounds the worst-case block size, provides an incentive for L2s to only use blobs and leaves over 99% of transactions unaffected. + +### Execution layer triggerable exits + +Currently, exiting a validator and [withdrawing staked ETH](/staking/withdrawals/) is a consensus layer operation that requires an active validator key, the same BLS key used by the validator to perform active duties like attestations. Withdrawal credentials is a separate cold key that receives the exited stake but cannot trigger the exit. The only way for stakers to exit is to send a special message to the Beacon Chain network signed using the active validator key. This is limiting in scenarios where the withdrawal credentials and validator key are held by different entities or when the validator key gets lost. + +[EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) introduces a new contract that can be used to trigger the exit using execution layer withdrawal credentials. Stakers will be able to exit their validator by calling a function in this special contract without the need for their validator signing key or access to Beacon Chain at all. Importantly, enabling validator withdrawals onchain allows for staking protocols with reduced trust assumptions over node operators. + +### Validator deposits on chain + +Validator deposits are currently processed by [eth1data poll](https://eth2book.info/capella/part2/deposits-withdrawals/deposit-processing/) which is a function on the Beacon Chain that fetches data from the execution layer. It's sort of a technical debt from times before The Merge when Beacon Chain was a separate network and had to concern itself with proof-of-work re-orgs. + +[EIP-6110](https://eips.ethereum.org/EIPS/eip-6110) is a new way of delivering deposits from execution to the consensus layer, which allows for instant processing with less implementation complexity. It's a more secure way of handling deposits native to merged Ethereum. It also helps to future-proof the protocol because it doesn't require historical deposits to bootstrap the node, which is necessary for history expiry. + +### Precompile for BLS12-381 + +Precompiles are a special set of smart contracts built directly into the Ethereum Virtual Machine ([EVM](/developers/docs/evm/)). Unlike regular contracts, precompiles are not deployed by users but are part of the client implementation itself, written in its native language (e.g. Go, Java, etc, not Solidity). Precompiles serve for widely used and standardized functions like cryptographic operations. Smart contract developers can call precompiles as a regular contract but with more security and efficiency. + +[EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) adds new precompiles for curve operations over [BLS12-381](https://hackmd.io/@benjaminion/bls12-381). This elliptic curve became widely used in cryptocurrency ecosystems thanks to its practical properties. More specifically, it's been adopted by Ethereum's consensus layer, where it's used by validators. + +The new precompile adds the ability for every developer to easily, efficiently, and securely perform cryptographic operations using this curve, for example, verifying signatures. Onchain applications that depend on this curve can become more gas efficient and secure relying on a precompile instead of some custom contract. This mainly applies to applications that want to reason about validators inside the EVM, e.g. staking pools, restaking, light clients, bridges but also zero-knowledge. + +### Serve historical block hashes from state + +The EVM currently provides `BLOCKHASH` opcode which enables contract developers to retrieve the hash of a block directly in the execution layer. However, this is limited only to the last 256 blocks and might become problematic for stateless clients in the future. + +[EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) creates a new system contract that can serve the last 8192 block hashes as storage slots. This helps to future-proof the protocol for stateless execution and becomes more efficient when verkle tries are adopted. However, apart from this, rollups can benefit from this right away, as they can query the contract directly with a longer historical window. + +### Move committee index outside Attestation + +The Beacon Chain consensus is based on validators casting their votes for the latest block and finalized epoch. The attestation includes 3 elements, 2 of which are votes and the third is the committee index value. + +[EIP-7549](https://eips.ethereum.org/EIPS/eip-7549) moves this index outside of the signed attestation message, which makes it easier to verify and aggregate consensus votes. This will enable more efficiency in every consensus client and can bring significant performance improvements to zero-knowledge circuits for proving Ethereum consensus. + +### Add blob schedule to EL config files + +[EIP-7840](https://eips.ethereum.org/EIPS/eip-7840) is a simple change that adds a new field to execution layer client configuration. It configures the number of blocks, enabling dynamic setting for target and maximum blob counts per block as well as blob fee adjustment. With directly defined configuration, clients can avoid the complexity of exchanging this information via Engine API. + + +To learn more about how Pectra affects you specifically as an Ethereum user, developer or validator, look into Pectra FAQ. + + +## Does this upgrade affect all Ethereum nodes and validators? + +Yes, Pectra upgrade requires updates to both [execution clients and consensus clients](/developers/docs/nodes-and-clients/). All main Ethereum clients will release versions supporting the hard fork marked as high priority. To maintain synchronization with the Ethereum network post-upgrade, node operators must ensure they are running a supported client version. Note that the information about client releases is time-sensitive, and users should refer to the latest updates for the most current details. + +## How can ETH be converted after the hard fork? + +- **No Action Required for Your ETH**: Following the Ethereum Pectra upgrade, there is no need to convert or upgrade your ETH. Your account balances will remain the same, and the ETH you currently hold will remain accessible in its existing form after the hard fork. +- **Beware of Scams!**  **anyone instructing you to "upgrade" your ETH is trying to scam you.** There is nothing you need to do in relation to this upgrade. Your assets will stay completely unaffected. Remember, staying informed is the best defense against scams. + +[More on recognizing and avoiding scams](/security/) + +## More of a visual learner? + + + +_What’s Going Into the Pectra Upgrade? - Christine Kim_ + + + +_Ethereum Pectra Upgrade: What Stakers Need to Know — Blockdaemon_ + +## Further reading + +- [Ethereum roadmap](/roadmap/) +- [Pectra FAQ](https://epf.wiki/#/wiki/pectra-faq) +- [Pectra.wtf info page](https://pectra.wtf) +- [How Pectra enhances staker experience](https://www.kiln.fi/post/next-ethereum-upgrade-how-pectra-will-enhance-the-staking-experience) +- [EIP7702 info page](https://eip7702.io/) +- [Pectra devnets](https://github.com/ethereum/pm/blob/master/Pectra/pectra-pm.md) + +--- + +## Roadmap > Pectra > Maxeb + +# MaxEB + +*tl;dr:* The Pectra hard fork allows Ethereum validators to opt into a higher max effective balance and compounding by converting from **Type 1** to **Type 2** withdrawal credentials. The official tool to do this is the Launchpad. This operation cannot be reversed. + +## Overview + +### Who is affected? + +Anyone who runs a validator - this is likely someone who knows the index (e.g. [Validator #12345](https://beaconcha.in/validator/12345)) of a validator that they control. If you use a protocol to run a validator (e.g. Lido CSM or Rocket Pool), you will have to check with them to see if and when they support maxEB. + +If you stake using a liquid staking token (e.g. rETH or stETH), no action is required or recommended. + +### What is "maxEB"? + +maxEB = the MAXimum Effective Balance of a validator. Until the Pectra hard fork, every validator earns on a maximum 32 ETH. After Pectra, validators have the option to earn on any balance between 32 and 2048 ETH, in 1 ETH increments by opting in to the change. + +### How does a validator opt in? + +A validator opts into the maxEB change by converting from **Type 1** to **Type 2** withdrawal credentials. This can be done on the [Launchpad](https://launchpad.ethereum.org/) after the Pectra hard fork goes live. As with **Type 0** → **Type 1**, converting from **Type 1** → **Type 2** is an irreversible process. + +### What's a withdrawal credential? + +When you run a validator, you have a set of withdrawal credentials. These can be found in your deposit data json or you can view them on your validator's beaconcha.in [deposit tab](https://beaconcha.in/validator/12345#deposits). + +1. **Type 0** withdrawal credentials: If your validator's withdrawal credentials begin with `0x00...`, you deposited before the Shapella hard fork and do not yet have a withdrawal address set. + +![Type 0 withdrawal credential](./0x00-wd.png) + +2. **Type 1** withdrawal credentials: If your validator's withdrawal credentials begin with `0x01...`, you deposited after the Shapella hard fork or already converted your **Type 0** credentials to **Type 1** credentials. + + ![Type 1 withdrawal credential](./0x01-wd.png) + +3. **Type 2** withdrawal credentials: This new withdrawal credential type will begin with `0x02...` and will be enabled after Pectra. Validators with **Type 2** withdrawal credentials are sometimes called "**compounding validators**" + +| **Allowed** | **Not allowed** | +| --- | --- | +| ✅ Type 0 → Type 1 | ❌ Type 0 → Type 2 | +| ✅ Type 1 → Type 2 | ❌ Type 1 → Type 0 | +| | ❌ Type 2 → Type 1 | +| | ❌ Type 2 → Type 0 | + +### Risks + +MaxEB enables a validator to send its entire balance to another validator. Users submitting a consolidation request should verify the source and contents of the transaction they're signing. The official tool for taking advantage of maxEB features is the Launchpad. If you do decide to use a third-party tool, you should verify that: + +- The source validator's pubkey and withdrawal address match the validator they control +- The target validator's pubkey is correct and belongs to them +- The request is a conversion, not a consolidation, if they don't intend to send funds to another validator +- The transaction is being signed by the correct withdrawal address + +We **strongly recommend** discussing any third-party tool you plan to use with the [EthStaker community](https://ethstaker.org/about). It's a helpful place to sanity-check your approach and avoid mistakes. If you use a malicious or misconfigured tool, **your entire validator balance could be sent to a validator you don't control** — with no way to get it back. + +## Technical details + +### The flow + +There will be two uses of the `ConsolidationRequest` operation: + +1. Converting an existing validator from a **Type 1** to a **Type 2** validator +2. Consolidating other validators into an existing **Type 2** validator + +In a conversion of a **Type 1** to a **Type 2** validator, both the *source* and *target* will be the validator you are converting. The operation will cost gas and will be queued behind other consolidation requests. This queue is **separate** from the deposit queue and is unaffected by new validator deposits and can be viewed on [pectrified.com](https://pectrified.com/). + +To consolidate validators, you must have a *target validator* that has a **Type 2** withdrawal credential. This is the destination of any validator balances being consolidated, and the index being preserved. + +### Requirements for converting to Type 2 + +This will be required for the first validator you convert to **Type 2**. This validator's index is preserved and active. For a conversion, the *source validator* == the *target validator.* + +The validator must... + +- be active +- have **Type 1** withdrawal credentials +- not be in an exiting state (or slashed) +- not have pending manually-triggered withdrawals (does not apply to sweeps) + +![conversion illustration](./conversion.png) + +### Requirements for consolidating + +This is the *same operation* as converting but is when the *source validator* is different from the *target validator*. The target validator's index is preserved and accepts the balance from the source validator. The source validator's index is put into an `EXITED` state. + +In this case, the source validator has all the same requirements as above plus: + +- has been active for at least ~27.3 hours (one `SHARD_COMMITTEE_PERIOD`) + +The target validator must + +- have **Type 2** withdrawal credentials +- not be in an exiting state. + +![consolidation illustration](./consolidation.png) + +### The consolidation request + +The consolidation request will be signed by the withdrawal address associated with the source validator and have: + +1. Address of the source validator (e.g. `0x15F4B914A0cCd14333D850ff311d6DafbFbAa32b`) +2. Public key of the source validator (e.g. `0xa1d1ad0714035353258038e964ae9675dc0252ee22cea896825c01458e1807bfad2f9969338798548d9858a571f7425c`) +3. Public key of that target validator + +In a conversion, 2 & 3 will be the same. This operation can be done on [the Launchpad](https://launchpad.ethereum.org/). + +### Signing requirements + +To submit a `ConsolidationRequest`, the **withdrawal address of the source validator** must sign the request. This proves control over the validator funds. + +### What is signed? + +A domain-separated [signing root](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root) of the `ConsolidationRequest` object is used. + +- **Domain:** `DOMAIN_CONSOLIDATION_REQUEST` +- **Signing root fields:** + - `source_pubkey`: `BLSPubkey` + - `target_pubkey`: `BLSPubkey` + - `source_address`: `ExecutionAddress` + +The resulting **BLS signature** is submitted alongside the request. + +Note: The signing is done by the withdrawal address, not the validator key. + +### Partial withdrawals + +Validators with **Type 1** credentials get automatic, gasless sweeps of their excess balance (anything over 32 ETH) to their withdrawal address. Because **Type 2** allows a validator to compound balances in 1 ETH increments, it will not automatically sweep balances until it reaches 2048 ETH. Partial withdrawals on **Type 2** validators must be manually triggered and will cost gas. + +## Consolidation tooling + +There are several tools available to manage consolidations. The official tool, created by the Ethereum Foundation, is the [Launchpad](https://launchpad.ethereum.org/en/validator-actions). There are also third-party tools created by entities from the staking community that may offer features not provided by the Launchpad. While the tools here are not audited or endorsed by the Ethereum Foundation, the following are open source tools by known members of the community. + +| Tool | Website | Open source | Creator | Audited | Interface | Notable features | +| --- | --- | --- | --- | --- | --- | --- | +| Pectra Staking Manager | pectrastaking.com | Yes, Apache 2.0 | [Pier Two](https://piertwo.com/) | No | Web UI | Wallet Connect, works with SAFE | +| Pectra Validator Ops CLI Tool | [GitHub](https://github.com/Luganodes/Pectra-Batch-Contract) | Yes, MIT | [Luganodes](https://www.luganodes.com/) | Yes, Quantstamp [May 2025](https://certificate.quantstamp.com/full/luganodes-pectra-batch-contract/23f0765f-969a-4798-9edd-188d276c4a2b/index.html) | Command line | Batching, for many validators at once | +| Ethereal | [GitHub](https://github.com/wealdtech/ethereal) | Yes, Apache 2.0 | [Jim McDonald](https://www.attestant.io/team/) | No | Command line | Full feature set for validator and node management | +| Siren | [GitHub](https://github.com/sigp/siren) | Yes, Apache 2.0 | [Sigma Prime](https://sigmaprime.io/) | No | Some command line, but primarily web UI | Only works if you're using the Lighthouse consensus client | + +## FAQ + +### Does opting-in change my proposal luck or rewards? + +No. Opting in does not decrease your change of proposal - your duties and proposal selection remain the same. For example, if you have two 32 ETH validators vs one 64 ETH validator, you will have the same total chances of being selected to propose a block and earn rewards. + +### Does opting in change my slashing risk? + +For smaller or unprofessional operators, the short answer is no. The longer answer is that, for professional operators running many validators per node with fast alerting, consolidating into fewer validators may reduce their ability to react to a slashing and prevent cascade events. The initial slashing *penalty* for all validators has been dramatically reduced from 1 ETH (per 32 ETH) to 0.0078125 ETH (per 32 ETH) to offset this risk. + +### Do I have to exit my validator to convert? + +No. You can convert in place without exiting. + +### How long will it take to convert / consolidate? + +A minimum of 27.3 hours but consolidations are also subject to a queue. This queue is independent of the deposit and withdrawal queues and is not affected by them. + +### Can I keep my validator index? + +Yes. In-place conversion keeps the same validator index. If you consolidate multiple validators, you'll only be able to keep the index of the *target validator*. + +### Will I miss attestations? + +During a consolidation into another validator, the source validator is exited and there is a ~27 hour waiting period before the balance is active on the target validator. This period **does not affect performance metrics**. + +### Will I incur penalties? + +No. As long as your validator is online, you will not incur penalties. + +### Do the withdrawal addresses of the validators being consolidated have to match? + +No. But the *source* must authorize the request from its own address. + +### Will my rewards compound after converting? + +Yes. With **Type 2** credentials, rewards above 32 ETH are automatically restaked — but not instantly. Because of a small buffer (called [*hysteresis*](https://eth2book.info/capella/part2/incentives/balances/#hysteresis)), your balance needs to reach **about 1.25 ETH more** before the extra is restaked. So instead of compounding at 33.0 ETH, it happens at 33.25 (effective balance = 33 ETH), then 34.25 (effective balance = 34 ETH), and so on. + +### Can I still get automatic sweeps after converting? + +Automatic sweeps will only happen with excess balances over 2048. For all other partial withdrawals, you'll need to manually trigger them. + +### Can I change my mind and go back from Type 2 to Type 1? + +No. Converting to **Type 2** is irreversible. + +### If I want to consolidate multiple validators, do I have convert each one to Type 2 first? + +Nope! Convert one validator to Type 2 then use that as the target. All other validators consolidated into that Type 2 target can be Type 1 or Type 2 + +### My validator is offline or below 32 ETH - can I still convert it? + +Yes. As long as it's active (not exited) and you can sign with its withdrawal address, you can convert it. + +## Resources + +- [Electra consensus specs](https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md): This is the 'truest' version that you should rely on. When in doubt, read the specs +- Not everybody is comfortable wading through code, so [this maxEB-GPT](https://chatgpt.com/g/g-67f1650fb48081918f555e0c8d1c2ae9-maxeb-gpt) can help interpret the specs. *Disclaimer: The specs, not the AI, should be relied on as truth, as the AI may misinterpret information or hallucinate answers* +- [pectrified.com](https://pectrified.com/): View the state of consolidations, deposits, and queue waiting times +- [Ethereal](https://github.com/wealdtech/ethereal): Community-created CLI tool for managing common validator tasks +- [batch-validator-depositor](https://github.com/attestantio/batch-validator-depositor): Community-created contract that allows multiple Ethereum validators to be deposited in a single transaction + +--- + +## Roadmap > Scaling + +Ethereum is scaled using [layer 2s](/layer-2/#rollups) (also known as rollups), which batch transactions together and send the output to Ethereum. Even though rollups are up to eight times less expensive than Ethereum Mainnet, it's possible to optimize rollups further to reduce costs for end users. Rollups also rely on some centralized components that developers can remove as the rollups mature. + + + + Today’s rollups are ~5-20x cheaper than Ethereum layer 1 + ZK-rollups will soon lower fees by ~40-100x + Upcoming changes to Ethereum will provide another ~100-1000x of scaling + Users should benefit from transactions costing less than $0.001 + + + +## Making data cheaper + +Rollups collect large numbers of transactions, execute them and submit the results to Ethereum. This generates a lot of data that needs to be openly available so that anyone can execute the transactions for themselves and verify that the rollup operator was honest. If someone finds a discrepancy, they can raise a challenge. + +### Proto-Danksharding + +Rollup data has historically been stored on Ethereum permanently, which is expensive. Over 90% of the transaction cost users pay on rollups is due to this data storage. To reduce transaction costs, we can move the data into a new temporary 'blob' storage. Blobs are cheaper because they are not permanent; they get deleted from Ethereum once they are no longer needed. Storing rollup data long-term becomes the responsibility of the people that need it, such as rollup operators, exchanges, indexing services etc. Adding blob transactions to Ethereum is part of an upgrade known as "Proto-Danksharding". + +With Proto-Danksharding, it is possible to add many blobs to Ethereum blocks. This enables another substantial (>100x) scale-up to Ethereum’s throughput and scale-down to transaction costs. + +### Danksharding + +The second stage of expanding blob data is complicated because it requires new methods for checking rollup data is available on the network and relies on [validators](/glossary/#validator) separating their [block](/glossary/#block) building and block proposal responsibilities. It also requires a way to cryptographically prove that validators have verified small subsets of the blob data. + +This second step is known as ["Danksharding"](/roadmap/danksharding/). Implementation work continues, with progress being made on prerequisites like [separating block building and block proposal](/roadmap/pbs) and new network designs that enable the network to efficiently confirm that data is available by randomly sampling a few kilobytes at a time, known as [data availability sampling (DAS)](/developers/docs/data-availability). + +More on Danksharding + +## Decentralizing rollups + +[Rollups](/layer-2) are already scaling Ethereum. A [rich ecosystem of rollup projects](https://l2beat.com/scaling/tvl) is enabling users to transact quickly and cheaply, with a range of security guarantees. However, rollups have been bootstrapped using centralized sequencers (computers that do all the transaction processing and aggregation before submitting them to Ethereum). This is vulnerable to censorship, because the sequencer operators can be sanctioned, bribed or otherwise compromised. At the same time, [rollups vary](https://l2beat.com) in the way they validate incoming data. The best way is for "provers" to submit [fraud proofs](/glossary/#fraud-proof) or validity proofs, but not all rollups are there yet. Even those rollups that do use validity/fraud proofs use a small pool of known provers. Therefore, the next critical step in scaling Ethereum is to distribute responsibility for running sequencers and provers across more people. + +More on rollups + +## Current progress + +Proto-Danksharding was successfully implemented as part of the Cancun-Deneb ("Dencun") network upgrade in March 2024. Since its implementation, rollups have begun utilizing blob storage, resulting in reduced transaction costs for users and millions of transactions processed in blobs. + +Work on full Danksharding continues, with progress being made on its prerequisites like PBS (Proposer-Builder Separation) and DAS (Data Availability Sampling). Decentralizing rollup infrastructure is a gradual process - there are many different rollups that are building slightly different systems and will fully decentralize at different rates. + +[More on the Dencun network upgrade and its impact](/roadmap/dencun/) + +--- + +## Roadmap > Secret Leader Election + +# Secret leader election + +In today's [proof-of-stake](/developers/docs/consensus-mechanisms/pos) based consensus mechanism, the list of upcoming block proposers is public and it is possible to map their IP addresses. This means that attackers could identify which validators are due to propose a block and target them with a denial-of-service (DOS) attack that leaves them unable to propose their block in time. + +This could create opportunities for an attacker to profit. For example a block proposer selected for slot `n+1` could DOS the proposer in slot `n` so that they miss their opportunity to propose a block. This would allow the attacking block proposer to extract the MEV of both slots, or grab all the transactions that should have been split across two blocks and instead include them all in one, gaining all the associated fees. This is likely to affect home validators more than sophisticated institutional validators who can use more advanced methods to protect themselves from DOS attacks, and could therefore be a centralizing force. + +There are several solutions to this problem. One is [Distributed Validator Technology](https://github.com/ethereum/distributed-validator-specs) which aims to spread the various tasks related to running a validator across multiple machines, with redundancy, so that it is much harder for an attacker to prevent a block from being proposed in a particular slot. However, the most robust solution is **Single Secret Leader Election (SSLE)**. + +## Single secret leader election + +In SSLE, clever cryptography is used to ensure that only the selected validator knows they have been selected. This works by having each validator submit a commitment to a secret they all share. The commitments are shuffled and reconfigured so that no-one can map commitments to validators but each validator knows which commitment belongs to them. Then, one commitment is chosen at random. If a validator detects that their commitment was chosen, they know it is their turn to propose a block. + +The leading implementation of this idea is called [Whisk](https://ethresear.ch/t/whisk-a-practical-shuffle-based-ssle-protocol-for-ethereum/11763). Which works as follows: + +1. Validators commit to a shared secret. The commitment scheme is designed such that it can be bound to a validator identity but also randomized so that no third party can reverse engineer the binding and link a specific commitment to a specific validator. +2. At the start of an epoch, a random set of validators is chosen to sample commitments from 16,384 validators, using RANDAO. +3. For the next 8182 slots (1 day), block proposers shuffle and randomize a subset of the commitments using their own private entropy. +4. After the shuffling is finished, RANDAO is used to create an ordered list of the commitments. This list is mapped onto Ethereum slots. +5. Validators see that their commitment is attached to a specific slot, and when that slot arrives they propose a block. +6. Repeat these steps so that the assignment of commitments to slots is always far ahead of the current slot. + +This prevents attackers from knowing in advance which specific validator will propose the next block, preventing the ability for DOS attacks. + +## Secret non-single leader election (SnSLE) + +There is also a separate proposal that aims to create a scenario where validators each have a random chance of proposing a block in each slot, similarly to how block proposal was decided under proof-of-work, known as **secret non-single leader election (SnSLE)**. One simple way to do this is to make use of the RANDAO function used to randomly select validators in today's protocol. The idea with RANDAO is that a sufficiently random number is generated by mixing hashes submitted by many independent validators. In SnSLE, these hashes could be used to choose the next block proposer, for example by choosing the lowest-value hash. The range of valid hashes could be constrained to tune the likelihood of individual validators being selected in each slot. By asserting that the hash must be less than `2^256 * 5 / N` where `N` = number of active validators, the chance of any individual validator being selected in each slot would be `5/N`. In this example, there would be a 99.3% chance of at least one proposer generating a valid hash in each slot. + +## Current progress + +SSLE and SnSLE are both in the research phase. There is no finalized specification for either idea yet. SSLE and SnSLE are competing proposals that couldn't both be implemented. Before shipping they need more research and development, prototyping, and implementing on public testnets. + +## Further reading + +- [SnSLE](https://ethresear.ch/t/secret-non-single-leader-election/11789) + +--- + +## Roadmap > Security + +**Ethereum is already a very secure**, decentralized [smart-contract](/glossary/#smart-contract) platform. However, there are still improvements that can be made so that Ethereum stays resilient to all kinds of attack far into the future. These include subtle changes to the way [Ethereum clients](/glossary/#consensus-client) deal with competing [blocks](/glossary/#block), as well as increasing the speed the network considers blocks to be ["finalized"](/developers/docs/consensus-mechanisms/pos/#finality) (meaning they can't be changed without extreme economic losses to an attacker). + +There are also improvements that make censoring transactions much more difficult by making block proposers blind to the actual contents of their blocks, and new ways to identify when a client is censoring. Together these improvements will upgrade the [proof-of-stake](/glossary/#pos) protocol so that users - from individuals to corporations - have instant confidence in their apps, data and assets on Ethereum. + +## Staking withdrawals + +The upgrade from [proof-of-work](/glossary/#pow) to proof-of-stake began with Ethereum pioneers “staking” their ETH in a deposit contract. That ETH is used to protect the network. There has been a second update on April 12, 2023 to allow withdraw the staked ETH. Since then validators can freely stake or withdraw ETH. + +Read about withdrawals + +## Defending against attacks + +There are improvements that can be made to Ethereum's proof-of-stake protocol. One is known as [view-merge](https://ethresear.ch/t/view-merge-as-a-replacement-for-proposer-boost/13739) - a more secure [fork](/glossary/#fork)-choice algorithm that makes certain sophisticated types of attack more difficult. + +Reducing the time Ethereum takes to [finalize](/glossary/#finality) blocks would provide a better user experience and prevent sophisticated "reorg" attacks where attackers try to reshuffle very recent blocks to extract profit or censor certain transactions. [**Single slot finality (SSF)**](/roadmap/single-slot-finality/) is a **way to minimize the finalization delay**. Right now there are 15 mins worth of blocks that an attacker could theoretically convince other validators to reconfigure. With SSF, there are 0. Users, from individuals to apps and exchanges, benefit from fast assurance that their transactions will not be reverted, and the network benefits by shutting down a whole class of attacks. + +Read about single slot finality + +## Defending against censorship + +Decentralization prevents individuals or small groups of [validators](/glossary/#validator) from becoming too influential. New staking technologies can help to ensure Ethereum's validators stay as decentralized as possible while also defending them against hardware, software and network failures. This includes software that shares validator responsibilities across multiple [nodes](/glossary/#node). This is known as **distributed validator technology (DVT)**. [Staking pools](/glossary/#staking-pool) are incentivized to use DVT because it allows multiple computers to collectively participate in validation, adding redundancy and fault-tolerance. It also splits validator keys across several systems, rather than having single operators running multiple validators. This makes it harder for dishonest operators to coordinate attacks on Ethereum. Overall, the idea is to derive security benefits by running validators as _communities_ rather than as individuals. + +Read about distributed validator technology + +Implementing **proposer-builder separation (PBS)** will drastically improve Ethereum's built-in defenses against censorship. PBS allows one validator to create a block and another to broadcast it across the Ethereum network. This ensures that the gains from professional profit-maximizing block building algorithms are shared more fairly across the network, **preventing stake from concentrating** with the best-performing institutional stakers over time. The block proposer gets to select the most profitable block offered to them by a market of block builders. To censor, a block proposer would often have to choose a less profitable block, which would be **economically irrational and also obvious to the rest of the validators** on the network. + +There are potential add-ons to PBS, such as encrypted transactions and inclusion lists, that could further improve Ethereum's censorship resistance. These make the block builder and proposer blind to the actual transactions included in their blocks. + +Read about proposer-builder separation + +## Protecting validators + +It is possible that a sophisticated attacker could identify upcoming validators and spam them to prevent them from proposing blocks; this is known as a **denial of service (DoS)** attack. Implementing [**secret leader election (SLE)**](/roadmap/secret-leader-election) will protect against this type of attack by preventing block proposers from being knowable in advance. This works by continually shuffling a set of cryptographic commitments representing candidate block proposers and using their order to determine which validator is selected in such a way that only the validators themselves know their ordering in advance. + +Read about secret leader election + +## Current progress + +**Security upgrades on the roadmap are in advanced stages of research**, but they are not expected to be implemented for some time. The next steps for view-merge, PBS, SSF and SLE is to finalize a specification and start building prototypes. + +--- + +## Roadmap > Single Slot Finality + +# Single slot finality + +It takes about 15 minutes for an Ethereum block to finalize. However, we can make Ethereum's consensus mechanism validate blocks more efficiently and decrease time-to-finality dramatically. Instead of waiting for fifteen minutes, blocks could get proposed and finalized in the same slot. This concept is known as **single slot finality (SSF)**. + +## What is finality? + +In Ethereum's proof-of-stake based consensus mechanism, finality refers to the guarantee that a block cannot be altered or removed from the blockchain without burning at least 33% of the total staked ETH. This is 'crypto-economic' security because confidence comes from the extremely high cost associated with changing the order or content of the chain that would prevent any rational economic actor from trying it. + +## Why aim for quicker finality? + +The current time to finality has turned out to be too long. Most users do not want to wait 15 minutes for finality, and it is inconvenient for apps and exchanges that might want high transaction throughput to have to wait that long to be certain their transactions are permanent. Having a delay between a block's proposal and finalization also creates an opportunity for short reorgs that an attacker could use to censor certain blocks or extract MEV. The mechanism that deals with upgrading blocks in stages is also quite complex and has been patched several times to close security vulnerabilities, making it one of the parts of the Ethereum codebase where subtle bugs are more likely to arise. These issues could all be eliminated by reducing the time to finality to a single slot. + +## The decentralization / time / overhead tradeoff + +The finality guarantee is not an immediate property of a new block; it takes time for a new block to finalize. The reason for this is that validators representing at least 2/3 of the total staked ETH on the network have to vote for the block ("attest") in order for it to be considered finalized. Each validating node on the network has to process attestations from other nodes in order to know that a block has, or has not, achieved that 2/3 threshold. + +The shorter the time allowed to reach finalization, the more computing power is required at each node because the attestation processing has to be done faster. Also, the more validating nodes exist on the network, the more attestations have to be processed for each block, also adding to the processing power required. The more processing power required, the fewer people can participate because more expensive hardware is needed to run each validating node. Increasing the time between blocks lessens the computing power required at each node but also lengthens the time to finality, because attestations are processed more slowly. + +Therefore, there is a trade-off between the overhead (computing power), decentralization (number of nodes that can participate in validating the chain) and time to finality. The ideal system balances minimum computing power, maximum decentralization and minimum time to finality. + +Ethereum's current consensus mechanism balanced these three parameters by: + +- **Setting the minimum stake to 32 ETH**. This sets an upper limit on the number of validators' attestations that have to be processed by individual nodes, and therefore an upper limit on computational requirements for each node. +- **Setting the time to finality at ~15 minutes**. This gives sufficient time for validators run on normal home computers to safely process attestations for each block. + +With the current mechanism design, in order to reduce the time to finality, it is necessary to reduce the number of validators on the network or increase the hardware requirements for each node. However, there are improvements that can be made to the way attestations are processed that can allow more attestations to be counted without adding to the overhead at each node. The more efficient processing will allow finality to be determined within a single slot, rather than across two epochs. + +## Routes to SSF + + + +The current consensus mechanism combines attestations from multiple validators, known as committees, to reduce the number of messages each validator has to process to validate a block. Every validator has an opportunity to attest in each epoch (32 slots) but in each slot, only a subset of validators, known as a 'committee' attest. They do so by dividing up into subnets in which a few validators are selected to be 'aggregators'. Those aggregators each combine all the signatures they see from other validators in their subnet into a single aggregate signature. The aggregator that includes the greatest number of individual contributions passes their aggregate signature to the block proposer, who includes it in the block along with the aggregate signature from the other committees. + +This process provides sufficient capacity for every validator to vote in each epoch, because `32 slots * 64 committees * 256 validators per committee = 524,288 validators per epoch`. At the time of writing (February 2023) there are ~513,000 active validators. + +In this scheme, it is only possible for every validator to vote on a block by distributing their attestations across the whole epoch. However, there are potentially ways to improve the mechanism so that _every validator has the chance to attest in every slot_. + + +Since the Ethereum consensus mechanism was designed, the signature aggregation scheme (BLS) has been found to be far more scalable than was initially thought, while the ability of clients to process and verify signatures has also improved. It turns out that processing attestations from a huge number of validators is actually possible within a single slot. For example, with one million validators each voting twice in each slot, and slot times adjusted to be 16 seconds, nodes would be required to verify signatures at a minimum rate of 125,000 aggregations per second in order to process all 1 million attestations within the slot. In reality, it takes a normal computer around 500 nanoseconds to do one signature verification, meaning 125,000 can be done in ~62.5 ms - far below the one second threshold. + +Further efficiency gains could be made by creating supercommittees of e.g. 125,000 randomly selected validators per slot. Only these validators get to vote on a block and therefore only this subset of validators decide whether a block is finalized. Whether this is a good idea or not comes down to how expensive the community would prefer a successful attack on Ethereum to be. This is because instead of requiring 2/3 of the total staked ether, an attacker could finalize a dishonest block with 2/3 of the staked ether _in that supercommittee_. This is still an active area of research, but it seems plausible that for a validator set sufficiently large to require supercommittees in the first place, the cost of attacking one of those subcommittees will be extremely high (e.g. the ETH denominated cost of attack would be `2/3 * 125,000 * 32 = ~2.6 million ETH`). The cost of attack can be adjusted by increasing the size of the validator set (e.g. tune the validator size so the cost of attack is equal to 1 million ether, 4 million ether, 10 million ether, etc). [Preliminary polls](https://youtu.be/ojBgyFl6-v4?t=755) of the community seem to suggest that 1-2 million ether is an acceptable cost of attack, which implies ~65,536 - 97,152 validators per supercommittee. + +However, verification is not the true bottleneck - it is signature aggregation that really challenges validator nodes. To scale signature aggregation will probably require increasing the number of validators in each subnet, increasing the number of subnets, or adding additional layers of aggregation (i.e. implement committees of committees). Part of the solution might be allowing specialized aggregators - similar to how block building and generating commitments for rollup data will be outsourced to specialized block builders under proposer-builder separation (PBS) and Danksharding. + +## What is the role of the fork-choice rule in SSF? + +Today's consensus mechanism relies on a tight coupling between the finality gadget (the algorithm that determines whether 2/3 of validators have attested to a certain chain) and the fork choice rule (the algorithm that decides which chain is the correct one when there are multiple options). The fork choice algorithm only considers blocks _since_ the last finalized block. Under SSF there wouldn't be any blocks for the fork choice rule to consider, because finality occurs in the same slot as the block is proposed. This means that under SSF _either_ the fork choice algorithm _or_ the finality gadget would be active at any time. The finality gadget would finalize blocks where 2/3 of validators were online and attesting honestly. If a block is not able to exceed the 2/3 threshold, the fork choice rule would kick in to determine which chain to follow. This also creates an opportunity to maintain the inactivity leak mechanism that recovers a chain where >1/3 validators go offline, albeit with some additional nuances. + +## Outstanding issues + +The problem with scaling aggregation by growing the number of validators per subnet is that it leads to greater load on the peer-to-peer network. The problem with adding layers of aggregations is that it is quite complex to engineer and adds latency (i.e. it could take longer for the block proposer to hear from all the subnet aggregators). It is also not clear how to deal with the scenario that there are more active validators on the network than can feasibly be processed in each slot, even with BLS signature aggregation. One potential solution is that, because all validators attest in every slot and there are no committees under SSF, the 32 ETH cap on the effective balance could be removed entirely, meaning operators managing multiple validators could consolidate their stake and run fewer, reducing the number of messages that validating nodes have to process to account for the entire validator set. This relies on large stakers agreeing to consolidate their validators. It is also possible to impose a fixed cap on the number of validators or the amount of staked ETH at any time. However, this requires some mechanism for deciding which validators are allowed to participate and which are not, which is liable to create unwanted secondary effects. + +## Current progress + +SSF is in the research phase. It is not expected to ship for several years, likely after other substantial upgrades such as [Verkle trees](/roadmap/verkle-trees/) and [Danksharding](/roadmap/danksharding/). + +## Further reading + +- [Vitalik on SSF at EDCON 2022](https://www.youtube.com/watch?v=nPgUKNPWXNI) +- [Vitalik's notes: Paths to single slot finality](https://notes.ethereum.org/@vbuterin/single_slot_finality) + +--- + +## Roadmap > Statelessness + +# Statelessness, state expiry and history expiry + +The ability to run Ethereum nodes on modest hardware is critical for true decentralization. This is because running a node gives users the ability to verify information by performing cryptographic checks independently rather than trusting a third party to feed them data. Running a node allows users to submit transactions directly to the Ethereum peer-to-peer network rather than having to trust an intermediary. Decentralization is not possible if these benefits are only available to users with expensive hardware. Instead, nodes should be able to run with extremely modest processing and memory requirements so that they can run on mobile phones, micro-computers or unnoticeably on a home computer. + +Today, high disk space requirements is the main barrier preventing universal access to nodes. This is primarily due to the need to store large chunks of Ethereum's state data. This state data contains critical information required to correctly process new blocks and transactions. At the time of writing, a fast 2TB SSD is recommended for running a full Ethereum node. For a node that does not prune any older data, the storage requirement grows at around 14GB/week, and archive nodes that store all data since genesis are approaching 12 TB (at time of writing, in Feb 2023). + +Cheaper hard drives can be used to store older data but those are too slow to keep up with incoming blocks. Keeping the current storage models for clients while making data cheaper and easier to store is only a temporary and partial solution to the problem because Ethereum's state growth is 'unbounded', meaning that storage requirements can only ever increase, and technological improvements will always have to keep pace with continual state growth. Instead, clients must find new ways to verify blocks and transactions that doesn't rely on looking up data from local databases. + +## Reducing storage for nodes + +There are several ways to reduce the amount of data each node has to store, each requiring Ethereum's core protocol to be updated to a different extent: + +- **History expiry**: enable nodes to discard state data older than X blocks, but does not change how Ethereum client's handle state data. +- **State expiry**: allow state data that is not used frequently to become inactive. Inactive data can be ignored by clients until it is resurrected. +- **Weak statelessness**: only block producers need access to full state data, other nodes can verify blocks without a local state database. +- **Strong statelessness**: no nodes need access to the full state data. + +## Data expiry + +### History expiry + +History expiry refers to clients pruning away older data that they are unlikely to need, so that they only store a small amount of historical data, dropping older data when new data arrives. There are two reasons clients require historical data: syncing and serving data requests. Originally, clients had to sync from the genesis block, verifying that each successive block is correct all the way to the head of the chain. Today, clients use "weak subjectivity checkpoints" to bootstrap their way to the head of the chain. These checkpoints are trusted started points, like having a genesis block close to the present rather than the very start of Ethereum. This means clients can drop all information prior to the most recent weak subjectivity checkpoint without losing the ability to sync to the head of the chain. Clients currently serve requests (arriving via JSON-RPC) for historical data by grabbing it from their local databases. However, with history expiry this will not be possible if the requested data has been pruned. Serving this historical data is where some innovative solutions are required. + +One option is that clients request historical data from peers using a solution such as the Portal Network. The Portal Network is an in-development peer-to-peer network for serving historical data where each node stores a small piece of Ethereum's history such that the entire history exists distributed across the network. Requests are served by seeking out peers storing the relevant data and requesting it from them. Alternatively, since it is generally apps that require access to historical data, it can become their responsibility to store it. There may also be enough altruistic actors in the Ethereum space that would be willing to maintain historical archives. It could be a DAO that spins up to manage historical data storage, or ideally it will be a combination of all these options. These providers could serve the data in many ways, such as on a torrent, FTP, Filecoin or IPFS. + +History expiry is somewhat controversial because so far Ethereum has always implicitly guaranteed the availability of any historical data. A full sync from genesis has always been possible as standard, even if it relies on rebuilding some older data from snapshots. History expiry moves the responsibility for providing this guarantee outside of the Ethereum core protocol. This could introduce new censorship risks if it is centralized organizations that end up stepping in to provide historical data. + +EIP-4444 is not yet ready to ship, but it is under active discussion. Interestingly, the challenges with EIP-4444 are not so much technical, but mostly community management. In order for this to ship, there needs to be community buy-in that includes not only agreement but also commitments to store and serve historical data from trustworthy entities. + +This upgrade doesn't fundamentally change how Ethereum nodes handle state data, it just changes how historical data is accessed. + +### State expiry + +State expiry refers to removing state from individual nodes if it hasn't been accessed recently. There are several ways this could be implemented, including: + +- **Expire by rent**: charging "rent" to accounts and expiring them when their rent reaches zero +- **Expire by time**: making accounts inactive if there are no reading/writing to that account for some amount of time + +Expiry by rent could be a direct rent charged to accounts to keep them in the active state database. Expiry by time could be by countdown from the last account interaction, or it could be periodic expiry of all accounts. There could also be mechanisms that combine elements of both the time and rent based-models, for example individual accounts persist in the active state if they pay some small fee prior to time based expiry. With state expiry it is important to note that inactive state is **not deleted**, it is just stored separately from the active state. The inactive state can be resurrected into the active state. + +The way this would work is probably to have a state tree for specific time periods (perhaps ~1 year). Whenever a new period begins, so does a completely fresh state tree. Only the current state tree can be modified, all others are immutable. Ethereum nodes are only expected to hold the current state tree and the next most recent one. This requires a way to time-stamp an address with the period it exists in. There are [several possible ways](https://ethereum-magicians.org/t/types-of-resurrection-metadata-in-state-expiry/6607) to do this, but the leading option requires [addresses to be lengthened](https://ethereum-magicians.org/t/increasing-address-size-from-20-to-32-bytes/5485) to accommodate the additional information with the added benefit that longer addresses are much more secure. The roadmap item that does this is called [address space extension](https://ethereum-magicians.org/t/increasing-address-size-from-20-to-32-bytes/5485). + +Similarly to history expiry, under state expiry responsibility for storing old state data is removed from individual users and pushed onto other entities such as centralized providers, altruistic community members or more futuristic decentralized solutions such as the Portal Network. + +State expiry is still in the research phase and not yet ready to ship. State expiry may well happen later than stateless clients and history expiry because those upgrades make large state sizes easily manageable for the majority of validators. + +## Statelessness + +Statelessness is a bit of a misnomer because it does not mean the concept of "state" is eliminated, but it does involve changes to how Ethereum nodes handle state data. Statelessness itself comes in two flavors: weak statelessness and strong statelessness. Weak statelessness enables most nodes to go stateless by putting responsibility for state storage onto a few. Strong statelessness completely removes the need for any node to store the full state data. Both weak and strong statelessness offer the following benefits to normal validators: + +- nearly instant syncing +- ability to validate blocks out-of-order +- nodes able to run with very low hardware requirements (e.g. on phones) +- nodes can run on top of cheap hard drives because there is no disk reading/writing required +- compatible with future upgrades to Ethereum's cryptography + +### Weak Statelessness + +Weak statelessness does involve changes to the way Ethereum nodes verify state changes, but it does not completely eliminate the need for state storage in all nodes on the network. Instead, weak statelessness puts the responsibility for state storage onto block proposers, while all other nodes on the network verify blocks without storing the full state data. + +**In weak statelessness proposing blocks requires access to full state data but verifying blocks requires no state data** + +For this to happen, [Verkle trees](/roadmap/verkle-trees/) must already have been implemented in Ethereum clients. Verkle trees are a replacement data structure for storing Ethereum state data that allow small, fixed size "witnesses" to the data to be passed between peers and used to verify blocks instead of verifying blocks against local databases. [Proposer-builder separation](/roadmap/pbs/) is also required because this allows block builders to be specialized nodes with more powerful hardware, and those are the ones that require access to the full state data. + + + +Statelessness relies on block builders maintaining a copy of the full state data so that they can generate witnesses that can be used to verify the block. Other nodes do not need access to the state data, all the information required to verify the block is available in the witness. This creates a situation where proposing a block is expensive, but verifying the block is cheap, which implies fewer operators will run a block proposing node. However, decentralization of block proposers is not critical as long as as many participants as possible can independently verify that the blocks they propose are valid. + +Read more on Dankrad's notes + + +Block proposers use the state data to create "witnesses" - the minimal set of data that prove the values of the state that are being changed by the transactions in a block. Other validators do not hold the state, they only store the state root (a hash of the entire state). They receive a block and a witness and use them to update their state root. This makes a validating node extremely lightweight. + +Weak statelessness is in an advanced state of research, but it relies upon proposer-builder separation and Verkle Trees to have been implemented so that small witnesses can be passed between peers. This means weak statelessness is probably a few years away from Ethereum Mainnet. + +### Strong statelessness + +Strong statelessness removes the need for any node to store state data. Instead, transactions are sent with witnesses that can be aggregated by block producers. The block producers are then responsible for storing only that state that are needed for generating witnesses for relevant accounts. The responsibility for state is almost entirely moved to users, as they send witnesses and 'access lists' to declare which accounts and storage keys they are interacting with. This would enable extremely lightweight nodes, but there are tradeoffs including making it more difficult to transact with smart contracts. + +Strong statelessness has been investigated by researchers but is not currently expected to be part of Ethereum's roadmap - it is more likely that weak statelessness is sufficient for Ethereum's scaling needs. + +## Current progress + +Weak statelessness, history expiry and state expiry are all in the research phase and are expected to ship several years from now. There is no guarantee that all of these proposals will be implemented, for example, if state expiry is implemented first there may be no need to also implement history expiry. There are also other roadmap items, such as [Verkle Trees](/roadmap/verkle-trees) and [Proposer-builder separation](/roadmap/pbs) that need to be completed first. + +## Further reading + +- [Vitalik statelessness AMA](https://www.reddit.com/r/ethereum/comments/o9s15i/impromptu_technical_ama_on_statelessness_and/) +- [A theory of state size management](https://hackmd.io/@vbuterin/state_size_management) +- [Resurrection-conflict-minimized state bounding](https://ethresear.ch/t/resurrection-conflict-minimized-state-bounding-take-2/8739) +- [Paths to statelessness and state expiry](https://hackmd.io/@vbuterin/state_expiry_paths) +- [EIP-4444 specification](https://eips.ethereum.org/EIPS/eip-4444) +- [Alex Stokes on EIP-4444](https://youtu.be/SfDC_qUZaos) +- [Why it's so important to go stateless](https://dankradfeist.de/ethereum/2021/02/14/why-stateless.html) +- [The original stateless client concept notes](https://ethresear.ch/t/the-stateless-client-concept/172) +- [More on state expiry](https://hackmd.io/@vbuterin/state_size_management#A-more-moderate-solution-state-expiry) +- [Even more on state expiry](https://hackmd.io/@vbuterin/state_expiry_paths#Option-2-per-epoch-state-expiry) + +--- + +## Roadmap > User Experience + +**Using Ethereum needs to be simplified**; from managing [keys](/glossary/#key) and [wallets](/glossary/#wallet) to initiating transactions. To facilitate mass adoption, Ethereum must drastically increase the ease of use, allowing users to experience permissionless and censorship-resistant access to Ethereum with the frictionless experience of using [Web2](/glossary/#web2) apps. + +## Beyond seed phrases + +Ethereum accounts are protected by a pair of keys used to identify accounts (public key) and sign messages (private key). A private key is like a master password; it allows complete access to an Ethereum account. This is a different way of operating for people more familiar with banks and Web2 apps which manage accounts on a user's behalf. For Ethereum to reach mass adoption without relying on centralized third parties, there must be a straightforward, frictionless way for a user to take custody of their assets and keep control of their data without having to understand public-private key cryptography and key management. + +The solution to this is using [smart contract](/glossary/#smart-contract) wallets to interact with Ethereum. Smart contract wallets create ways to protect accounts if the keys are lost or stolen, opportunities for better fraud detection and defense, and allow wallets to get new functionality. Although smart contract wallets exist today, they are awkward to build because the Ethereum protocol needs to support them better. This additional support is known as account abstraction. + +More on account abstraction + +## Nodes for everyone + +Users running [nodes](/glossary/#node) do not have to trust third parties to provide them with data, and they can interact quickly, privately, and permissionlessly with the Ethereum [blockchain](/glossary/#blockchain). However, running a node right now requires technical knowledge and substantial disk space, meaning many people must trust intermediaries instead. + +There are several upgrades that will make running nodes far easier and far less resource intensive. The way data is stored will be changed to use a more space-efficient structure known as a **Verkle Tree**. Also, with [statelessness](/roadmap/statelessness) or [data expiry](/roadmap/statelessness/#data-expiry), Ethereum nodes will not need to store a copy of the entire Ethereum state data, drastically reducing hard disk space requirements. [Light nodes](/developers/docs/nodes-and-clients/light-clients/) will offer many benefits of running a full node but can run easily on mobile phones or inside simple browser apps. + +Read about Verkle trees + +With these upgrades, the barriers to running a node are reduced to effectively zero. Users will benefit from secure, permissionless access to Ethereum without having to sacrifice noticeable disk space or CPU on their computer or mobile phone, and will not have to rely on third parties for data or network access when they use apps. + +## Current progress + +Smart contract wallets are already available, but more upgrades are required to make them as decentralized and permissionless as possible. EIP-4337 is a mature proposal that does not require any changes to Ethereum's protocol. The main smart contract required for EIP-4337 was **deployed in March 2023**. + +**Full statelessness is still in the research phase** and is likely several years away from being implemented. There are several milestones on the road to full statelessness, including data expiry, that may be implemented sooner. Other roadmap items, such as [Verkle Trees](/roadmap/verkle-trees/) and [Proposer-builder separation](/roadmap/pbs/) need to be completed first. + +Verkle tree testnets are already up and running, and the next phase is running Verkle-tree enabled clients on private, then public testnets. You can help accelerate progress by deploying contracts to the testnets or running testnet clients. + +--- + +## Roadmap > Verkle Trees + +# Verkle trees + +Verkle trees (a portmanteau of "Vector commitment" and "Merkle Trees") are a data structure that can be used to upgrade Ethereum nodes so that they can stop storing large amounts of state data without losing the ability to validate blocks. + +## Statelessness + +Verkle trees are a critical step on the path to stateless Ethereum clients. Stateless clients are ones that do not have to store the entire state database in order to validate incoming blocks. Instead of using their own local copy of Ethereum's state to verify blocks, stateless clients use a "witness" to the state data that arrives with the block. A witness is a collection of individual pieces of the state data that are required to execute a particular set of transactions, and a cryptographic proof that the witness is really part of the full data. The witness is used _instead_ of the state database. For this to work, the witnesses need to be very small, so that they can be safely broadcast across the network in time for validators to process them within a 12 second slot. The current state data structure is not suitable because witnesses are too large. Verkle trees solve this problem by enabling small witnesses, removing one of the main barriers to stateless clients. + + + +Ethereum clients currently use a data structure known as a Patricia Merkle Trie to store its state data. Information about individual accounts are stored as leaves on the trie and pairs of leaves are hashed repeatedly until only a single hash remains. This final hash is known as the "root". To verify blocks, Ethereum clients execute all the transactions in a block and update their local state trie. The block is considered valid if the root of the local tree is identical to the one provided by the block proposer, because any differences in the computation done by the block proposer and the validating node would cause the root hash to be completely different. The problem with this is that verifying the blockchain requires each client to store the whole state trie for the head block and several historical blocks (the default in Geth is to keep state data for 128 blocks behind the head). This requires clients to have access to a large amount of disk space, which is a barrier to running full nodes on cheap, low power hardware. A solution to this is to update the state trie to a more efficient structure (Verkle tree) that can be summarized using a small "witness" to the data that can be shared instead of the full state data. Reformatting the state data into a Verkle tree is a stepping stone for moving to stateless clients. + + + +## What is a witness and why do we need them? + +Verifying a block means re-executing the transactions contained in the block, applying the changes to Ethereum's state trie, and calculating the new root hash. A verified block is one whose computed state root hash is the same as the one provided with the block (because this means the block proposer really did the computation they say they did). In today's Ethereum clients, updating the state requires access to the entire state trie, which is a large data structure that must be stored locally. A witness only contains the fragments of the state data that are required to execute the transactions in the block. A validator can then only use those fragments to verify that the block proposer has executed the block transactions and updated the state correctly. However, this means that the witness needs to be transferred between peers on the Ethereum network rapidly enough to be received and processed by each node safely within a 12 second slot. If the witness is too large, it might take some nodes too long to download it and keep up with the chain. This is a centralizing force because it means only nodes with fast internet connections can participate in validating blocks. With Verkle trees there is no need to have the state stored on your hard drive; _everything_ you need to verify a block is contained within the block itself. Unfortunately, the witnesses that can be produced from Merkle tries are too large to support stateless clients. + +## Why do Verkle trees enable smaller witnesses? + +The structure of a Merkle Trie makes witness sizes very large - too large to safely broadcast between peers within a 12 second slot. This is because the witness is a path connecting the data, which is held in leaves, to the root hash. To verify the data it is necessary to have not only all the intermediate hashes that connect each leaf to the root, but also all the "sibling" nodes. Each node in the proof has a sibling that it is hashed with to create the next hash up the trie. This is a lot of data. Verkle trees reduce the witness size by shortening the distance between the leaves of the tree and its root and also eliminating the need to provide sibling nodes for verifying the root hash. Even more space efficiency will be gained by using a powerful polynomial commitment scheme instead of the hash-style vector commitment. The polynomial commitment allows the witness to have a fixed size regardless of the number of leaves that it proves. + +Under the polynomial commitment scheme, the witnesses have manageable sizes that can easily be transferred on the peer-to-peer network. This allows clients to verify state changes in each block with a minimal amount of data. + + + +The witness size varies depending on the number of leaves it includes. Assuming the witness covers 1000 leaves, a witness for a Merkle trie would be about 3.5MB (assuming 7 levels to the trie). A witness for the same data in a Verkle tree (assuming 4 levels to the tree) would be about 150 kB - **about 23x smaller**. This reduction in witness size will allow stateless client witnesses to be acceptably small. Polynomial witnesses are 0.128 -1 kB depending on which specific polynomial commitment is used. + + + +## What is the structure of a Verkle tree? + +Verkle trees are `(key,value)` pairs where the keys are 32-byte elements composed of a 31-byte _stem_ and a single byte _suffix_. These keys are organized into _extension_ nodes and _inner_ nodes. Extension nodes represent a single stem for 256 children with different suffixes. Inner nodes also have 256 children, but they can be other extension nodes. The main difference between the Verkle tree and the Merkle tree structure is that the Verkle tree is much flatter, meaning there are fewer intermediate nodes linking a leaf to the root, and therefore less data required to generate a proof. + +![](./verkle.png) + +[Read more about the structure of Verkle trees](https://blog.ethereum.org/2021/12/02/verkle-tree-structure) + +## Current progress + +Verkle tree testnets are already up and running, but there are still substantial outstanding updates to clients that are required to support Verkle trees. You can help accelerate progress by deploying contracts to the testnets or running testnet clients. + +[Explore the Verkle Gen Devnet 6 testnet](https://verkle-gen-devnet-6.ethpandaops.io/) + +[Watch Guillaume Ballet explain the Condrieu Verkle testnet](https://www.youtube.com/watch?v=cPLHFBeC0Vg) (note that the Condrieu testnet was proof-of-work and has now been superseded by the Verkle Gen Devnet 6 testnet). + +## Further reading + +- [Verkle Trees for Statelessness](https://verkle.info/) +- [Dankrad Feist explain Verkle trees on PEEPanEIP](https://www.youtube.com/watch?v=RGJOQHzg3UQ) +- [Verkle Trees For The Rest Of Us](https://research.2077.xyz/verkle-trees) +- [Anatomy of A Verkle Proof](https://ihagopian.com/posts/anatomy-of-a-verkle-proof) +- [Guillaume Ballet explain Verkle trees at ETHGlobal](https://www.youtube.com/watch?v=f7bEtX3Z57o) +- ["How Verkle trees make Ethereum lean and mean" by Guillaume Ballet at Devcon 6](https://www.youtube.com/watch?v=Q7rStTKwuYs) +- [Piper Merriam on stateless clients from ETHDenver 2020](https://www.youtube.com/watch?v=0yiZJNciIJ4) +- [Dankrad Fiest explains Verkle trees and statelessness on Zero Knowledge podcast](https://zeroknowledge.fm/podcast/202/) +- [Vitalik Buterin on Verkle trees](https://vitalik.eth.limo/general/2021/06/18/verkle.html) +- [Dankrad Feist on Verkle trees](https://dankradfeist.de/ethereum/2021/06/18/verkle-trie-for-eth1.html) +- [Verkle tree EIP documentation](https://notes.ethereum.org/@vbuterin/verkle_tree_eip#Illustration) + +--- + +# Security + +## Security + +# Ethereum security and scam prevention + +Rising interest in cryptocurrency brings with it growing risk from scammers and hackers. This article lays out some best practices to mitigate these risks. + +**Remember: No one from ethereum.org will ever contact you. Don’t reply to emails saying they’re from official Ethereum support.** + + + +## Crypto security 101 + +### Level up your knowledge + +Misunderstandings about how crypto works can lead to costly mistakes. For example, if someone pretends to be a customer service agent who can return lost ETH in exchange for your private keys, they are preying on people not understanding that Ethereum is a decentralized network lacking this kind of functionality. Educating yourself on how Ethereum works is a worthwhile investment. + + + What is Ethereum? + + + + What is ether? + + + +## Wallet security + +### Don't give out your private keys + +**Never, for any reason, share your private keys!** + +The private key to your wallet is a password to your Ethereum wallet. It is the only thing stopping someone who knows your wallet address from draining your account of all of its assets! + + + What's an Ethereum wallet? + + +#### Don't take screenshots of your seed phrases/private keys + +Screenshotting your seed phrases or private keys might sync them to a cloud data provider, which could make them accessible to hackers. Obtaining private keys from the cloud is a common attack vector for hackers. + +### Use a hardware wallet + +A hardware wallet provides offline storage for private keys. They are considered the most secure wallet option for storing your private keys: your private key never touches the internet and stays completely local on your device. + +Keeping private keys offline massively reduces the risk of being hacked, even if a hacker gets control of your computer. + +#### Try a hardware wallet: + +- [Ledger](https://www.ledger.com/) +- [Trezor](https://trezor.io/) + +### Double check transactions before sending + +Accidentally sending crypto to the wrong wallet address is a common mistake. **A transaction sent on Ethereum is irreversible.** Unless you know the address owner and can convince them to send you your fund back, you will not be able to retrieve your funds. + +Always make sure the address you are sending to exactly matches the desired recipient's address before sending a transaction. +It is good practice when interacting with a smart contract to read the transaction message before signing. + +### Set smart contract spend limits + +When interacting with smart contracts, do not allow unlimited spend limits. An unlimited spend could enable the smart contract to drain your wallet. Instead, set spending limits to only the amount necessary for the transaction. + +Many Ethereum wallets offer limits protection to safeguard against accounts being drained. + +[How to revoke smart contract access to your crypto funds](/guides/how-to-revoke-token-access/) + + + +## Common scams + +It is impossible to stop scammers completely, but we can make them less effective by being aware of their most used techniques. There are many variations of these scams, but they generally follow the same high-level patterns. If nothing else, remember: + +- always be skeptical +- no one is going to give you free or discounted ETH +- no one needs access to your private keys or personal information + +### Twitter ad phishing + +![Twitter link phishing](./twitterPhishingScam.png) + +There is a method for spoofing Twitter's (also known as X) link preview feature (unfurling) to potentially deceive users into thinking they are visiting a legitimate website. This technique exploits Twitter's mechanism for generating previews of URLs shared in tweets, and shows _from ethereum.org_ for example (shown above), when in fact they are being redirected to a malicious site. + +Always check that you are on the right domain, especially after clicking a link. + +[More information here](https://harrydenley.com/faking-twitter-unfurling). + +### Giveaway scam + +One of the most common scams in cryptocurrency is the giveaway scam. The giveaway scam can take many forms, but the general idea is that if you send ETH to the provided wallet address, you will receive your ETH back but doubled. *For this reason, it is also known as the 2-for-1 scam.* + +These scams usually stipulate a limited time of opportunity to claim the giveaway to create a false sense of urgency. + +### Social media hacks + +A high-profile version of this occurred in July 2020, when the Twitter accounts of prominent celebrities and organizations got hacked. The hacker simultaneously posted a Bitcoin giveaway on the hacked accounts. Although the deceptive tweets were quickly noticed and deleted, the hackers still managed to get away with 11 bitcoin (or $500,000 as of September 2021). + +![A scam on Twitter](./appleTwitterScam.png) + +### Celebrity giveaway + +The celebrity giveaway is another common form the giveaway scam takes. The scammers will take a recorded video interview or conference talk given a celebrity and livestream it on YouTube - making it appear as though the celebrity was giving a live video interview endorsing a cryptocurrency giveaway. + +Vitalik Buterin is used most often in this scam, but many other prominent people involved in crypto are also used (e.g. Elon Musk or Charles Hoskinson). Including a well-known person gives the scammers livestream a sense of legitimacy (this looks sketchy, but Vitalik is involved, so it must be ok!). + +**Giveaways are always scams. If you send your funds to these accounts, you will lose them forever.** + +![A scam on YouTube](./youtubeScam.png) + +### Support scams + +Cryptocurrency is a relatively young and misunderstood technology. A common scam that takes advantage of this is the support scam, where scammers will impersonate support personnel for popular wallets, exchanges, or blockchains. + +Much of the discussion about Ethereum happens on Discord. Support scammers will commonly find their target by searching for support questions in public discord channels and then sending the enquirer a private message offering support. By building trust, support scammers try to trick you into revealing your private keys or sending your funds to their wallets. + +![A support scam on Discord](./discordScam.png) + +As a general rule, staff will never communicate with you through private, unofficial channels. Some simple things to keep in mind when dealing with support: + +- Never share your private keys, seed phrases or passwords +- Never allow anyone remote access into your computer +- Never communicate outside an organization's designated channels + + + + Beware: although support-style scams commonly happen on Discord, they can also be prevalent on any chat applications where crypto discussion happens, including email. + + + +### 'Eth2' token scam + +In the run-up to [The Merge](/roadmap/merge/), scammers took advantage of the confusion around the term 'Eth2' to try and get users to redeem their ETH for an 'ETH2' token. There is no 'ETH2', and no other legitimate token was introduced with The Merge. The ETH that you owned before The Merge is the same ETH now. There is **no need to take any action related to your ETH to account for the switch from proof-of-work to proof-of-stake**. + +Scammers may appear as "support", telling you that if you deposit your ETH, you will receive back 'ETH2'. There is no [official Ethereum support](/community/support/), and there is no new token. Never share your wallet seed phrase with anyone. + +_Note: There are derivative tokens/tickers that may represent staked ETH (ie. rETH from Rocket Pool, stETH from Lido, ETH2 from Coinbase), but these are not something you need to "migrate to."_ + +### Phishing scams + +Phishing scams are another increasingly common angle that scammers will use to attempt to steal your wallet's funds. + +Some phishing emails ask users to click on links that will re-direct them to imitation websites, asking them to enter their seed phrase, reset their password or send ETH. Others may ask you to unknowingly install malware to infect your computer and give scammers access to your computer's files. + +If you receive an email from an unknown sender, remember: + +- Never open a link or attachment from email addresses you don't recognize +- Never divulge your personal information or passwords to anyone +- Delete emails from unknown senders + +[More on avoiding phishing scams](https://support.mycrypto.com/staying-safe/mycrypto-protips-how-not-to-get-scammed-during-ico) + +### Crypto trading broker scams + +Scam crypto trading brokers claim to be specialist cryptocurrency brokers who will offer to take your money and invest on your behalf. After the scammer receives your funds, they may lead you on, asking that you send more funds, so you don't miss out on further investment gains, or they may disappear entirely. + +These fraudsters often find targets by using fake accounts on YouTube to start seemingly natural conversations about the 'broker'. These conversations are often highly upvoted to increase legitimacy, but the upvotes are all from bot accounts. + +**Do not trust internet strangers to invest on your behalf. You will lose your crypto.** + +![A trading broker scam on YouTube](./brokerScam.png) + +### Crypto mining pool scams + +As of September 2022, mining on Ethereum is no longer possible. However, mining pool scams still exist. Mining pool scams involve people contacting you unsolicited and claiming that you can make large returns by joining an Ethereum mining pool. The scammer will make claims and stay in contact with you for however long it takes. Essentially, the scammer will try to convince you that when you join an Ethereum mining pool, your cryptocurrency will be used to create ETH and that you will be paid ETH dividends. You will then see that your cryptocurrency is making small returns. This is simply to bait you into investing more. Eventually, all of your funds will be sent to an unknown address, and the scammer will either disappear or in some cases will continue to stay in touch as has happened in a recent case. + +Bottom line: be wary of people who contact you on social media asking for you to be part of a mining pool. Once you lose your crypto, it is gone. + +Some things to remember: + +- Be wary of anyone contacting you about ways to make money off of your crypto +- Do your research about staking, liquidity pools, or other ways of investing your crypto +- Rarely, if ever, are such schemes legitimate. If they were, they would probably be mainstream and you will have heard of them. + +[Man loses $200k in mining pool scam](https://www.reddit.com/r/CoinBase/comments/r0qe0e/scam_or_possible_incredible_payout/) + +### Airdrop scams + +Airdrop scams involve a scam project airdropping an asset (NFT, token) into your wallet and sending you to a scam website to claim the airdropped asset. You will get prompted to sign in with your Ethereum wallet and "approve" a transaction when attempting to claim. This transaction compromises your account by sending your public and private keys to the scammer. An alternative form of this scam may have you confirm a transaction that sends funds to the scammer's account. + +[More on airdrop scams](https://www.youtube.com/watch?v=LLL_nQp1lGk) + + + +## Web security 101 + +### Use strong passwords + +[Over 80% of account hacks are a result of weak or stolen passwords](https://cloudnine.com/ediscoverydaily/electronic-discovery/80-percent-hacking-related-breaches-related-password-issues-cybersecurity-trends/). A long combination of characters, numbers and symbols will help keep your accounts secure. + +A common mistake is using a combination of a few common, related words. Passwords like this are insecure because they are prone to a hacking technique called dictionary attack. + +```md +Example of a weak password: CuteFluffyKittens! + +Example of a strong password: ymv\*azu.EAC8eyp8umf +``` + +Another common mistake is using passwords that can be easily guessed or discovered through [social engineering](). Including your mother's maiden name, the names of your children or pets, or dates of birth in your password will increase the risk of getting hacked. + +#### Good password practices: + +- Make passwords as long as allowed by either your password generator or the form you're filling out +- Use a mixture of uppercase, lowercase, numbers and symbols +- Don't use personal details, such as family names, in your password +- Avoid common words + +[More on creating strong passwords](https://terranovasecurity.com/how-to-create-a-strong-password-in-7-easy-steps/) + +### Use unique passwords for everything + +A strong password that has been revealed in a data breach is no longer a strong password. The website [Have I Been Pwned](https://haveibeenpwned.com) allows you to check if your accounts were involved in any public data breaches. If they have, **change those passwords immediately**. Using unique passwords for every account lowers the risk of hackers getting access to all of your accounts if one of your passwords is compromised. + +### Use a password manager + + + + Using a password manager takes care of creating strong, unique passwords and remembering them! We strongly recommend using one, and most of them are free! + + + +Remembering strong, unique passwords for every account you have isn't ideal. A password manager offers a secure, encrypted store for all your passwords that you can access through one strong master password. They also suggest strong passwords when signing up for a new service, so you don't have to create your own. Many password managers will also tell you if you have been involved in a data breach, allowing you to change the passwords before any malicious attacks. + +![Example of using a password manager](./passwordManager.png) + +#### Try a password manager: + +- [Bitwarden](https://bitwarden.com/) +- [KeePass](https://keepass.info/) +- [1Password](https://1password.com/) +- Or check out other [recommended password managers](https://www.privacytools.io/secure-password-manager) + +### Use Two-Factor Authentication + +You may sometimes be asked to authenticate your identity through unique proofs. These are known as **factors**. The three main factors are: + +- Something you know (such as a password or security question) +- Something you are (such as a fingerprint or iris/facial scanner) +- Something you own (a security key or authentication app on your phone) + +Using **Two-Factor Authentication (2FA)** provides an additional *security factor* for your online accounts. 2FA ensures that merely having your password is not enough to access an account. Most commonly, the second factor is a randomized 6-digit code, known as a **time-based one-time password (TOTP)**, that you can access through an authenticator app such as Google Authenticator or Authy. These work as a "something you own" factor because the seed that generates the timed code is stored on your device. + + + + Note: Using SMS-based 2FA is susceptible to SIM jacking and is not secure. For the best security, use a service like Google Authenticator or Authy. + + + +#### Security keys + +A security key is a more advanced and secure type of 2FA. Security keys are physical hardware authentication devices that work like authenticator apps. Using a security key is the most secure way to 2FA. Many of these keys utilize the FIDO Universal 2nd Factor (U2F) standard. [Learn more about FIDO U2F](https://www.yubico.com/authentication-standards/fido-u2f/). + +Watch more on 2FA: + + + +### Uninstall browser extensions + +Browser extensions, like Chrome extensions or Add-ons for Firefox, can improve browser functionality but also come with risks. By default, most browser extensions ask for access to 'read and change site data', allowing them to do almost anything with your data. Chrome extensions are always automatically updated, so a previously safe extension may update later to include malicious code. Most browser extensions are not trying to steal your data, but you should be aware that they can. + +#### Stay safe by: + +- Only install browser extensions from trusted sources +- Removing unused browser extensions +- Install Chrome extensions locally to stop auto-updating (Advanced) + +[More on the risks of browser extensions](https://www.kaspersky.co.uk/blog/browser-extensions-security/12750/) + + + +## Further reading + +### Web security + +- [Up to 3 million devices infected by malware-laced Chrome and Edge add-ons](https://arstechnica.com/information-technology/2020/12/up-to-3-million-devices-infected-by-malware-laced-chrome-and-edge-add-ons/) - _Dan Goodin_ +- [How to Create a Strong Password — That You Won’t Forget](https://www.avg.com/en/signal/how-to-create-a-strong-password-that-you-wont-forget) - _AVG_ +- [What is a security key?](https://help.coinbase.com/en/coinbase/getting-started/verify-my-account/security-keys-faq) - _Coinbase_ + +### Crypto security + +- [Protecting Yourself and Your Funds](https://support.mycrypto.com/staying-safe/protecting-yourself-and-your-funds) - _MyCrypto_ +- [Security issues in common crypto communication software](https://docs.salusec.io/untitled/web3-penetration-test/risks-in-social-media) - _Salus_ +- [Security Guide For Dummies And Smart People Too](https://medium.com/mycrypto/mycryptos-security-guide-for-dummies-and-smart-people-too-ab178299c82e) - _MyCrypto_ +- [Crypto Security: Passwords and Authentication](https://www.youtube.com/watch?v=m8jlnZuV1i4) - _Andreas M. Antonopoulos_ + +### Scam education + +- [Guide: How to identify scam tokens](/guides/how-to-id-scam-tokens/) +- [Staying Safe: Common Scams](https://support.mycrypto.com/staying-safe/common-scams) - _MyCrypto_ +- [Avoiding Scams](https://bitcoin.org/en/scams) - _Bitcoin.org_ +- [Twitter thread on common crypto phishing emails and messages](https://twitter.com/tayvano_/status/1516225457640787969) - _Taylor Monahan_ + +--- + +# Smart Contracts + +## Smart Contracts + +# Introduction to smart contracts + + + + + +Smart contracts are the fundamental building blocks of Ethereum's application layer. They are computer programs stored on the [blockchain](/glossary/#blockchain) that follow "if this then that" logic, and are guaranteed to execute according to the rules defined by its code, which cannot be changed once created. + +Nick Szabo coined the term "smart contract". In 1994, he wrote [an introduction to the concept](https://www.fon.hum.uva.nl/rob/Courses/InformationInSpeech/CDROM/Literature/LOTwinterschool2006/szabo.best.vwh.net/smart.contracts.html), and in 1996 he wrote [an exploration of what smart contracts could do](https://www.fon.hum.uva.nl/rob/Courses/InformationInSpeech/CDROM/Literature/LOTwinterschool2006/szabo.best.vwh.net/smart_contracts_2.html). + +Szabo envisioned a digital marketplace where automatic, [cryptographically-secure](/glossary/#cryptography) processes enable transactions and business functions to happen without trusted intermediaries. Smart contracts on Ethereum put this vision into practice. + +Watch Finematics explain smart contracts: + + + +## Trust in conventional contracts + +One of the biggest problems with a traditional contract is the need for trusted individuals to follow through with the contract's outcomes. + +Here is an example: + +Alice and Bob are having a bicycle race. Let's say Alice bets Bob $10 that she will win the race. Bob is confident he'll be the winner and agrees to the bet. In the end, Alice finishes the race well ahead of Bob and is the clear winner. But Bob refuses to pay out on the bet, claiming Alice must have cheated. + +This silly example illustrates the problem with any non-smart agreement. Even if the conditions of the agreement get met (i.e. you are the winner of the race), you must still trust another person to fulfill the agreement (i.e. payout on the bet). + +## A digital vending machine + +A simple metaphor for a smart contract is a vending machine, which works somewhat similarly to a smart contract - specific inputs guarantee predetermined outputs. + +- You select a product +- The vending machine displays the price +- You pay the price +- The vending machine verifies that you paid the right amount +- The vending machine gives you your item + +The vending machine will only dispense your desired product after all requirements are met. If you don't select a product or insert enough money, the vending machine won't give out your product. + +## Automatic execution + +The main benefit of a smart contract is that it deterministically executes unambiguous code when certain conditions are met. There is no need to wait for a human to interpret or negotiate the result. This removes the need for trusted intermediaries. + +For example, you could write a smart contract that holds funds in escrow for a child, allowing them to withdraw funds after a specific date. If they try to withdraw before that date, the smart contract won't execute. Or you could write a contract that automatically gives you a digital version of a car's title when you pay the dealer. + +## Predictable outcomes + +Traditional contracts are ambiguous because they rely on humans to interpret and implement them. For example, two judges might interpret a contract differently, which could lead to inconsistent decisions and unequal outcomes. Smart contracts remove this possibility. Instead, smart contracts execute precisely based on the conditions written within the contract's code. This precision means that given the same circumstances, the smart contract will produce the same result. + +## Public record + +Smart contracts are useful for audits and tracking. Since Ethereum smart contracts are on a public blockchain, anyone can instantly track asset transfers and other related information. For example, you can check to see that someone sent money to your address. + +## Privacy protection + +Smart contracts also protect your privacy. Since Ethereum is a pseudonymous network (your transactions are tied publicly to a unique cryptographic address, not your identity), you can protect your privacy from observers. + +## Visible terms + +Finally, like traditional contracts, you can check what's in a smart contract before you sign it (or otherwise interact with it). A smart contract's transparency guarantees that anyone can scrutinize it. + +## Smart contract use cases + +Smart contracts can do essentially anything that computer programs can do. + +They can perform computations, create currency, store data, mint [NFTs](/glossary/#nft), send communications and even generate graphics. Here are some popular, real-world examples: + +- [Stablecoins](/stablecoins/) +- [Creating and distributing unique digital assets](/nft/) +- [An automatic, open currency exchange](/get-eth/#dex) +- [Decentralized gaming](/dapps/?category=gaming#explore) +- [An insurance policy that pays out automatically](https://etherisc.com/) +- [A standard that lets people create customized, interoperable currencies](/developers/docs/standards/tokens/) + +## Further reading + +- [How Smart Contracts Will Change the World](https://www.youtube.com/watch?v=pA6CGuXEKtQ) +- [Smart contracts for developers](/developers/docs/smart-contracts/) +- [Learn to write smart-contracts](/developers/learning-tools/) +- [Mastering Ethereum - What is a Smart Contract?](https://github.com/ethereumbook/ethereumbook/blob/develop/07smart-contracts-solidity.asciidoc#what-is-a-smart-contract) + +--- + +# Social Networks + +## Social Networks + +Social networks play a massive role in our daily communications and interactions. However, centralized control of these platforms has created many problems: data breaches, server outages, de-platforming, censorship, and privacy violations are some of the trade-offs social media often make. To combat these issues, developers are building social networks on Ethereum. Decentralized social networks can fix many of the problems of traditional social networking platforms and improve users' overall experience. + +## What are decentralized social networks? + +Decentralized social networks are [blockchain-based](/glossary/#blockchain) platforms that allow users to exchange information as well as publish and distribute content to audiences. Because these applications run on the blockchain, they are capable of being decentralized and resistant to censorship and undue control. + +Many decentralized social networks exist as alternatives to established social media services, such as Facebook, LinkedIn, Twitter, and Medium. But blockchain-powered social networks have a number of features that put them ahead of traditional social platforms. + + + +### How do decentralized social networks work? + +Decentralized social networks are a class of [decentralized applications (dapps)](/dapps/)—applications powered by [smart contracts](/glossary/#smart-contract) deployed on the blockchain. The contract code serves as the backend for these apps and defines their business logic. + +Traditional social media platforms rely on databases to store user information, program code, and other forms of data. But this creates single points-of-failure and introduces significant risk. For instance, Facebook's servers infamously [went offline for hours](https://www.npr.org/2021/10/05/1043211171/facebook-instagram-whatsapp-outage-business-impact) in October 2021, cutting off users from the platform. + +Decentralized social networks exist on a [peer-to-peer network](/glossary/#peer-to-peer-network) comprising thousands of nodes around the globe. Even if some nodes fail, the network will run uninterrupted, making applications resistant to failures and outages. + +Using decentralized storage systems like [the InterPlanetary File System (IPFS)](https://ipfs.io/), social networks built on Ethereum can protect user information from exploitation and malicious use. No one will sell your personal information to advertisers, neither will hackers be able to steal your confidential details. + +Many blockchain-based social platforms have native tokens that power monetization in absence of advertising revenue. Users can buy these tokens to access certain features, complete in-app purchases, or tip their favorite content creators. + +## Benefits of decentralized social networks + +1. Decentralized social networks are censorship-resistant and open to everyone. This means **users cannot be banned**, deplatformed, or restricted arbitrarily. + +2. Decentralized social networks are **built on open-source ideals** and make source code for applications available for public inspection. By eliminating the implementation of opaque algorithms common in traditional social media, blockchain-based social networks can align the interests of users and platform creators. + +3. Decentralized social networks eliminate the "middle-man". Content **creators have direct ownership over their content**, and they engage directly with followers, fans, buyers, and other parties, with nothing but a smart contract in between. + +4. As dapps running on the Ethereum network, which is sustained by a global, peer-to-peer network of nodes, decentralized social networks are **less susceptible to server downtime** and outages. + +5. Decentralized social platforms offer an **improved monetization** framework for content creators via [non-fungible tokens (NFTs)](/glossary/#nft), in-app crypto payments, and more. + +6. Decentralized social networks afford users **a high level of privacy and anonymity**. For instance, an individual can sign in to an Ethereum-based social network using an [ENS](/glossary/#ens) profile or [wallet](/glossary/#wallet)—without having to share personally identifiable information (PII), such as names, email addresses, etc. + +7. Decentralized social networks rely on decentralized storage, not centralized databases, which are considerably better for safeguarding user data. + +## Decentralized social networks on Ethereum + +The Ethereum network has become the preferred tool for developers creating decentralized social media owing to the popularity of its tokens and its massive user base. Here are some examples of Ethereum-based social networks: + +### Mirror + +[Mirror](https://mirror.xyz/) is a web3-enabled writing platform that aims to be decentralized and user-owned. Users can read and write for free on Mirror by simply connecting their wallets. Users can also collect writing and subscribe to their favorite writers. + +Posts published on Mirror are permanently stored on Arweave, a decentralized storage platform, and can be minted as collectable [non-fungible tokens (NFTs)](/nft/) known as Writing NFTs. Writing NFTs are completely free for writers to create, and collection happens on an Ethereum [L2](/glossary/#layer-2) — making transactions inexpensive, fast, and environmentally friendly. + +### MINDS + +[MINDS](https://www.minds.com/) is one of the most used decentralized social networks. It works like Facebook and has racked up millions of users already. + +Users use the platform's native [ERC-20](/glossary/#erc-20) token $MIND to pay for items. Users can also earn $MIND tokens by publishing popular content, contributing to the ecosystem, and referring others to the platform. + +## Use decentralized social networks + +- **[Status.im](https://status.im/)** - _Status is a secure messaging app that uses an open-source, peer-to-peer protocol, and end-to-end encryption to protect your messages from third parties._ +- **[Mirror.xyz](https://mirror.xyz/)** - _Mirror is a decentralized, user-owned publishing platform built on Ethereum for users to crowdfund ideas, monetize content, and build high-value communities._ +- **[Lens Protocol](https://lens.xyz/)** - _Lens Protocol is a composable and decentralized social graph helping creators take ownership of their content wherever they go in the digital garden of the decentralized internet._ +- **[Farcaster](https://farcaster.xyz/)** - _Farcaster is a sufficiently decentralized social network. It is an open protocol that can support many clients, just like email._ + +## Web2 social networks on Ethereum + +[Web3](/glossary/#web3) native social platforms aren't the only ones trying to incorporate blockchain technology into social media. Many centralized platforms are also exploring or have experimented with integrating Ethereum into their infrastructure: + +### Reddit + +- Reddit previously experimented with **Community Points**, which were ERC-20 tokens users could earn by posting quality content and contributing to specific online communities (subreddits). Users could redeem these tokens within a subreddit for exclusive perks or trade them. For this project, Reddit utilized Arbitrum Nova, a [layer 2](/glossary/#layer-2) network designed to scale Ethereum transactions. +- The program was notably active in the r/CryptoCurrency subreddit with its "Moons" and the r/FortNiteBR subreddit with its "Bricks". Because these tokens were on the blockchain, they were independent of Reddit once claimed into a user's [wallet](/glossary/#wallet). +- However, **Reddit [sunsetted the Community Points program](https://www.reddit.com/r/CryptoCurrency/comments/17a33ql/reddit_is_officially_deprecating_community_points/) in late 2023**, citing scalability and resource challenges. While the tokens still exist on the blockchain, Reddit no longer actively supports or integrates them into its platform features. + +## Further reading + +### Articles + +- [Decentralizing social media: a guide to the web3 social stack](https://www.coinbase.com/blog/decentralizing-social-media-a-guide-to-the-web3-social-stack) - _Coinbase Ventures_ +- [Social Networks Are the Next Big Decentralization Opportunity](https://www.coindesk.com/tech/2021/01/22/social-networks-are-the-next-big-decentralization-opportunity/) — _Ben Goertzel_ +- [Web3 holds the promise of decentralized, community-powered social networks](https://venturebeat.com/2022/02/26/web3-holds-the-promise-of-decentralized-community-powered-social-networks/) — _Sumit Ghosh_ +- [An Overview of the Blockchain Social Media Landscape](https://www.gemini.com/cryptopedia/blockchain-social-media-decentralized-social-media) — _Gemini Cryptopedia_ +- [How Blockchain Can Solve Social Media Privacy](https://www.investopedia.com/news/ethereum-blockchain-social-media-privacy-problem-linkedin-indorse/) — _Prableen Bajpai_ +- [Sufficient Decentralization for Social Networks](https://www.varunsrinivasan.com/2022/01/11/sufficient-decentralization-for-social-networks) — _Varun Srinivasan_ + +### Videos + +- [Decentralized Social Media Explained](https://www.youtube.com/watch?v=UdT2lpcGvcQ) — _Coinmarketcap_ +- [DeSo Blockchain Wants to Decentralize Social Media](https://www.youtube.com/watch?v=SG2HUiVp0rE) — _Bloomberg Technology_ +- [The Future of Decentralized Social Media w/ Balaji Srinivasan, Vitalik Buterin, Juan Benet](https://www.youtube.com/watch?v=DTxE9KV3YrE) — _ETHGlobal_ + +### Communities + +- [r/CryptoCurrency subreddit](https://www.reddit.com/r/CryptoCurrency/) + +--- + +# Staking + +## Staking > Dvt + +# Distributed validator technology + +Distributed validator technology (DVT) is an approach to validator security that spreads out key management and signing responsibilities across multiple parties, to reduce single points of failure, and increase validator resiliency. + +It does this by **splitting the private key** used to secure a validator **across many computers** organized into a "cluster". The benefit of this is that it makes it very difficult for attackers to gain access to the key, because it is not stored in full on any single machine. It also allows for some nodes to go offline, as the necessary signing can be done by a subset of the machines in each cluster. This reduces single points of failure from the network and makes the whole validator set more robust. + +![A Diagram showing how a single validator key is split into key shares and distributed to multiple nodes with varying components.](./dvt-cluster.png) + +## Why do we need DVT? + +### Security + +Validators generate two public-private key pairs: validator keys for participating in consensus and withdrawal keys for accessing funds. While validators can secure withdrawal keys in cold storage, validator private keys must be online 24/7. If a validator private key is compromised, an attacker can control the validator, potentially leading to slashing or the loss of the staker's ETH. DVT can help mitigate this risk. Here's how: + +By using DVT, stakers can participate in staking while keeping the validator private key in cold storage. This is achieved by encrypting the original, full validator key and then splitting it into key shares. The key shares live online and are distributed to multiple nodes which enable the distributed operation of the validator. This is possible because Ethereum validators use BLS signatures that are additive, meaning the full key can be reconstructed by summing their component parts. This allows the staker to keep the full, original 'master' validator key securely offline. + +### No single points of failure + +When a validator is divided across multiple operators and multiple machines, it can withstand individual hardware and software failures without going offline. The risk of failures can also be reduced by using diverse hardware and software configurations across the nodes in a cluster. This resilience is not available to single-node validator configurations - it comes from the DVT layer. + +If one of the components of a machine in a cluster goes down (for example, if there are four operators in a validator cluster and one uses a specific client that has a bug), the others ensure that the validator keeps running. + +### Decentralization + +The ideal scenario for Ethereum is to have as many independently operated validators as possible. However, a few staking providers have become very popular and account for a substantial portion of the total staked ETH on the network. DVT can allow these operators to exist while preserving decentralization of stake. This is because the keys for each validator are distributed across many machines and it would take much greater collusion for a validator to turn malicious. + +Without DVT, it's easier for staking providers to support only one or two client configurations for all their validators, increasing the impact of a client bug. DVT can be used to spread the risk across multiple client configurations and different hardware, creating resilience through diversity. + +**DVT offers the following benefits to Ethereum:** + +1. **Decentralization** of Ethereum's proof-of-stake consensus +2. Ensures the **liveness** of the network +3. Creates validator **fault tolerance** +4. **Trust minimized** validator operation +5. **Minimized slashing** and downtime risks +6. **Improves diversity** (client, data center, location, regulation, etc.) +7. **Enhanced security** of validator key management + +## How does DVT work? + +A DVT solution contains the following components: + +- **[Shamir's secret sharing](https://medium.com/@keylesstech/a-beginners-guide-to-shamir-s-secret-sharing-e864efbf3648)** - Validators use [BLS keys](https://en.wikipedia.org/wiki/BLS_digital_signature). Individual BLS "key shares" ("key shares") can be combined into a single aggregated key (signature). In DVT, the private key for a validator is the combined BLS signature of each operator in the cluster. +- **[Threshold signature scheme](https://medium.com/nethermind-eth/threshold-signature-schemes-36f40bc42aca)** - Determines the number of individual key shares that are required for signing duties, e.g., 3 out of 4. +- **[Distributed key generation (DKG)](https://medium.com/toruslabs/what-distributed-key-generation-is-866adc79620)** - Cryptographic process that generates the key shares and is used to distribute the shares of an existing or new validator key to the nodes in a cluster. +- **[Multiparty computation (MPC)](https://messari.io/report/applying-multiparty-computation-to-the-world-of-blockchains)** - The full validator key is generated in secret using multiparty computation. The full key is never known to any individual operator—they only ever know their own part of it (their "share"). +- **Consensus protocol** - The consensus protocol selects one node to be the block proposer. They share the block with the other nodes in the cluster, who add their key shares to the aggregate signature. When enough key shares have been aggregated, the block is proposed on Ethereum. + +Distributed validators have built-in fault tolerance and can keep running even if some of the individual nodes go offline. This means that the cluster is resilient even if some of the nodes within it turn out to be malicious or lazy. + +## DVT use cases + +DVT has significant implications for the broader staking industry: + +### Solo stakers + +DVT also enables non-custodial staking by allowing you to distribute your validator key across remote nodes while keeping the full key completely offline. This means home stakers do not necessarily need to outlay for hardware, while distributing the key shares can help strengthen them against potential hacks. + +### Staking as a service (SaaS) + +Operators (such as staking pools and institutional stakers) managing many validators can use DVT to reduce their risk. By distributing their infrastructure, they can add redundancy to their operations and diversify the types of hardware they use. + +DVT shares responsibility for key management across multiple nodes, meaning some operational costs can also be shared. DVT can also reduce operational risk and insurance costs for staking providers. + +### Staking pools + +Due to standard validator setups, staking pools and liquid staking providers are compelled to have varying levels of single-operator trust since gains and losses are socialized throughout the pool. They are also reliant on operators to safeguard signing keys because, until now, there has been no other option for them. + +Even though traditionally efforts are made to spread risk by distributing stakes across multiple operators, each operator still manages a significant stake independently. Relying on a single operator poses immense risks if they underperform, encounter downtime, get compromised, or act maliciously. + +By leveraging DVT, the trust required from operators is significantly reduced. **Pools can enable operators to hold stakes without needing custody of validator keys** (as only key shares are utilized). It also allows managed stakes to be distributed between more operators (e.g., instead of having a single operator managing 1000 validators, DVT enables those validators to be collectively run by multiple operators). Diverse operator configurations will ensure that if one operator should go down, the others will still be able to attest. This results in redundancy and diversification that leads to better performance and resilience, while maximizing rewards. + +Another benefit to minimizing single-operator trust is that staking pools can allow more open and permissionless operator participation. By doing this, services can reduce their risk and support Ethereum decentralization by using both curated and permissionless sets of operators, for example, by pairing home or more minor stakers with larger ones. + +## Potential drawbacks of using DVT + +- **Additional component** - introducing a DVT node adds another part that can possibly be faulty or vulnerable. A way to mitigate this is to strive for multiple implementations of a DVT node, meaning multiple DVT clients (similarly as there are multiple clients for the consensus and execution layers). +- **Operational costs** - as DVT distributes the validator between multiple parties, there are more nodes required for operation instead of only a single node, which introduces increased operating costs. +- **Potentially increased latency** - since DVT utilizes a consensus protocol to achieve consensus between the multiple nodes operating a validator, it can potentially introduce increased latency. + +## Further Reading + +- [Ethereum distributed validator specs (high level)](https://github.com/ethereum/distributed-validator-specs) +- [Ethereum distributed validator technical specs](https://github.com/ethereum/distributed-validator-specs/tree/dev/src/dvspec) +- [Shamir secret sharing demo app](https://iancoleman.io/shamir/) + +--- + +## Staking > Pools + +## What are staking pools? + +Staking pools are a collaborative approach to allow many with smaller amounts of ETH to obtain the 32 ETH required to activate a set of validator keys. Pooling functionality is not natively supported within the protocol, so solutions were built out separately to address this need. + +Some pools operate using smart contracts, where funds can be deposited to a contract, which trustlessly manages and tracks your stake, and issues you a token that represents this value. Other pools may not involve smart contracts and are instead mediated offchain. + +## Why stake with a pool? + +In addition to the benefits we outlined in our [intro to staking](/staking/), staking with a pool comes with a number of distinct benefits. + + + + + + + + + +## What to consider + +Pooled or delegated staking is not natively supported by the Ethereum protocol, but given the demand for users to stake less than 32 ETH a growing number of solutions have been built out to serve this demand. + +Each pool and the tools or smart contracts they use have been built out by different teams, and each comes with benefits and risks. Pools enable users to swap their ETH for a token representing staked ETH. The token is useful because it allows users to swap any amount of ETH to an equivalent amount of a yield-bearing token that generates a return from the staking rewards applied to the underlying staked ETH (and vice versa) on decentralized exchanges even though the actual ETH stays staked on the consensus layer. This means swaps back and forth from a yield-bearing staked-ETH product and "raw ETH" is quick, easy and not only available in multiples of 32 ETH. + +However, these staked-ETH tokens tend to create cartel-like behaviors where a large amount of staked ETH ends up under the control of a few centralized organizations rather than spread across many independent individuals. This creates conditions for censorship or value extraction. The gold standard for staking should always be individuals running validators on their own hardware whenever possible. + +[More on risks of staking tokens](https://notes.ethereum.org/@djrtwo/risks-of-lsd). + +Attribute indicators are used below to signal notable strengths or weaknesses a listed staking pool may have. Use this section as a reference for how we define these attributes while you're choosing a pool to join. + + + +## Explore staking pools + +There are a variety of options available to help you with your setup. Use the above indicators to help guide you through the tools below. + + + + + +Please note the importance of choosing a service that takes [client diversity](/developers/docs/nodes-and-clients/client-diversity/) seriously, as it improves the security of the network, and limits your risk. Services that have evidence of limiting majority client use are indicated with "execution client diversity" and "consensus client diversity." + +Have a suggestion for a staking tool we missed? Check out our [product listing policy](/contributing/adding-staking-products/) to see if it would be a good fit, and to submit it for review. + +## Frequently asked questions + + +Typically ERC-20 staking tokens are issued to stakers and represent the value of their staked ETH plus rewards. Keep in mind that different pools will distribute staking rewards to their users via slightly different methods, but this is the common theme. + + + +Right now! The Shanghai/Capella network upgrade occurred in April 2023, and introduced staking withdrawals. Validator accounts that back staking pools now have the ability to exit and withdraw ETH to their designated withdrawal address. This enables the ability to redeem your portion of stake for the underlying ETH. Check with your provider to see how they support this functionality. + +Alternatively, pools that utilize an ERC-20 staking token allow users to trade this token in the open market, allowing you to sell your staking position, effectively "withdrawing" without actually removing ETH from the staking contract. + +More on staking withdrawals + + + +There are many similarities between these pooled staking options and centralized exchanges, such as the ability to stake small amounts of ETH and have them bundled together to activate validators. + +Unlike centralized exchanges, many other pooled staking options utilize smart contracts and/or staking tokens, which are usually ERC-20 tokens that can be held in your own wallet, and bought or sold just like any other token. This offers a layer of sovereignty and security by giving you control over your tokens, but still does not give you direct control over the validator client attesting on your behalf in the background. + +Some pooling options are more decentralized than others when it comes to the nodes that back them. To promote the health and decentralization of the network, stakers are always encouraged to select a pooling service that enables a permissionless decentralized set of node operators. + + +## Further reading + +- [The Ethereum Staking Directory](https://www.staking.directory/) - _Eridian and Spacesider_ +- [Staking with Rocket Pool - Staking Overview](https://docs.rocketpool.net/guides/staking/overview.html) - _RocketPool docs_ +- [Staking Ethereum With Lido](https://help.lido.fi/en/collections/2947324-staking-ethereum-with-lido) - _Lido help docs_ + +--- + +## Staking > Saas + +## What is staking as a service? + +Staking as a service (“SaaS") represents a category of staking services where you deposit your own 32 ETH for a validator, but delegate node operations to a third-party operator. This process usually involves being guided through the initial setup, including key generation and deposit, then uploading your signing keys to the operator. This allows the service to operate your validator on your behalf, usually for a monthly fee. + +## Why stake with a service? + +The Ethereum protocol does not natively support delegation of stake, so these services have been built out to fill this demand. If you have 32 ETH to stake, but don't feel comfortable dealing with hardware, SaaS services allow you to delegate the hard part while you earn native block rewards. + + + + + + + + + +## What to consider + +There are a growing number of SaaS providers to help you stake your ETH, but they all have their own benefits and risks. All SaaS options require additional trust assumptions compared to home-staking. Saas options may have additional code wrapping the Ethereum clients that is not open or auditable. SaaS also has a detrimental effect on network decentralization. Depending on the setup, you may not control your validator - the operator could act dishonestly using your ETH. + +Attribute indicators are used below to signal notable strengths or weaknesses a listed SaaS provider may have. Use this section as a reference for how we define these attributes while you're choosing a service to help with your staking journey. + + + +## Explore staking service providers + +Below are some available SaaS providers. Use the above indicators to help guide you through these services + + + +### SaaS providers + + + +Please note the importance of supporting [client diversity](/developers/docs/nodes-and-clients/client-diversity/) as it improves the security of the network, and limits your risk. Services that have evidence of limiting majority client use are indicated with "execution client diversity" and "consensus client diversity." + +### Key Generators + + + +Have a suggestion for a staking-as-a-service provider we missed? Check out our [product listing policy](/contributing/adding-staking-products/) to see if it would be a good fit, and to submit it for review. + +## Frequently asked questions + + +Arrangements will differ from provider-to-provider, but commonly you will be guided through setting up any signing keys you need (one per 32 ETH), and uploading these to your provider to allow them to validate on your behalf. The signing keys alone do not give any ability to withdraw, transfer, or spend your funds. However, they do provide the ability to cast votes towards consensus, which if not done properly can result in offline penalties or slashing. + + + +Yes. Each account is comprised of both BLS signing keys, and BLS withdrawal keys. In order for a validator to attest to the state of the chain, participate in sync committees and propose blocks, the signing keys must be readily accessible by a validator client. These must be connected to the internet in some form, and are thus inherently considered to be "hot" keys. This is a requirement for your validator to be able to attest, and thus the keys used to transfer or withdraw funds are separated for security reasons. + +The BLS withdrawal keys are used to sign a one-time message that declares which execution layer account staking rewards and exited funds should go to. Once this message is broadcast, the BLS withdrawal keys are no longer needed. Instead, control over withdrawn funds is permanently delegated to the address you provided. This allows you to set a withdrawal address secured via your own cold storage, minimizing risk to your validator funds, even if someone else controls your validator signing keys. + +Updating withdrawal credentials is a required step to enable withdrawals\*. This process involves generating the withdrawal keys using your mnemonic seed phrase. + +Make certain you back this seed phrase up safely or you will be unable to generate your withdraw keys when the time comes. + +\*Stakers who provided a withdrawal address with initial deposit do not need to set this. Check with your SaaS provider for support regarding how to prepare your validator. + + + +Stakers need to provide a withdrawal address (if not provided on initial deposit), and reward payments will begin being distributed automatically on a periodic basis every few days. + +Validators can also fully exit as a validator, which will unlock their remaining ETH balance for withdrawal. Accounts that have provided an execution withdrawal address and completed the exiting process will receive their entire balance to the withdrawal address provided during the next validator sweep. + +More on staking withdrawals + + + +By using an SaaS provider, you are entrusting the operation of your node to someone else. This comes with the risk of poor node performance, which is not in your control. In the event your validator is slashed, your validator balance will be penalized and forcibly removed from the validator pool. + +Upon completion of the slashing/exiting process, these funds will be transferred to the withdrawal address assigned to the validator. This requires providing a withdrawal address to enable. This may have been provided on initial deposit. If not, the validator withdrawal keys will need to be used to sign a message declaring a withdrawal address. If no withdrawal address has been provided, funds will remain locked until provided. + +Contact individual SaaS provider for more details on any guarantees or insurance options, and for instructions on how to provide a withdrawal address. If you'd prefer to be in full control of your validator setup, learn more about how to solo stake your ETH. + + +## Further reading + +- [The Ethereum Staking Directory](https://www.staking.directory/) - _Eridian and Spacesider_ +- [Evaluating Staking Services](https://www.attestant.io/posts/evaluating-staking-services/) - _Jim McDonald 2020_ + +--- + +## Staking > Solo + +## What is home staking? + +Home staking is the act of [running an Ethereum node](/run-a-node/) connected to the internet and depositing 32 ETH to activate a [validator](#faq), giving you the ability to participate directly in network consensus. + +**Home staking increases the decentralization of the Ethereum network**, making Ethereum more censorship-resistant and robust against attacks. Other staking methods may not help the network in the same ways. Home staking is the best staking option for securing Ethereum. + +An Ethereum node consists of both an execution layer (EL) client, as well as a consensus layer (CL) client. These clients are software that work together, along with a valid set of signing keys, to verify transactions and blocks, attest to the correct head of the chain, aggregate attestations, and propose blocks. + +Home stakers are responsible for operating the hardware needed to run these clients. It is highly recommended to use a dedicated machine for this that you operate from home–this is extremely beneficial to the health of the network. + +A home staker receives rewards directly from the protocol for keeping their validator properly functioning and online. + +## Why stake from home? + +Home staking comes with more responsibility but provides you with maximum control over your funds and staking setup. + + + + + + + +## Considerations before home staking + +As much as we wish that home staking was accessible and risk free to everyone, this is not reality. There are some practical and serious considerations to keep in mind before choosing to home stake your ETH. + + + +When operating your own node you should spend some time learning how to use the software you've chosen. This involves reading relevant documentation and being attune to communication channels of those dev teams. + +The more you understand about the software you're running and how proof-of-stake works, the less risky it will be as a staker, and the easier it will be to fix any issues that may arise along the way as a node operator. + + + +Node setup requires a reasonable comfort level when working with computers, although new tools are making this easier over time. Understanding of the command-line interface is helpful, but no longer strictly required. + +It also requires very basic hardware setup, and some understanding of minimum recommended specs. + + + +Just like how private keys secure your Ethereum address, you will need to generate keys specifically for your validator. You must understand how to keep any seed phrases or private keys safe and secure. + +Ethereum security and scam prevention + + + +Hardware occasionally fails, network connections error out, and client software occasionally needs upgrading. Node maintenance is inevitable and will occasionally require your attention. You'll want to be sure you stay aware of any anticipated network upgrades, or other critical client upgrades. + + + +Your rewards are proportional to the time your validator is online and properly attesting. Downtime incurs penalties proportional to how many other validators are offline at the same time, but does not result in slashing. Bandwidth also matters, as rewards are decreased for attestations that are not received in time. Requirements will vary, but a minimum of 10 Mb/s up and down is recommended. + + + +Different from inactivity penalties for being offline, slashing is a much more serious penalty reserved for malicious offenses. By running a minority client with your keys loaded on only one machine at time, your risk of being slashed is minimized. That being said, all stakers must be aware of the risks of slashing. + + More on slashing and validator lifecycle + + + + + +## How it works + + + +While active you will earn ETH rewards, which will be periodically deposited into your withdrawal address. + +If ever desired, you can exit as a validator which eliminates the requirement to be online, and stops any further rewards. Your remaining balance will then be withdrawn to the withdrawal address that you designate during setup. + +[More on staking withdrawals](/staking/withdrawals/) + +## Get started on the Staking Launchpad + +The Staking Launchpad is an open source application that will help you become a staker. It will guide you through choosing your clients, generate your keys and depositing your ETH to the staking deposit contract. A checklist is provided to make sure you've covered everything to get your validator set up safely. + + + +## What to consider with node and client setup tools + +There are a growing number of tools and services to help you home stake your ETH, but each come with different risks and benefits. + +Attribute indicators are used below to signal notable strengths or weaknesses a listed staking tool may have. Use this section as a reference for how we define these attributes while you’re choosing what tools to help with your staking journey. + + + +## Explore node and client setup tools + +There are a variety of options available to help you with your setup. Use the above indicators to help guide you through the tools below. + + + +### Node tools + + + +Please note the importance of choosing a [minority client](/developers/docs/nodes-and-clients/client-diversity/) as it improves the security of the network, and limits your risk. Tools that allow you to setup minority client are denoted as "multi-client." + +### Key Generators + +These tools can be used as an alternative to the [Staking Deposit CLI](https://github.com/ethereum/staking-deposit-cli/) to help with key generation. + + + +Have a suggestion for a staking tool we missed? Check out our [product listing policy](/contributing/adding-staking-products/) to see if it would be a good fit, and to submit it for review. + +## Explore home staking guides + + + +## Frequently asked questions + +These are a few of the most common questions about staking that are worth knowing about. + + + +A validator is a virtual entity that lives on Ethereum and participates in the consensus of the Ethereum protocol. Validators are represented by a balance, public key, and other properties. A validator client is the software that acts on behalf of the validator by holding and using its private key. A single validator client can hold many key pairs, controlling many validators. + + + + +Yes, modern validator accounts are capable of holding up to 2048 ETH. Additional ETH over 32 will compound in a step-wise manner, increasing in whole-number increments as your true balance increases. This is known as your effective balance. + +To increase the effective balance of an account, and thus increase rewards, a buffer of 0.25 ETH above any full-ETH threshold must be crossed. For example, an account with a true balance of 32.9 and an effective balance of 32 would need to earn another 0.35 ETH to bring it's true balance above 33.25 before triggering an increase in effective balance. + +This buffer prevents also prevents an effective balance from dropping until it has gone 0.25 ETH below it's current effective balance. + +Each key-pair associated with a validator requires at least 32 ETH to be activated. Any balance above this may be withdrawn to the associated withdrawal address at any time via a transaction signed by this address. Any funds over the maximum effective balance will automatically be withdrawn on a periodic basis. + +If home staking seems too demanding for you, consider using a staking-as-a-service provider, or if you're working with less than 32 ETH, check out the staking pools. + + + +Going offline when the network is finalizing properly will NOT result in slashing. Small inactivity penalties are incurred if your validator is not available to attest for a given epoch (each 6.4 minutes long), but this is very different to slashing. These penalties are slightly less than the reward you would have earned had the validator been available to attest, and losses can be earned back with approximately an equal amount of time back online again. + +Note that penalties for inactivity are proportional to how many validators are offline at the same time. In cases where a large portion of the network is all offline at once, the penalties for each of these validators will be greater than when a single validator is unavailable. + +In extreme cases if the network stops finalizing as a result of more than a third of the validators being offline, these users will suffer what is known as a quadratic inactivity leak, which is an exponential drain of ETH from offline validator accounts. This enables the network to eventually self-heal by burning the ETH of inactive validators until their balance reaches 16 ETH, at which point they will be automatically ejected from the validator pool. The remaining online validators will eventually comprise over 2/3 the network again, satisfying the supermajority needed to once again finalize the chain. + + + +In short, this can never be fully guaranteed, but if you act in good faith, run a minority client and only keep your signing keys on one machine at a time, the risk of getting slashed is nearly zero. + +There are only a few specific ways that can result in a validator getting slashed and ejected from the network. At time of writing, the slashings that have occurred have been exclusively a product of redundant hardware setups where signing keys are stored on two separate machines at once. This can inadvertently result in a double vote from your keys, which is a slashable offense. + +Running a supermajority client (any client used by over 2/3 the network) also holds the risk of potential slashing in the event this client has a bug that results in a chain fork. This can result in a faulty fork that gets finalized. To correct back to the intended chain would require submitting a surround vote by trying to undo a finalized block. This is also a slashable offense and can be avoided simply by running a minority client instead. + +Equivalent bugs in a minority client would never finalize and thus would never result in a surround vote, and would simply result in inactivity penalties, not slashing. + + + Learn more about the importance of running a minority client. + Learn more about slashing prevention + + + + +Individual clients may vary slightly in terms of performance and user interface, as each are developed by different teams using a variety of programming languages. That being said, none of them are "best." All production clients are excellent pieces of software, that all perform the same core functions to sync and interact with the blockchain. + +Since all production clients provide the same basic functionality, it is actually very important that you choose a minority client, meaning any client that is NOT currently being used by a majority of validators on the network. This may sound counterintuitive, but running a majority or supermajority client puts you at an increased risk of slashing in the event of a bug in that client. Running a minority client drastically limits these risks. + +Learn more about why client diversity is critical + + + +Although a virtual private server (VPS) can be used as a replacement to home hardware, the physical access and location of your validator client does matter. Centralized cloud solutions such as Amazon Web Services or Digital Ocean allow the convenience of not having to obtain and operate hardware, at the expense of centralizing the network. + +The more validator clients running on a single centralized cloud storage solution, the more dangerous it becomes for these users. Any event that takes these providers offline, whether by an attack, regulatory demands, or just power/internet outages, will result in every validator client that relies on this server to go offline at the same time. + +Offline penalties are proportional to how many others are offline at the same time. Using a VPS greatly increases the risk that offline penalties will be more severe, and increases your risk of quadratic leaking or slashing in the event the outage is large enough. To minimize your own risk, and the risk to the network, users are strongly encouraged to obtain and operate their own hardware. + + + + +Withdrawals of any kind from the Beacon Chain require withdrawal credentials to be set. + +New stakers set this at time of key generation and deposit. Existing stakers who did not already set this can upgrade their keys to support this functionality. + +Once withdrawal credentials are set, reward payments (accumulated ETH over the initial 32) will be periodically distributed to the withdrawal address automatically. + +To unlock and receive your entire balance back you must also complete the process of exiting your validator. + +More on staking withdrawals + + +## Further reading + +- [The Ethereum Staking Directory](https://www.staking.directory/) - _Eridian and Spacesider_ +- [Ethereum's Client Diversity Problem](https://hackernoon.com/ethereums-client-diversity-problem) - _@emmanuelawosika 2022_ +- [Helping Client Diversity](https://www.attestant.io/posts/helping-client-diversity/) - _Jim McDonald 2022_ +- [Client diversity on Ethereum's consensus layer](https://mirror.xyz/jmcook.eth/S7ONEka_0RgtKTZ3-dakPmAHQNPvuj15nh0YGKPFriA) - _jmcook.eth 2022_ +- [How To: Shop For Ethereum Validator Hardware](https://www.youtube.com/watch?v=C2wwu1IlhDc) - _EthStaker 2022_ +- [Step by Step: How to join the Ethereum 2.0 Testnet](https://kb.beaconcha.in/guides/tutorial-eth2-multiclient) - _Butta_ +- [Eth2 Slashing Prevention Tips](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) - _Raul Jordan 2020_ + +--- + +## Staking > Withdrawals + +**Staking withdrawals** refer to transfers of ETH from a validator account on Ethereum's consensus layer (the Beacon Chain), to the execution layer where it can be transacted with. + +**Reward payments of excess balance** over 32 ETH will automatically and regularly be sent to a withdrawal address linked to each validator, once provided by the user. Users can also **exit staking entirely**, unlocking their full validator balance. + +## Staking rewards + +Reward payments are automatically processed for active validator accounts with a maxed out effective balance of 32 ETH. + +Any balance above 32 ETH earned through rewards does not actually contribute to principal, or increase the weight of this validator on the network, and is thus automatically withdrawn as a reward payment every few days. Aside from providing a withdrawal address one time, these rewards do not require any action from the validator operator. This is all initiated on the consensus layer, thus no gas (transaction fee) is required at any step. + +### How did we get here? + +Over the past few years Ethereum has undergone several network upgrades transitioning to a network secured by ETH itself, instead of energy-intensive mining as it once was. Participating in consensus on Ethereum is now known as "staking", as participants have voluntarily locked up ETH, placing it "at stake" for the ability to participate in the network. Users who follow the rules will be rewarded, while attempts to cheat can be penalized. + +Since the launch of the staking deposit contract in November 2020, some brave Ethereum pioneers have voluntarily locked funds up to activate "validators", special accounts that have the right to formally attest to and propose blocks, following network rules. + +Before the Shanghai/Capella upgrade, you couldn't use or access your staked ETH. But now, you can opt-in to automatically receive your rewards into a chosen account, and you can also withdraw your staked ETH whenever you want. + +### How do I prepare? + + + +### Important notices + +Providing a withdrawal address is a required step for any validator account before it will be eligible to have ETH withdrawn from its balance. + + + Each validator account can only be assigned a single withdrawal address, one time. Once an address is chosen and submitted to the consensus layer, this cannot be undone or changed again. Double-check ownership and accuracy of the address provided before submitting. + + +There is no threat to your funds in the meantime for not providing this, assuming your mnemonic/seed phrase has remained safe offline, and has not been compromised in any way. Failure to add withdrawal credentials will simply leave the ETH locked in the validator account as it has been until a withdrawal address is provided. + +## Exiting staking entirely + +Providing a withdrawal address is required before _any_ funds can be transferred out of a validator account balance. + +Users looking to exit staking entirely and withdraw their full balance back must also sign and broadcast a "voluntary exit" message with validator keys which will start the process of exiting from staking. This is done with your validator client and submitted to your consensus node, and does not require gas. + +The process of a validator exiting from staking takes variable amounts of time, depending on how many others are exiting at the same time. Once complete, this account will no longer be responsible for performing validator network duties, is no longer eligible for rewards, and no longer has their ETH "at stake". At this time the account will be marked as fully “withdrawable”. + +Once an account is flagged as "withdrawable", and withdrawal credentials have been provided, there is nothing more a user needs to do aside from wait. Accounts are automatically and continuously swept by block proposers for eligible exited funds, and your account balance will be transferred in full (also known as a "full withdrawal") during the next sweep. + +## When were staking withdrawals enabled? + +Withdrawal functionality was enabled as part of the Shanghai/Capella upgrade which occurred on** April 12, 2023**. + +The Shanghai/Capella upgrade enabled previously staked ETH to be reclaimed into regular Ethereum accounts. This closed the loop on staking liquidity, and brought Ethereum one step closer on its journey towards building a sustainable, scalable, secure decentralized ecosystem. + +- [More on Ethereum history](/history/) +- [More on the Ethereum roadmap](/roadmap/) + +## How do withdrawal payments work? + +Whether a given validator is eligible for a withdrawal or not is determined by the state of the validator account itself. No user input is needed at any given time to determine whether an account should have a withdrawal initiated or not—the entire process is done automatically by the consensus layer on a continuous loop. + +### More of a visual learner? + +Check out this explanation of Ethereum staking withdrawals by Finematics: + + + +### Validator "sweeping" + +When a validator is scheduled to propose the next block, it is required to build a withdrawal queue, of up to 16 eligible withdrawals. This is done by originally starting with validator index 0, determining if there is an eligible withdrawal for this account per the rules of the protocol, and adding it to the queue if there is. The validator set to propose the following block will pick up where the last one left off, progressing in order indefinitely. + + +Think about an analogue clock. The hand on the clock points to the hour, progresses in one direction, doesn’t skip any hours, and eventually wraps around to the beginning again after the last number is reached. +Now instead of 1 through 12, imagine the clock has 0 through N (the total number of validator accounts that have ever been registered on the consensus layer, over 500,000 as of Jan 2023). +The hand on the clock points to the next validator that needs to be checked for eligible withdrawals. It starts at 0, and progresses all the way around without skipping any accounts. When the last validator is reached, the cycle continues back at the beginning. + + +#### Checking an account for withdrawals + +While a proposer is sweeping through validators for possible withdrawals, each validator being checked is evaluated against a short series of questions to determine if a withdrawal should be triggered, and if so, how much ETH should be withdrawn. + +1. **Has a withdrawal address been provided?** If no withdrawal address has been provided, the account is skipped and no withdrawal initiated. +2. **Is the validator exited and withdrawable?** If the validator has fully exited, and we have reached the epoch where their account is considered to be "withdrawable", then a full withdrawal will be processed. This will transfer the entire remaining balance to the withdrawal address. +3. **Is the effective balance maxed out at 32?** If the account has withdrawal credentials, is not fully exited, and has rewards above 32 waiting, a partial withdrawal will be processed which transfers only the rewards above 32 to the user's withdrawal address. + +There are only two actions that are taken by validator operators during the course of a validator's life cycle that influence this flow directly: + +- Provide withdrawal credentials to enable any form of withdrawal +- Exit from the network, which will trigger a full withdrawal + +### Gas free + +This approach to staking withdrawals avoids requiring stakers to manually submit a transaction requesting a particular amount of ETH to be withdrawn. This means there is **no gas (transaction fee) required**, and withdrawals also do not compete for existing execution layer block space. + +### How frequently will I get my staking rewards? + +A maximum of 16 withdrawals can be processed in a single block. At that rate, 115,200 validator withdrawals can be processed per day (assuming no missed slots). As noted above, validators without eligible withdrawals will be skipped, decreasing the time to finish the sweep. + +Expanding this calculation, we can estimate the time it will take to process a given number of withdrawals: + + + +| Number of withdrawals | Time to complete | +| :-------------------: | :--------------: | +| 400,000 | 3.5 days | +| 500,000 | 4.3 days | +| 600,000 | 5.2 days | +| 700,000 | 6.1 days | +| 800,000 | 7.0 days | + + + +As you see this slows down as more validators are on the network. An increase in missed slots could slow this down proportionally, but this will generally represent the slower side of possible outcomes. + +## Frequently asked questions + + +No, the process to provide withdrawal credentials is a one-time process, and cannot be changed once submitted. + + + +By setting an execution layer withdrawal address the withdrawal credentials for that validator have permanently been changed. This means the old credentials will no longer work, and the new credentials direct to an execution layer account. + +Withdrawal addresses can be either a smart contract (controlled by its code), or an externally owned account (EOA, controlled by its private key). Currently these accounts have no way to communicate a message back to the consensus layer that would signal a change of validator credentials, and adding this functionality would add unnecessary complexity to the protocol. + +As an alternative to changing the withdrawal address for a particular validator, users may choose to set a smart contract as their withdrawal address which could handle key rotating, such as a Safe. Users who set their funds to their own EOA can perform a full exit to withdraw all of their staked funds, and then re-stake using new credentials. + + + + +If you are part of a staking pool or hold staking tokens, you should check with your provider for more details about how staking withdrawals are handled, as each service operates differently. + +In general, users should be free to reclaim their underlying staked ETH, or change which staking provider they utilize. If a particular pool is getting too large, funds can be exited, redeemed, and re-staked with a smaller provider. Or, if you’ve accumulated enough ETH you could stake from home. + + + + +Yes, as long as your validator has provided a withdrawal address. This must be provided once to initially enable any withdrawals, then reward payments will be automatically triggered every few days with each validator sweep. + + + + +No, if your validator is still active on the network, a full withdrawal will not happen automatically. This requires manually initiating a voluntary exit. + +Once a validator has completed the exiting process, and assuming the account has withdrawal credentials, the remaining balance will then be withdrawn during the next validator sweep. + + + + +Withdrawals are designed to be pushed automatically, transferring any ETH that is not actively contributing to stake. This includes full balances for accounts that have completed the exiting process. + +It is not possible to manually request specific amounts of ETH to be withdrawn. + + + + +Validator operators are recommended to visit the Staking Launchpad Withdrawals page where you'll find more details about how to prepare your validator for withdrawals, timing of events, and more details about how withdrawals function. + +To try out your setup on a testnet first, visit the Holesky Testnet Staking Launchpad to get started. + + + + +No. Once a validator has exited and its full balance has been withdrawn, any additional funds deposited to that validator will automatically be transferred to the withdrawal address during the next validator sweep. To re-stake ETH, a new validator must be activated. + + +## Further reading + +- [Staking Launchpad Withdrawals](https://launchpad.ethereum.org/withdrawals) +- [EIP-4895: Beacon chain push withdrawals as operations](https://eips.ethereum.org/EIPS/eip-4895) +- [Ethereum Cat Herders - Shanghai](https://www.ethereumcatherders.com/shanghai_upgrade/index.html) +- [PEEPanEIP #94: Staked ETH Withdrawal (Testing) with Potuz & Hsiao-Wei Wang](https://www.youtube.com/watch?v=G8UstwmGtyE) +- [PEEPanEIP#68: EIP-4895: Beacon chain push withdrawals as operations with Alex Stokes](https://www.youtube.com/watch?v=CcL9RJBljUs) +- [Understanding Validator Effective Balance](https://www.attestant.io/posts/understanding-validator-effective-balance/) + +--- + +# Terms Of Use + +## Terms Of Use + +# Terms of Use + +**PLEASE READ THESE TERMS OF USE BEFORE USING THE WEBSITES.** + +**Acceptance of the Terms of Use** + +These terms of use are entered into by and between you and Stiftung Ethereum (the “Foundation”, “we”, or “us”). The following terms and conditions, together with any documents they expressly incorporate by reference (collectively, these “Terms of Use”), govern your access to and use of any website published by the Foundation, including, but not limited to, any content, functionality, and services offered on or through ethereum.org, ethereum.foundation, esp.ethereum.foundation, devcon.org, devconnect.org, and blog.ethereum.org (the “Websites”). + +Please read the Terms of Use carefully before you start to use the Websites. By using the Websites or by clicking to accept or agree to the Terms of Use when this option is made available to you, you accept and agree to be bound and abide by these Terms of Use in addition to: + +- our [Privacy Policy](/privacy-policy/), incorporated herein by + reference; and +- our [Cookie Policy](/cookie-policy/), incorporated herein by + reference. + +If you do not agree to these Terms of Use, you must not access or use the Websites. + +**Who May Use the Websites** + +The Websites are offered and available to users who are 13 years of age or older. The Websites are not intended for children under 13 years of age. By using the Websites, you represent and warrant that you (i) are 13 years of age or older, (ii) are not barred to use the Websites under any applicable law, and (iii) are using the Websites only for your own personal use. If you do not meet these requirements, you must not access or use the Websites. + +**Changes to the Terms of Use** + +We may revise and update these Terms of Use from time to time in our sole discretion. All changes are effective immediately when we post them. + +Your continued use of the Websites following the posting of revised Terms of Use means that you accept and agree to the changes. You are expected to check this page frequently so you are aware of any changes, as they are binding on you. + +**Accessing the Websites and Account Security** + +We reserve the right to withdraw or amend the Websites, and any service or material we provide on the Websites, in our sole discretion without notice. We do not guarantee that our Websites or any content on them will always be available or not be interrupted. We will not be liable if for any reason all or any part of the Websites are unavailable at any time or for any period. From time to time, we may restrict access to some parts of the Websites, or entire Websites, to users. + +You are responsible for: + +- Making all arrangements necessary for you to have access to the Websites; and +- Ensuring that all persons who access the Websites through your internet connection are aware of these Terms of Use and comply with them. + +To access the Websites or some of the resources it offers, you may be asked to provide certain registration details or other information. It is a condition of your use of the Websites that all the information you provide on the Websites is correct, current, and complete. You agree that all information you provide to use the Websites, including, but not limited to, using any interactive features on the Websites, is governed by our Privacy Policy, and you consent to all actions we may take with respect to your information that are consistent with our Privacy Policy. + +You should use particular caution when inputting personal information onto the Websites on a public or shared computer so that others are not able to view or record your personal information. + +**Intellectual Property Rights** + +The Websites and their entire contents, features, and functionality (including but not limited to all information, software, text, displays, images, video and audio, and the design, selection, and arrangement thereof), are owned by the Foundation, its licensors or other providers of such material and are protected by copyright, trademark, patent, trade secret, and other intellectual property or proprietary rights laws. + +Unless otherwise marked, (a) all material, data, and information on the Websites, such as data files, text, music, audio files or other sounds, photographs, videos, or other images, but excluding any software or computer code (collectively, the “Non-Code Content”) are licensed under the Creative Commons Attribution 4.0 International License; and (b) all software or computer code (collectively, the “Code Content”) are licensed under the MIT License. + +**Trademarks** + +The Foundation name, the terms Ethereum Switzerland, Ethereum Asia, the Foundation logo and all related names, logos, product and service names, designs and slogans are trademarks of the Foundation or its affiliates or licensors. You must not use such marks without the prior written permission of the Foundation. All other names, logos, product and service names, designs and slogans on this Websites are the trademarks of their respective owners. + +**Prohibited Uses** + +You may use the Websites only for lawful purposes and in accordance with these Terms of Use. You agree not to use the Websites: + +- In any way that violates any applicable federal, state, local, or international law or regulation (including, without limitation, any laws regarding the export of data or software to and from the US or other countries); +- For the purpose of exploiting, harming, or attempting to exploit or harm minors in any way by exposing them to inappropriate content, asking for personally identifiable information or otherwise; +- To send, knowingly receive, upload, download, use, or re-use any material which does not comply with these Terms of Use; +- To transmit, or procure the sending of, any advertising or promotional material without our prior written consent, including any “junk mail”, “chain letter”, “spam”, or any other similar solicitation; +- To impersonate or attempt to impersonate the Foundation, a Foundation employee, another user, or any other person or entity (including, without limitation, by using e-mail addresses or screen names associated with any of the foregoing); and +- To engage in any other conduct that restricts or inhibits anyone's use or enjoyment of the Websites, or which, as determined by us, may harm the Foundation or users of the Websites or expose them to liability. + +Additionally, you agree not to: + +- Use the Websites in any manner that could disable, overburden, damage, or impair the Websites or interfere with any other party’s use of the Websites, including their ability to engage in real time activities through the Websites; +- Use any robot, spider, or other automatic device, process or means to access the Websites for any purpose, including monitoring or copying any of the material on the Websites; +- Use any manual process to monitor or copy any of the material on the Websites or for any other unauthorized purpose without our prior written consent; +- Use any device, software or routine that interferes with the proper working of the Websites; +- Introduce any viruses, trojan horses, worms, logic bombs, or other material which is malicious or technologically harmful; +- Attempt to gain unauthorized access to, interfere with, damage, or disrupt any parts of the Websites, the server(s) on which the Websites is stored, or any server, computer or database connected to the Websites; +- Attack the Websites via a denial-of-service attack or a distributed denial-of-service attack; and +- Otherwise attempt to interfere with the proper working of the Websites. + +**Reliance on Information Posted** + +The information presented on or through the Websites is made available solely for general information purposes. We do not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. We disclaim all liability and responsibility arising from any reliance placed on such materials by you or any other visitor to the Websites, or by anyone who may be informed of any of its contents. + +The Websites may include content provided by third parties, including materials provided by other users, bloggers and third-party licensors, syndicators, aggregators, and/or reporting services. All statements and/or opinions expressed in these materials, and all articles and responses to questions and other content, other than the content provided by the Foundation, are solely the opinions and the responsibility of the person or entity providing those materials. These materials do not necessarily reflect the opinion of the Foundation. We are not responsible, or liable to you or any third party, for the content or accuracy of any materials provided by any third parties. + +**Changes to the Websites** + +We may update the content on the Websites from time to time, but its content is not necessarily complete or up-to-date. Any of the material on the Websites may be out of date at any given time, and we are under no obligation to update such material. + +**Information About You and Your Visits to the Websites** + +All information we collect on the Websites is subject to our [Privacy +Policy](/privacy-policy/). By using the Websites, you consent to all actions that may be taken by us with respect to your information in compliance with the Privacy Policy. + +**Online Purchases and Other Terms and Conditions** + +Additional terms and conditions may also apply to specific portions, services or features of the Websites, including the registration and sponsorship for conference events. All such additional terms and conditions are hereby incorporated by this reference into these Terms of Use. In the event of terms that are directly conflicting between these Terms of Use and terms of conditions for the registration or sponsorship of a conference event, the terms and conditions for the event shall control. + +**Linking to the Websites and Social Media Features** + +You may link to our homepage, provided you do so in a way that is fair and legal and does not damage our reputation or take advantage of it, but you must not establish a link in such a way as to suggest any form of association, approval or endorsement on our part without our express written consent. + +**Links from the Websites** + +If the Websites contain links to other sites and resources provided by third parties, these links are provided for your convenience only. This includes links contained in advertisements, including banner advertisements and sponsored links. We have no control over the contents of those sites or resources, and accept no responsibility for them or for any loss or damage that may arise from your use of them. If you decide to access any of the third party websites linked to the Websites, you do so entirely at your own risk and subject to the terms and conditions of use for such websites. We reserve the right to withdraw linking permission without notice. + +**Geographic Restrictions** + +The owner of the Websites is based in Switzerland. We make no claims that the Websites or any of its content is accessible or appropriate outside of Switzerland. Access to the Websites may not be legal by certain persons or in certain countries. If you access the Websites from outside Switzerland, you do so on your own initiative and are responsible for compliance with local laws. + +**Disclaimer of Warranties** + +You understand that we cannot and do not guarantee or warrant that files available for downloading from the internet or the Websites will be free of viruses or other destructive code. You are responsible for implementing sufficient procedures and checkpoints to satisfy your particular requirements for anti-virus protection and accuracy of data input and output, and for maintaining a means external to our site for any reconstruction of any lost data. WE WILL NOT BE LIABLE FOR ANY LOSS OR DAMAGE CAUSED BY A DISTRIBUTED DENIAL-OF-SERVICE ATTACK, VIRUSES, OR OTHER TECHNOLOGICALLY HARMFUL MATERIAL THAT MAY INFECT YOUR COMPUTER EQUIPMENT, COMPUTER PROGRAMS, DATA, OR OTHER PROPRIETARY MATERIAL DUE TO YOUR USE OF THE WEBSITES OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES OR TO YOUR DOWNLOADING OF ANY MATERIAL POSTED ON IT, OR ON ANY WEBSITES LINKED TO IT. + +YOUR USE OF THE WEBSITES, THEIR CONTENT AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES IS AT YOUR OWN RISK. THE WEBSITES, THEIR CONTENT AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, WITHOUT ANY WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. NEITHER THE FOUNDATION NOR ANY PERSON ASSOCIATED WITH THE FOUNDATION MAKES ANY WARRANTY OR REPRESENTATION WITH RESPECT TO THE COMPLETENESS, SECURITY, RELIABILITY, QUALITY, ACCURACY, OR AVAILABILITY OF THE WEBSITES. WITHOUT LIMITING THE FOREGOING, NEITHER THE FOUNDATION NOR ANYONE ASSOCIATED WITH THE FOUNDATION REPRESENTS OR WARRANTS THAT THE WEBSITES, THEIR CONTENT OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES WILL BE ACCURATE, RELIABLE, ERROR-FREE OR UNINTERRUPTED, THAT DEFECTS WILL BE CORRECTED, THAT THE WEBSITES OR THE SERVER(S) THAT MAKES THEM AVAILABLE ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS OR THAT THE WEBSITES OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES WILL OTHERWISE MEET YOUR NEEDS OR EXPECTATIONS. + +THE FOUNDATION HEREBY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, STATUTORY, OR OTHERWISE, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND FITNESS FOR PARTICULAR PURPOSE. + +SOME JURISDICTIONS DO NOT ALLOW EXCLUSION OF WARRANTIES OR LIMITATIONS ON THE DURATION OF IMPLIED WARRANTIES, SO THE ABOVE DISCLAIMER MAY NOT APPLY TO YOU IN THEIR ENTIRETIES, BUT WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW. + +**Limitation on Liability** + +IN NO EVENT WILL THE FOUNDATION, ITS AFFILIATES OR THEIR LICENSORS, SERVICE PROVIDERS, EMPLOYEES, AGENTS, OFFICERS, OR DIRECTORS BE LIABLE FOR DAMAGES OF ANY KIND, UNDER ANY LEGAL THEORY, ARISING OUT OF OR IN CONNECTION WITH YOUR USE, OR INABILITY TO USE, THE WEBSITES, ANY WEBSITES LINKED TO THEM, ANY CONTENT ON THE WEBSITES OR SUCH OTHER WEBSITES OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE WEBSITES OR SUCH OTHER WEBSITES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO, PERSONAL INJURY, PAIN AND SUFFERING, EMOTIONAL DISTRESS, LOSS OF REVENUE, LOSS OF PROFITS, LOSS OF BUSINESS OR ANTICIPATED SAVINGS, LOSS OF USE, LOSS OF GOODWILL, LOSS OF DATA, AND WHETHER CAUSED BY TORT (INCLUDING NEGLIGENCE), BREACH OF CONTRACT OR OTHERWISE, EVEN IF FORESEEABLE. THE FOREGOING DOES NOT AFFECT ANY LIABILITY WHICH CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW WHICH MAY INCLUDE FRAUD. + +**Indemnification** + +You agree to defend, indemnify, and hold harmless the Foundation, its affiliates, licensors, and service providers, and its and their respective officers, directors, employees, contractors, agents, licensors, suppliers, successors, and assigns from and against any claims, liabilities, damages, judgments, awards, losses, costs, expenses, or fees (including reasonable attorneys’ fees) arising out of or relating to your violation of these Terms of Use or your use of the Websites, including, but not limited to, any use of the Websites’ content, services and products other than as expressly authorized in these Terms of Use or your use of any information obtained from the Websites. + +**Governing Law and Jurisdiction** + +All matters relating to the Websites and these Terms of Use and any dispute or claim arising therefrom or related thereto (in each case, including non-contractual disputes or claims), shall be governed by and construed in accordance with the internal laws of Switzerland without giving effect to any choice or conflict of law provision or rule (whether of Switzerland or any other jurisdiction). + +Any legal suit, action or proceeding arising out of, or related to, these Terms of Use or the Websites shall be instituted exclusively in the Switzerland in the Kanton of Zug although we retain the right to bring any suit, action or proceeding against you for breach of these Terms of Use in your country of residence or any other relevant country. You waive any and all objections to the exercise of jurisdiction over you by such courts and to venue in such courts. + +**Waiver and Severability** + +No waiver by the Foundation of any term or condition set forth in these Terms of Use shall be deemed a further or continuing waiver of such term or condition or a waiver of any other term or condition, and any failure of the Foundation to assert a right or provision under these Terms of Use shall not constitute a waiver of such right or provision. + +If any provision of these Terms of Use is held by a court or other tribunal of competent jurisdiction to be invalid, illegal, or unenforceable for any reason, such provision shall be eliminated or limited to the minimum extent such that the remaining provisions of the Terms of Use will continue in full force and effect. + +**Entire Agreement** + +The Terms of Use, our Privacy Policy and terms of conditions for the registration of events constitute the sole and entire agreement between you and the Foundation with respect to the Websites and supersede all prior and contemporaneous understandings, agreements, representations and warranties, both written and oral, with respect to the Websites. + +**Your Comments and Concerns** + +The Websites are operated by the Foundation. All other feedback, comments, requests for technical support and other communications relating to the Websites should be directed to: [support@ethereum.org](mailto:support@ethereum.org). + +--- + +# Web3 + +## Web3 + +# Introduction to Web3 + + + + + +Centralization has helped onboard billions of people to the World Wide Web and created the stable, robust infrastructure on which it lives. At the same time, a handful of centralized entities have a stronghold on large swathes of the World Wide Web, unilaterally deciding what should and should not be allowed. + +Web3 is the answer to this dilemma. Instead of a Web monopolized by large technology companies, Web3 embraces decentralization and is being built, operated, and owned by its users. Web3 puts power in the hands of individuals rather than corporations. +Before we talk about Web3, let's explore how we got here. + + + +## The early Web + +Most people think of the Web as a continuous pillar of modern life—it was invented and has just existed since. However, the Web most of us know today is quite different from originally imagined. To understand this better, it's helpful to break the Web's short history into loose periods—Web 1.0 and Web 2.0. + +### Web 1.0: Read-Only (1990-2004) + +In 1989, at CERN, Geneva, Tim Berners-Lee was busy developing the protocols that would become the World Wide Web. His idea? To create open, decentralized protocols that allowed information-sharing from anywhere on Earth. + +The first inception of Berners-Lee's creation, now known as 'Web 1.0', occurred roughly between 1990 to 2004. Web 1.0 was mainly static websites owned by companies, and there was close to zero interaction between users - individuals seldom produced content - leading to it being known as the read-only web. + +![Client-server architecture, representing Web 1.0](./web1.png) + +### Web 2.0: Read-Write (2004-now) + +The Web 2.0 period began in 2004 with the emergence of social media platforms. Instead of a read-only, the web evolved to be read-write. Instead of companies providing content to users, they also began to provide platforms to share user-generated content and engage in user-to-user interactions. As more people came online, a handful of top companies began to control a disproportionate amount of the traffic and value generated on the web. Web 2.0 also birthed the advertising-driven revenue model. While users could create content, they didn't own it or benefit from its monetization. + +![Client-server architecture, representing Web 2.0](./web2.png) + + + +## Web 3.0: Read-Write-Own + +The premise of 'Web 3.0' was coined by [Ethereum](/what-is-ethereum/) co-founder Gavin Wood shortly after Ethereum launched in 2014. Gavin put into words a solution for a problem that many early crypto adopters felt: the Web required too much trust. That is, most of the Web that people know and use today relies on trusting a handful of private companies to act in the public's best interests. + +![Decentralized node architecture, representing Web3](./web3.png) + +### What is Web3? + +Web3 has become a catch-all term for the vision of a new, better internet. At its core, Web3 uses blockchains, cryptocurrencies, and NFTs to give power back to the users in the form of ownership. [A 2020 post on Twitter](https://twitter.com/himgajria/status/1266415636789334016) said it best: Web1 was read-only, Web2 is read-write, Web3 will be read-write-own. + +#### Core ideas of Web3 + +Although it's challenging to provide a rigid definition of what Web3 is, a few core principles guide its creation. + +- **Web3 is decentralized:** instead of large swathes of the internet controlled and owned by centralized entities, ownership gets distributed amongst its builders and users. +- **Web3 is permissionless:** everyone has equal access to participate in Web3, and no one gets excluded. +- **Web3 has native payments:** it uses cryptocurrency for spending and sending money online instead of relying on the outdated infrastructure of banks and payment processors. +- **Web3 is trustless:** it operates using incentives and economic mechanisms instead of relying on trusted third-parties. + +### Why is Web3 important? + +Although Web3's killer features aren't isolated and don't fit into neat categories, for simplicity we've tried to separate them to make them easier to understand. + +#### Ownership + +Web3 gives you ownership of your digital assets in an unprecedented way. For example, say you're playing a web2 game. If you purchase an in-game item, it is tied directly to your account. If the game creators delete your account, you will lose these items. Or, if you stop playing the game, you lose the value you invested into your in-game items. + +Web3 allows for direct ownership through [non-fungible tokens (NFTs)](/glossary/#nft). No one, not even the game's creators, has the power to take away your ownership. And, if you stop playing, you can sell or trade your in-game items on open markets and recoup their value. + + + Learn more about NFTs + + More on NFTs + + + +#### Censorship resistance + +The power dynamic between platforms and content creators is massively imbalanced. + +OnlyFans is a user-generated adult content site with over 1-million content creators, many of which use the platform as their primary source of income. In August 2021, OnlyFans announced plans to ban sexually explicit content. The announcement sparked outrage amongst creators on the platform, who felt they were getting robbed of an income on a platform they helped create. After the backlash, the decision got quickly reversed. Despite the creators winning this battle, it highlights a problem for Web 2.0 creators: you lose the reputation and following you accrued if you leave a platform. + +On Web3, your data lives on the blockchain. When you decide to leave a platform, you can take your reputation with you, plugging it into another interface that more clearly aligns with your values. + +Web 2.0 requires content creators to trust platforms not to change the rules, but censorship resistance is a native feature of a Web3 platform. + +#### Decentralized autonomous organizations (DAOs) + +As well as owning your data in Web3, you can own the platform as a collective, using tokens that act like shares in a company. DAOs let you coordinate decentralized ownership of a platform and make decisions about its future. + +DAOs are defined technically as agreed-upon [smart contracts](/glossary/#smart-contract) that automate decentralized decision-making over a pool of resources (tokens). Users with tokens vote on how resources get spent, and the code automatically performs the voting outcome. + +However, people define many Web3 communities as DAOs. These communities all have different levels of decentralization and automation by code. Currently, we are exploring what DAOs are and how they might evolve in the future. + + + Learn more about DAOs + + More on DAOs + + + +### Identity + +Traditionally, you would create an account for every platform you use. For example, you might have a Twitter account, a YouTube account, and a Reddit account. Want to change your display name or profile picture? You have to do it across every account. You can use social sign-ins in some cases, but this presents a familiar problem—censorship. In a single click, these platforms can lock you out of your entire online life. Even worse, many platforms require you to trust them with personally identifiable information to create an account. + +Web3 solves these problems by allowing you to control your digital identity with an Ethereum address and [Ethereum Name Service (ENS)](/glossary/#ens) profile. Using an Ethereum address provides a single login across platforms that is secure, censorship-resistant, and anonymous. + +### Native payments + +Web2's payment infrastructure relies on banks and payment processors, excluding people without bank accounts or those who happen to live within the borders of the wrong country. +Web3 uses tokens like [ETH](/glossary/#ether) to send money directly in the browser and requires no trusted third party. + + + More on ETH + + +## Web3 limitations + +Despite the numerous benefits of Web3 in its current form, there are still many limitations that the ecosystem must address for it to flourish. + +### Accessibility + +Important Web3 features, like Sign-in with Ethereum, are already available for anyone to use at zero cost. But, the relative cost of transactions is still prohibitive to many. Web3 is less likely to be utilized in less-wealthy, developing nations due to high transaction fees. On Ethereum, these challenges are being solved through [the roadmap](/roadmap/) and [layer 2 scaling solutions](/glossary/#layer-2). The technology is ready, but we need higher levels of adoption on layer 2 to make Web3 accessible to everyone. + +### User experience + +The technical barrier to entry to using Web3 is currently too high. Users must comprehend security concerns, understand complex technical documentation, and navigate unintuitive user interfaces. [Wallet providers](/wallets/find-wallet/), in particular, are working to solve this, but more progress is needed before Web3 gets adopted en masse. + +### Education + +Web3 introduces new paradigms that require learning different mental models than the ones used in Web2.0. A similar education drive happened as Web1.0 was gaining popularity in the late 1990s; proponents of the world wide web used a slew of educational techniques to educate the public from simple metaphors (the information highway, browsers, surfing the web) to [television broadcasts](https://www.youtube.com/watch?v=SzQLI7BxfYI). Web3 isn't difficult, but it is different. Educational initiatives informing Web2 users of these Web3 paradigms are vital for its success. + +Ethereum.org contributes to Web3 education through our [Translation Program](/contributing/translation-program/), aiming to translate important Ethereum content to as many languages as possible. + +### Centralized infrastructure + +The Web3 ecosystem is young and quickly evolving. As a result, it currently depends mainly on centralized infrastructure (GitHub, Twitter, Discord, etc.). Many Web3 companies are rushing to fill these gaps, but building high-quality, reliable infrastructure takes time. + +## A decentralized future + +Web3 is a young and evolving ecosystem. Gavin Wood coined the term in 2014, but many of these ideas have only recently become a reality. In the last year alone, there has been a considerable surge in the interest in cryptocurrency, improvements to layer 2 scaling solutions, massive experiments with new forms of governance, and revolutions in digital identity. + +We are only at the beginning of creating a better Web with Web3, but as we continue to improve the infrastructure that will support it, the future of the Web looks bright. + +## How can I get involved + +- [Get a wallet](/wallets/) +- [Find a community](/community/) +- [Explore Web3 applications](/dapps/) +- [Join a DAO](/dao/) +- [Build on Web3](/developers/) + +## Further reading + +Web3 isn’t rigidly defined. Various community participants have different perspectives on it. Here are a few of them: + +- [What is Web3? The Decentralized Internet of the Future Explained](https://www.freecodecamp.org/news/what-is-web3) – _Nader Dabit_ +- [Making Sense of Web 3](https://medium.com/l4-media/making-sense-of-web-3-c1a9e74dcae) – _Josh Stark_ +- [Why Web3 Matters](https://future.a16z.com/why-web3-matters/) — _Chris Dixon_ +- [Why Decentralization Matters](https://onezero.medium.com/why-decentralization-matters-5e3f79f7638e) - _Chris Dixon_ +- [The Web3 Landscape](https://a16z.com/wp-content/uploads/2021/10/The-web3-Readlng-List.pdf) – _a16z_ +- [The Web3 Debate](https://www.notboring.co/p/the-web3-debate) – _Packy McCormick_ + +--- + +# Whitepaper + +## Whitepaper + +# Ethereum Whitepaper + +_This introductory paper was originally published in 2014 by Vitalik Buterin, the founder of [Ethereum](/what-is-ethereum/), before the project's launch in 2015. It's worth noting that Ethereum, like many community-driven, open-source software projects, has evolved since its initial inception._ + +_While several years old, we maintain this paper because it continues to serve as a useful reference and an accurate representation of Ethereum and its vision. To learn about the latest developments of Ethereum, and how changes to the protocol are made, we recommend [this guide](/learn/)._ + +[Researchers and academics seeking a historical or canonical version of the whitepaper [from December 2014] should use this PDF.](./whitepaper-pdf/Ethereum_Whitepaper_-_Buterin_2014.pdf) + +## A Next-Generation Smart Contract and Decentralized Application Platform + +Satoshi Nakamoto's development of Bitcoin in 2009 has often been hailed as a radical development in money and currency, being the first example of a digital asset which simultaneously has no backing or "[intrinsic value](http://bitcoinmagazine.com/8640/an-exploration-of-intrinsic-value-what-it-is-why-bitcoin-doesnt-have-it-and-why-bitcoin-does-have-it/)" and no centralized issuer or controller. However, another, arguably more important, part of the Bitcoin experiment is the underlying blockchain technology as a tool of distributed consensus, and attention is rapidly starting to shift to this other aspect of Bitcoin. Commonly cited alternative applications of blockchain technology include using on-blockchain digital assets to represent custom currencies and financial instruments ("[colored coins](https://docs.google.com/a/buterin.com/document/d/1AnkP_cVZTCMLIzw4DvsW6M8Q2JC0lIzrTLuoWu2z1BE/edit)"), the ownership of an underlying physical device ("[smart property](https://en.bitcoin.it/wiki/Smart_Property)"), non-fungible assets such as domain names ("[Namecoin](http://namecoin.org)"), as well as more complex applications involving having digital assets being directly controlled by a piece of code implementing arbitrary rules ("[smart contracts](http://www.fon.hum.uva.nl/rob/Courses/InformationInSpeech/CDROM/Literature/LOTwinterschool2006/szabo.best.vwh.net/idea.html)") or even blockchain-based "[decentralized autonomous organizations](http://bitcoinmagazine.com/7050/bootstrapping-a-decentralized-autonomous-corporation-part-i/)" (DAOs). What Ethereum intends to provide is a blockchain with a built-in fully fledged Turing-complete programming language that can be used to create "contracts" that can be used to encode arbitrary state transition functions, allowing users to create any of the systems described above, as well as many others that we have not yet imagined, simply by writing up the logic in a few lines of code. + +## Introduction to Bitcoin and Existing Concepts + +### History + +The concept of decentralized digital currency, as well as alternative applications like property registries, has been around for decades. The anonymous e-cash protocols of the 1980s and the 1990s, mostly reliant on a cryptographic primitive known as Chaumian blinding, provided a currency with a high degree of privacy, but the protocols largely failed to gain traction because of their reliance on a centralized intermediary. In 1998, Wei Dai's [b-money](http://www.weidai.com/bmoney.txt) became the first proposal to introduce the idea of creating money through solving computational puzzles as well as decentralized consensus, but the proposal was scant on details as to how decentralized consensus could actually be implemented. In 2005, Hal Finney introduced a concept of "[reusable proofs of work](https://nakamotoinstitute.org/finney/rpow/)", a system which uses ideas from b-money together with Adam Back's computationally difficult Hashcash puzzles to create a concept for a cryptocurrency, but once again fell short of the ideal by relying on trusted computing as a backend. In 2009, a decentralized currency was for the first time implemented in practice by Satoshi Nakamoto, combining established primitives for managing ownership through public key cryptography with a consensus algorithm for keeping track of who owns coins, known as "proof-of-work". + +The mechanism behind proof-of-work was a breakthrough in the space because it simultaneously solved two problems. First, it provided a simple and moderately effective consensus algorithm, allowing nodes in the network to collectively agree on a set of canonical updates to the state of the Bitcoin ledger. Second, it provided a mechanism for allowing free entry into the consensus process, solving the political problem of deciding who gets to influence the consensus, while simultaneously preventing sybil attacks. It does this by substituting a formal barrier to participation, such as the requirement to be registered as a unique entity on a particular list, with an economic barrier - the weight of a single node in the consensus voting process is directly proportional to the computing power that the node brings. Since then, an alternative approach has been proposed called _proof-of-stake_, calculating the weight of a node as being proportional to its currency holdings and not computational resources; the discussion of the relative merits of the two approaches is beyond the scope of this paper but it should be noted that both approaches can be used to serve as the backbone of a cryptocurrency. + +### Bitcoin As A State Transition System + +![Ethereum state transition](./ethereum-state-transition.png) + +From a technical standpoint, the ledger of a cryptocurrency such as Bitcoin can be thought of as a state transition system, where there is a "state" consisting of the ownership status of all existing bitcoins and a "state transition function" that takes a state and a transaction and outputs a new state which is the result. In a standard banking system, for example, the state is a balance sheet, a transaction is a request to move $X from A to B, and the state transition function reduces the value in A's account by $X and increases the value in B's account by $X. If A's account has less than $X in the first place, the state transition function returns an error. Hence, one can formally define: + +``` +APPLY(S,TX) -> S' or ERROR +``` + +In the banking system defined above: + +```js +APPLY(,"send $20 from Alice to Bob") = +``` + +But: + +```js +APPLY(,"send $70 from Alice to Bob") = ERROR +``` + +The "state" in Bitcoin is the collection of all coins (technically, "unspent transaction outputs" or UTXO) that have been minted and not yet spent, with each UTXO having a denomination and an owner (defined by a 20-byte address which is essentially a cryptographic public key[fn1](#notes)). A transaction contains one or more inputs, with each input containing a reference to an existing UTXO and a cryptographic signature produced by the private key associated with the owner's address, and one or more outputs, with each output containing a new UTXO to be added to the state. + +The state transition function `APPLY(S,TX) -> S'` can be defined roughly as follows: + + + + For each input in TX: + + + If the referenced UTXO is not in S, return an error. + + + If the provided signature does not match the owner of the UTXO, return an error. + + + + + If the sum of the denominations of all input UTXO is less than the sum of the denominations of all output UTXO, return an error. + + + Return S with all input UTXO removed and all output UTXO added. + + + +The first half of the first step prevents transaction senders from spending coins that do not exist, the second half of the first step prevents transaction senders from spending other people's coins, and the second step enforces conservation of value. In order to use this for payment, the protocol is as follows. Suppose Alice wants to send 11.7 BTC to Bob. First, Alice will look for a set of available UTXO that she owns that totals up to at least 11.7 BTC. Realistically, Alice will not be able to get exactly 11.7 BTC; say that the smallest she can get is 6+4+2=12. She then creates a transaction with those three inputs and two outputs. The first output will be 11.7 BTC with Bob's address as its owner, and the second output will be the remaining 0.3 BTC "change", with the owner being Alice herself. + +### Mining + +![Ethereum blocks](./ethereum-blocks.png) + +If we had access to a trustworthy centralized service, this system would be trivial to implement; it could simply be coded exactly as described, using a centralized server's hard drive to keep track of the state. However, with Bitcoin we are trying to build a decentralized currency system, so we will need to combine the state transaction system with a consensus system in order to ensure that everyone agrees on the order of transactions. Bitcoin's decentralized consensus process requires nodes in the network to continuously attempt to produce packages of transactions called "blocks". The network is intended to produce roughly one block every ten minutes, with each block containing a timestamp, a nonce, a reference to (ie. hash of) the previous block and a list of all of the transactions that have taken place since the previous block. Over time, this creates a persistent, ever-growing, "blockchain" that constantly updates to represent the latest state of the Bitcoin ledger. + +The algorithm for checking if a block is valid, expressed in this paradigm, is as follows: + +1. Check if the previous block referenced by the block exists and is valid. +2. Check that the timestamp of the block is greater than that of the previous block[fn2](#notes) and less than 2 hours into the future +3. Check that the proof-of-work on the block is valid. +4. Let `S[0]` be the state at the end of the previous block. +5. Suppose `TX` is the block's transaction list with `n` transactions. For all `i` in `0...n-1`, set `S[i+1] = APPLY(S[i],TX[i])` If any application returns an error, exit and return false. +6. Return true, and register `S[n]` as the state at the end of this block. + +Essentially, each transaction in the block must provide a valid state transition from what was the canonical state before the transaction was executed to some new state. Note that the state is not encoded in the block in any way; it is purely an abstraction to be remembered by the validating node and can only be (securely) computed for any block by starting from the genesis state and sequentially applying every transaction in every block. Additionally, note that the order in which the miner includes transactions into the block matters; if there are two transactions A and B in a block such that B spends a UTXO created by A, then the block will be valid if A comes before B but not otherwise. + +The one validity condition present in the above list that is not found in other systems is the requirement for "proof-of-work". The precise condition is that the double-SHA256 hash of every block, treated as a 256-bit number, must be less than a dynamically adjusted target, which as of the time of this writing is approximately 2187. The purpose of this is to make block creation computationally "hard", thereby preventing sybil attackers from remaking the entire blockchain in their favor. Because SHA256 is designed to be a completely unpredictable pseudo-random function, the only way to create a valid block is simply trial and error, repeatedly incrementing the nonce and seeing if the new hash matches. + +At the current target of ~2187, the network must make an average of ~269 tries before a valid block is found; in general, the target is recalibrated by the network every 2016 blocks so that on average a new block is produced by some node in the network every ten minutes. In order to compensate miners for this computational work, the miner of every block is entitled to include a transaction giving themselves 25 BTC out of nowhere. Additionally, if any transaction has a higher total denomination in its inputs than in its outputs, the difference also goes to the miner as a "transaction fee". Incidentally, this is also the only mechanism by which BTC are issued; the genesis state contained no coins at all. + +In order to better understand the purpose of mining, let us examine what happens in the event of a malicious attacker. Since Bitcoin's underlying cryptography is known to be secure, the attacker will target the one part of the Bitcoin system that is not protected by cryptography directly: the order of transactions. The attacker's strategy is simple: + +1. Send 100 BTC to a merchant in exchange for some product (preferably a rapid-delivery digital good) +2. Wait for the delivery of the product +3. Produce another transaction sending the same 100 BTC to himself +4. Try to convince the network that his transaction to himself was the one that came first. + +Once step (1) has taken place, after a few minutes some miner will include the transaction in a block, say block number 270000. After about one hour, five more blocks will have been added to the chain after that block, with each of those blocks indirectly pointing to the transaction and thus "confirming" it. At this point, the merchant will accept the payment as finalized and deliver the product; since we are assuming this is a digital good, delivery is instant. Now, the attacker creates another transaction sending the 100 BTC to himself. If the attacker simply releases it into the wild, the transaction will not be processed; miners will attempt to run `APPLY(S,TX)` and notice that `TX` consumes a UTXO which is no longer in the state. So instead, the attacker creates a "fork" of the blockchain, starting by mining another version of block 270000 pointing to the same block 269999 as a parent but with the new transaction in place of the old one. Because the block data is different, this requires redoing the proof-of-work. Furthermore, the attacker's new version of block 270000 has a different hash, so the original blocks 270001 to 270005 do not "point" to it; thus, the original chain and the attacker's new chain are completely separate. The rule is that in a fork the longest blockchain is taken to be the truth, and so legitimate miners will work on the 270005 chain while the attacker alone is working on the 270000 chain. In order for the attacker to make his blockchain the longest, he would need to have more computational power than the rest of the network combined in order to catch up (hence, "51% attack"). + +### Merkle Trees + +![SPV in Bitcoin](./spv-bitcoin.png) + +_Left: it suffices to present only a small number of nodes in a Merkle tree to give a proof of the validity of a branch._ + +_Right: any attempt to change any part of the Merkle tree will eventually lead to an inconsistency somewhere up the chain._ + +An important scalability feature of Bitcoin is that the block is stored in a multi-level data structure. The "hash" of a block is actually only the hash of the block header, a roughly 200-byte piece of data that contains the timestamp, nonce, previous block hash and the root hash of a data structure called the Merkle tree storing all transactions in the block. A Merkle tree is a type of binary tree, composed of a set of nodes with a large number of leaf nodes at the bottom of the tree containing the underlying data, a set of intermediate nodes where each node is the hash of its two children, and finally a single root node, also formed from the hash of its two children, representing the "top" of the tree. The purpose of the Merkle tree is to allow the data in a block to be delivered piecemeal: a node can download only the header of a block from one source, the small part of the tree relevant to them from another source, and still be assured that all of the data is correct. The reason why this works is that hashes propagate upward: if a malicious user attempts to swap in a fake transaction into the bottom of a Merkle tree, this change will cause a change in the node above, and then a change in the node above that, finally changing the root of the tree and therefore the hash of the block, causing the protocol to register it as a completely different block (almost certainly with an invalid proof-of-work). + +The Merkle tree protocol is arguably essential to long-term sustainability. A "full node" in the Bitcoin network, one that stores and processes the entirety of every block, takes up about 15 GB of disk space in the Bitcoin network as of April 2014, and is growing by over a gigabyte per month. Currently, this is viable for some desktop computers and not phones, and later on in the future only businesses and hobbyists will be able to participate. A protocol known as "simplified payment verification" (SPV) allows for another class of nodes to exist, called "light nodes", which download the block headers, verify the proof-of-work on the block headers, and then download only the "branches" associated with transactions that are relevant to them. This allows light nodes to determine with a strong guarantee of security what the status of any Bitcoin transaction, and their current balance, is while downloading only a very small portion of the entire blockchain. + +### Alternative Blockchain Applications + +The idea of taking the underlying blockchain idea and applying it to other concepts also has a long history. In 2005, Nick Szabo came out with the concept of "[secure property titles with owner authority](https://nakamotoinstitute.org/secure-property-titles/)", a document describing how "new advances in replicated database technology" will allow for a blockchain-based system for storing a registry of who owns what land, creating an elaborate framework including concepts such as homesteading, adverse possession and Georgian land tax. However, there was unfortunately no effective replicated database system available at the time, and so the protocol was never implemented in practice. After 2009, however, once Bitcoin's decentralized consensus was developed a number of alternative applications rapidly began to emerge. + +- **Namecoin** - created in 2010, [Namecoin](https://namecoin.org/) is best described as a decentralized name registration database. In decentralized protocols like Tor, Bitcoin and BitMessage, there needs to be some way of identifying accounts so that other people can interact with them, but in all existing solutions the only kind of identifier available is a pseudo-random hash like `1LW79wp5ZBqaHW1jL5TCiBCrhQYtHagUWy`. Ideally, one would like to be able to have an account with a name like "george". However, the problem is that if one person can create an account named "george" then someone else can use the same process to register "george" for themselves as well and impersonate them. The only solution is a first-to-file paradigm, where the first registerer succeeds and the second fails - a problem perfectly suited for the Bitcoin consensus protocol. Namecoin is the oldest, and most successful, implementation of a name registration system using such an idea. +- **Colored coins** - the purpose of [colored coins](https://docs.google.com/a/buterin.com/document/d/1AnkP_cVZTCMLIzw4DvsW6M8Q2JC0lIzrTLuoWu2z1BE/edit) is to serve as a protocol to allow people to create their own digital currencies - or, in the important trivial case of a currency with one unit, digital tokens, on the Bitcoin blockchain. In the colored coins protocol, one "issues" a new currency by publicly assigning a color to a specific Bitcoin UTXO, and the protocol recursively defines the color of other UTXO to be the same as the color of the inputs that the transaction creating them spent (some special rules apply in the case of mixed-color inputs). This allows users to maintain wallets containing only UTXO of a specific color and send them around much like regular bitcoins, backtracking through the blockchain to determine the color of any UTXO that they receive. +- **Metacoins** - the idea behind a metacoin is to have a protocol that lives on top of Bitcoin, using Bitcoin transactions to store metacoin transactions but having a different state transition function, `APPLY'`. Because the metacoin protocol cannot prevent invalid metacoin transactions from appearing in the Bitcoin blockchain, a rule is added that if `APPLY'(S,TX)` returns an error, the protocol defaults to `APPLY'(S,TX) = S`. This provides an easy mechanism for creating an arbitrary cryptocurrency protocol, potentially with advanced features that cannot be implemented inside of Bitcoin itself, but with a very low development cost since the complexities of mining and networking are already handled by the Bitcoin protocol. Metacoins have been used to implement some classes of financial contracts, name registration and decentralized exchange. + +Thus, in general, there are two approaches toward building a consensus protocol: building an independent network, and building a protocol on top of Bitcoin. The former approach, while reasonably successful in the case of applications like Namecoin, is difficult to implement; each individual implementation needs to bootstrap an independent blockchain, as well as building and testing all of the necessary state transition and networking code. Additionally, we predict that the set of applications for decentralized consensus technology will follow a power law distribution where the vast majority of applications would be too small to warrant their own blockchain, and we note that there exist large classes of decentralized applications, particularly decentralized autonomous organizations, that need to interact with each other. + +The Bitcoin-based approach, on the other hand, has the flaw that it does not inherit the simplified payment verification features of Bitcoin. SPV works for Bitcoin because it can use blockchain depth as a proxy for validity; at some point, once the ancestors of a transaction go far enough back, it is safe to say that they were legitimately part of the state. Blockchain-based meta-protocols, on the other hand, cannot force the blockchain not to include transactions that are not valid within the context of their own protocols. Hence, a fully secure SPV meta-protocol implementation would need to backward scan all the way to the beginning of the Bitcoin blockchain to determine whether or not certain transactions are valid. Currently, all "light" implementations of Bitcoin-based meta-protocols rely on a trusted server to provide the data, arguably a highly suboptimal result especially when one of the primary purposes of a cryptocurrency is to eliminate the need for trust. + +### Scripting + +Even without any extensions, the Bitcoin protocol actually does facilitate a weak version of a concept of "smart contracts". UTXO in Bitcoin can be owned not just by a public key, but also by a more complicated script expressed in a simple stack-based programming language. In this paradigm, a transaction spending that UTXO must provide data that satisfies the script. Indeed, even the basic public key ownership mechanism is implemented via a script: the script takes an elliptic curve signature as input, verifies it against the transaction and the address that owns the UTXO, and returns 1 if the verification is successful and 0 otherwise. Other, more complicated, scripts exist for various additional use cases. For example, one can construct a script that requires signatures from two out of a given three private keys to validate ("multisig"), a setup useful for corporate accounts, secure savings accounts and some merchant escrow situations. Scripts can also be used to pay bounties for solutions to computational problems, and one can even construct a script that says something like "this Bitcoin UTXO is yours if you can provide an SPV proof that you sent a Dogecoin transaction of this denomination to me", essentially allowing decentralized cross-cryptocurrency exchange. + +However, the scripting language as implemented in Bitcoin has several important limitations: + +- **Lack of Turing-completeness** - that is to say, while there is a large subset of computation that the Bitcoin scripting language supports, it does not nearly support everything. The main category that is missing is loops. This is done to avoid infinite loops during transaction verification; theoretically it is a surmountable obstacle for script programmers, since any loop can be simulated by simply repeating the underlying code many times with an if statement, but it does lead to scripts that are very space-inefficient. For example, implementing an alternative elliptic curve signature algorithm would likely require 256 repeated multiplication rounds all individually included in the code. +- **Value-blindness** - there is no way for a UTXO script to provide fine-grained control over the amount that can be withdrawn. For example, one powerful use case of an oracle contract would be a hedging contract, where A and B put in $1000 worth of BTC and after 30 days the script sends $1000 worth of BTC to A and the rest to B. This would require an oracle to determine the value of 1 BTC in USD, but even then it is a massive improvement in terms of trust and infrastructure requirement over the fully centralized solutions that are available now. However, because UTXO are all-or-nothing, the only way to achieve this is through the very inefficient hack of having many UTXO of varying denominations (eg. one UTXO of 2k for every k up to 30) and having the oracle pick which UTXO to send to A and which to B. +- **Lack of state** - UTXO can either be spent or unspent; there is no opportunity for multi-stage contracts or scripts which keep any other internal state beyond that. This makes it hard to make multi-stage options contracts, decentralized exchange offers or two-stage cryptographic commitment protocols (necessary for secure computational bounties). It also means that UTXO can only be used to build simple, one-off contracts and not more complex "stateful" contracts such as decentralized organizations, and makes meta-protocols difficult to implement. Binary state combined with value-blindness also mean that another important application, withdrawal limits, is impossible. +- **Blockchain-blindness** - UTXO are blind to blockchain data such as the nonce, the timestamp and previous block hash. This severely limits applications in gambling, and several other categories, by depriving the scripting language of a potentially valuable source of randomness. + +Thus, we see three approaches to building advanced applications on top of cryptocurrency: building a new blockchain, using scripting on top of Bitcoin, and building a meta-protocol on top of Bitcoin. Building a new blockchain allows for unlimited freedom in building a feature set, but at the cost of development time, bootstrapping effort and security. Using scripting is easy to implement and standardize, but is very limited in its capabilities, and meta-protocols, while easy, suffer from faults in scalability. With Ethereum, we intend to build an alternative framework that provides even larger gains in ease of development as well as even stronger light client properties, while at the same time allowing applications to share an economic environment and blockchain security. + +## Ethereum + +The intent of Ethereum is to create an alternative protocol for building decentralized applications, providing a different set of tradeoffs that we believe will be very useful for a large class of decentralized applications, with particular emphasis on situations where rapid development time, security for small and rarely used applications, and the ability of different applications to very efficiently interact, are important. Ethereum does this by building what is essentially the ultimate abstract foundational layer: a blockchain with a built-in Turing-complete programming language, allowing anyone to write smart contracts and decentralized applications where they can create their own arbitrary rules for ownership, transaction formats and state transition functions. A bare-bones version of Namecoin can be written in two lines of code, and other protocols like currencies and reputation systems can be built in under twenty. Smart contracts, cryptographic "boxes" that contain value and only unlock it if certain conditions are met, can also be built on top of the platform, with vastly more power than that offered by Bitcoin scripting because of the added powers of Turing-completeness, value-awareness, blockchain-awareness and state. + +### Ethereum Accounts + +In Ethereum, the state is made up of objects called "accounts", with each account having a 20-byte address and state transitions being direct transfers of value and information between accounts. An Ethereum account contains four fields: + +- The **nonce**, a counter used to make sure each transaction can only be processed once +- The account's current **ether balance** +- The account's **contract code**, if present +- The account's **storage** (empty by default) + +"Ether" is the main internal crypto-fuel of Ethereum, and is used to pay transaction fees. In general, there are two types of accounts: **externally owned accounts**, controlled by private keys, and **contract accounts**, controlled by their contract code. An externally owned account has no code, and one can send messages from an externally owned account by creating and signing a transaction; in a contract account, every time the contract account receives a message its code activates, allowing it to read and write to internal storage and send other messages or create contracts in turn. + +Note that "contracts" in Ethereum should not be seen as something that should be "fulfilled" or "complied with"; rather, they are more like "autonomous agents" that live inside of the Ethereum execution environment, always executing a specific piece of code when "poked" by a message or transaction, and having direct control over their own ether balance and their own key/value store to keep track of persistent variables. + +### Messages and Transactions + +The term "transaction" is used in Ethereum to refer to the signed data package that stores a message to be sent from an externally owned account. Transactions contain: + +- The recipient of the message +- A signature identifying the sender +- The amount of ether to transfer from the sender to the recipient +- An optional data field +- A `STARTGAS` value, representing the maximum number of computational steps the transaction execution is allowed to take +- A `GASPRICE` value, representing the fee the sender pays per computational step + +The first three are standard fields expected in any cryptocurrency. The data field has no function by default, but the virtual machine has an opcode using which a contract can access the data; as an example use case, if a contract is functioning as an on-blockchain domain registration service, then it may wish to interpret the data being passed to it as containing two "fields", the first field being a domain to register and the second field being the IP address to register it to. The contract would read these values from the message data and appropriately place them in storage. + +The `STARTGAS` and `GASPRICE` fields are crucial for Ethereum's anti-denial of service model. In order to prevent accidental or hostile infinite loops or other computational wastage in code, each transaction is required to set a limit to how many computational steps of code execution it can use. The fundamental unit of computation is "gas"; usually, a computational step costs 1 gas, but some operations cost higher amounts of gas because they are more computationally expensive, or increase the amount of data that must be stored as part of the state. There is also a fee of 5 gas for every byte in the transaction data. The intent of the fee system is to require an attacker to pay proportionately for every resource that they consume, including computation, bandwidth and storage; hence, any transaction that leads to the network consuming a greater amount of any of these resources must have a gas fee roughly proportional to the increment. + +### Messages + +Contracts have the ability to send "messages" to other contracts. Messages are virtual objects that are never serialized and exist only in the Ethereum execution environment. A message contains: + +- The sender of the message (implicit) +- The recipient of the message +- The amount of ether to transfer alongside the message +- An optional data field +- A `STARTGAS` value + +Essentially, a message is like a transaction, except it is produced by a contract and not an external actor. A message is produced when a contract currently executing code executes the `CALL` opcode, which produces and executes a message. Like a transaction, a message leads to the recipient account running its code. Thus, contracts can have relationships with other contracts in exactly the same way that external actors can. + +Note that the gas allowance assigned by a transaction or contract applies to the total gas consumed by that transaction and all sub-executions. For example, if an external actor A sends a transaction to B with 1000 gas, and B consumes 600 gas before sending a message to C, and the internal execution of C consumes 300 gas before returning, then B can spend another 100 gas before running out of gas. + +### Ethereum State Transition Function + +![Ether state transition](./ether-state-transition.png) + +The Ethereum state transition function, `APPLY(S,TX) -> S'` can be defined as follows: + +1. Check if the transaction is well-formed (ie. has the right number of values), the signature is valid, and the nonce matches the nonce in the sender's account. If not, return an error. +2. Calculate the transaction fee as `STARTGAS * GASPRICE`, and determine the sending address from the signature. Subtract the fee from the sender's account balance and increment the sender's nonce. If there is not enough balance to spend, return an error. +3. Initialize `GAS = STARTGAS`, and take off a certain quantity of gas per byte to pay for the bytes in the transaction. +4. Transfer the transaction value from the sender's account to the receiving account. If the receiving account does not yet exist, create it. If the receiving account is a contract, run the contract's code either to completion or until the execution runs out of gas. +5. If the value transfer failed because the sender did not have enough money, or the code execution ran out of gas, revert all state changes except the payment of the fees, and add the fees to the miner's account. +6. Otherwise, refund the fees for all remaining gas to the sender, and send the fees paid for gas consumed to the miner. + +For example, suppose that the contract's code is: + +```py +if !self.storage[calldataload(0)]: + self.storage[calldataload(0)] = calldataload(32) +``` + +Note that in reality the contract code is written in the low-level EVM code; this example is written in Serpent, one of our high-level languages, for clarity, and can be compiled down to EVM code. Suppose that the contract's storage starts off empty, and a transaction is sent with 10 ether value, 2000 gas, 0.001 ether gasprice, and 64 bytes of data, with bytes 0-31 representing the number `2` and bytes 32-63 representing the string `CHARLIE`. The process for the state transition function in this case is as follows: + +1. Check that the transaction is valid and well formed. +2. Check that the transaction sender has at least 2000 \* 0.001 = 2 ether. If it is, then subtract 2 ether from the sender's account. +3. Initialize gas = 2000; assuming the transaction is 170 bytes long and the byte-fee is 5, subtract 850 so that there is 1150 gas left. +4. Subtract 10 more ether from the sender's account, and add it to the contract's account. +5. Run the code. In this case, this is simple: it checks if the contract's storage at index `2` is used, notices that it is not, and so it sets the storage at index `2` to the value `CHARLIE`. Suppose this takes 187 gas, so the remaining amount of gas is 1150 - 187 = 963 +6. Add 963 \* 0.001 = 0.963 ether back to the sender's account, and return the resulting state. + +If there was no contract at the receiving end of the transaction, then the total transaction fee would simply be equal to the provided `GASPRICE` multiplied by the length of the transaction in bytes, and the data sent alongside the transaction would be irrelevant. + +Note that messages work equivalently to transactions in terms of reverts: if a message execution runs out of gas, then that message's execution, and all other executions triggered by that execution, revert, but parent executions do not need to revert. This means that it is "safe" for a contract to call another contract, as if A calls B with G gas then A's execution is guaranteed to lose at most G gas. Finally, note that there is an opcode, `CREATE`, that creates a contract; its execution mechanics are generally similar to `CALL`, with the exception that the output of the execution determines the code of a newly created contract. + +### Code Execution + +The code in Ethereum contracts is written in a low-level, stack-based bytecode language, referred to as "Ethereum virtual machine code" or "EVM code". The code consists of a series of bytes, where each byte represents an operation. In general, code execution is an infinite loop that consists of repeatedly carrying out the operation at the current program counter (which begins at zero) and then incrementing the program counter by one, until the end of the code is reached or an error or `STOP` or `RETURN` instruction is detected. The operations have access to three types of space in which to store data: + +- The **stack**, a last-in-first-out container to which values can be pushed and popped +- **Memory**, an infinitely expandable byte array +- The contract's long-term **storage**, a key/value store. Unlike stack and memory, which reset after computation ends, storage persists for the long term. + +The code can also access the value, sender and data of the incoming message, as well as block header data, and the code can also return a byte array of data as an output. + +The formal execution model of EVM code is surprisingly simple. While the Ethereum virtual machine is running, its full computational state can be defined by the tuple `(block_state, transaction, message, code, memory, stack, pc, gas)`, where `block_state` is the global state containing all accounts and includes balances and storage. At the start of every round of execution, the current instruction is found by taking the `pc`th byte of `code` (or 0 if `pc >= len(code)`), and each instruction has its own definition in terms of how it affects the tuple. For example, `ADD` pops two items off the stack and pushes their sum, reduces `gas` by 1 and increments `pc` by 1, and `SSTORE` pops the top two items off the stack and inserts the second item into the contract's storage at the index specified by the first item. Although there are many ways to optimize Ethereum virtual machine execution via just-in-time compilation, a basic implementation of Ethereum can be done in a few hundred lines of code. + +### Blockchain and Mining + +![Ethereum apply block diagram](./ethereum-apply-block-diagram.png) + +The Ethereum blockchain is in many ways similar to the Bitcoin blockchain, although it does have some differences. The main difference between Ethereum and Bitcoin with regard to the blockchain architecture is that, unlike Bitcoin, Ethereum blocks contain a copy of both the transaction list and the most recent state. Aside from that, two other values, the block number and the difficulty, are also stored in the block. The basic block validation algorithm in Ethereum is as follows: + +1. Check if the previous block referenced exists and is valid. +2. Check that the timestamp of the block is greater than that of the referenced previous block and less than 15 minutes into the future +3. Check that the block number, difficulty, transaction root, uncle root and gas limit (various low-level Ethereum-specific concepts) are valid. +4. Check that the proof-of-work on the block is valid. +5. Let `S[0]` be the state at the end of the previous block. +6. Let `TX` be the block's transaction list, with `n` transactions. For all `i` in `0...n-1`, set `S[i+1] = APPLY(S[i],TX[i])`. If any applications returns an error, or if the total gas consumed in the block up until this point exceeds the `GASLIMIT`, return an error. +7. Let `S_FINAL` be `S[n]`, but adding the block reward paid to the miner. +8. Check if the Merkle tree root of the state `S_FINAL` is equal to the final state root provided in the block header. If it is, the block is valid; otherwise, it is not valid. + +The approach may seem highly inefficient at first glance, because it needs to store the entire state with each block, but in reality efficiency should be comparable to that of Bitcoin. The reason is that the state is stored in the tree structure, and after every block only a small part of the tree needs to be changed. Thus, in general, between two adjacent blocks the vast majority of the tree should be the same, and therefore the data can be stored once and referenced twice using pointers (ie. hashes of subtrees). A special kind of tree known as a "Patricia tree" is used to accomplish this, including a modification to the Merkle tree concept that allows for nodes to be inserted and deleted, and not just changed, efficiently. Additionally, because all of the state information is part of the last block, there is no need to store the entire blockchain history - a strategy which, if it could be applied to Bitcoin, can be calculated to provide 5-20x savings in space. + +A commonly asked question is "where" contract code is executed, in terms of physical hardware. This has a simple answer: the process of executing contract code is part of the definition of the state transition function, which is part of the block validation algorithm, so if a transaction is added into block `B` the code execution spawned by that transaction will be executed by all nodes, now and in the future, that download and validate block `B`. + +## Applications + +In general, there are three types of applications on top of Ethereum. The first category is financial applications, providing users with more powerful ways of managing and entering into contracts using their money. This includes sub-currencies, financial derivatives, hedging contracts, savings wallets, wills, and ultimately even some classes of full-scale employment contracts. The second category is semi-financial applications, where money is involved but there is also a heavy non-monetary side to what is being done; a perfect example is self-enforcing bounties for solutions to computational problems. Finally, there are applications such as online voting and decentralized governance that are not financial at all. + +### Token Systems + +On-blockchain token systems have many applications ranging from sub-currencies representing assets such as USD or gold to company stocks, individual tokens representing smart property, secure unforgeable coupons, and even token systems with no ties to conventional value at all, used as point systems for incentivization. Token systems are surprisingly easy to implement in Ethereum. The key point to understand is that all a currency, or token system, fundamentally is, is a database with one operation: subtract X units from A and give X units to B, with the proviso that (i) A had at least X units before the transaction and (2) the transaction is approved by A. All that it takes to implement a token system is to implement this logic into a contract. + +The basic code for implementing a token system in Serpent looks as follows: + +```py +def send(to, value): + if self.storage[msg.sender] >= value: + self.storage[msg.sender] = self.storage[msg.sender] - value + self.storage[to] = self.storage[to] + value +``` + +This is essentially a literal implementation of the "banking system" state transition function described further above in this document. A few extra lines of code need to be added to provide for the initial step of distributing the currency units in the first place and a few other edge cases, and ideally a function would be added to let other contracts query for the balance of an address. But that's all there is to it. Theoretically, Ethereum-based token systems acting as sub-currencies can potentially include another important feature that onchain Bitcoin-based meta-currencies lack: the ability to pay transaction fees directly in that currency. The way this would be implemented is that the contract would maintain an ether balance with which it would refund ether used to pay fees to the sender, and it would refill this balance by collecting the internal currency units that it takes in fees and reselling them in a constant running auction. Users would thus need to "activate" their accounts with ether, but once the ether is there it would be reusable because the contract would refund it each time. + +### Financial derivatives and Stable-Value Currencies + +Financial derivatives are the most common application of a "smart contract", and one of the simplest to implement in code. The main challenge in implementing financial contracts is that the majority of them require reference to an external price ticker; for example, a very desirable application is a smart contract that hedges against the volatility of ether (or another cryptocurrency) with respect to the US dollar, but doing this requires the contract to know what the value of ETH/USD is. The simplest way to do this is through a "data feed" contract maintained by a specific party (eg. NASDAQ) designed so that that party has the ability to update the contract as needed, and providing an interface that allows other contracts to send a message to that contract and get back a response that provides the price. + +Given that critical ingredient, the hedging contract would look as follows: + +1. Wait for party A to input 1000 ether. +2. Wait for party B to input 1000 ether. +3. Record the USD value of 1000 ether, calculated by querying the data feed contract, in storage, say this is $x. +4. After 30 days, allow A or B to "reactivate" the contract in order to send $x worth of ether (calculated by querying the data feed contract again to get the new price) to A and the rest to B. + +Such a contract would have significant potential in crypto-commerce. One of the main problems cited about cryptocurrency is the fact that it's volatile; although many users and merchants may want the security and convenience of dealing with cryptographic assets, they many not wish to face that prospect of losing 23% of the value of their funds in a single day. Up until now, the most commonly proposed solution has been issuer-backed assets; the idea is that an issuer creates a sub-currency in which they have the right to issue and revoke units, and provide one unit of the currency to anyone who provides them (offline) with one unit of a specified underlying asset (eg. gold, USD). The issuer then promises to provide one unit of the underlying asset to anyone who sends back one unit of the crypto-asset. This mechanism allows any non-cryptographic asset to be "uplifted" into a cryptographic asset, provided that the issuer can be trusted. + +In practice, however, issuers are not always trustworthy, and in some cases the banking infrastructure is too weak, or too hostile, for such services to exist. Financial derivatives provide an alternative. Here, instead of a single issuer providing the funds to back up an asset, a decentralized market of speculators, betting that the price of a cryptographic reference asset (eg. ETH) will go up, plays that role. Unlike issuers, speculators have no option to default on their side of the bargain because the hedging contract holds their funds in escrow. Note that this approach is not fully decentralized, because a trusted source is still needed to provide the price ticker, although arguably even still this is a massive improvement in terms of reducing infrastructure requirements (unlike being an issuer, issuing a price feed requires no licenses and can likely be categorized as free speech) and reducing the potential for fraud. + +### Identity and Reputation Systems + +The earliest alternative cryptocurrency of all, [Namecoin](http://namecoin.org/), attempted to use a Bitcoin-like blockchain to provide a name registration system, where users can register their names in a public database alongside other data. The major cited use case is for a [DNS](https://wikipedia.org/wiki/Domain_Name_System) system, mapping domain names like "bitcoin.org" (or, in Namecoin's case, "bitcoin.bit") to an IP address. Other use cases include email authentication and potentially more advanced reputation systems. Here is the basic contract to provide a Namecoin-like name registration system on Ethereum: + +```py +def register(name, value): + if !self.storage[name]: + self.storage[name] = value +``` + +The contract is very simple; all it is a database inside the Ethereum network that can be added to, but not modified or removed from. Anyone can register a name with some value, and that registration then sticks forever. A more sophisticated name registration contract will also have a "function clause" allowing other contracts to query it, as well as a mechanism for the "owner" (ie. the first registerer) of a name to change the data or transfer ownership. One can even add reputation and web-of-trust functionality on top. + +### Decentralized File Storage + +Over the past few years, there have emerged a number of popular online file storage startups, the most prominent being Dropbox, seeking to allow users to upload a backup of their hard drive and have the service store the backup and allow the user to access it in exchange for a monthly fee. However, at this point the file storage market is at times relatively inefficient; a cursory look at various existing solutions shows that, particularly at the "uncanny valley" 20-200 GB level at which neither free quotas nor enterprise-level discounts kick in, monthly prices for mainstream file storage costs are such that you are paying for more than the cost of the entire hard drive in a single month. Ethereum contracts can allow for the development of a decentralized file storage ecosystem, where individual users can earn small quantities of money by renting out their own hard drives and unused space can be used to further drive down the costs of file storage. + +The key underpinning piece of such a device would be what we have termed the "decentralized Dropbox contract". This contract works as follows. First, one splits the desired data up into blocks, encrypting each block for privacy, and builds a Merkle tree out of it. One then makes a contract with the rule that, every N blocks, the contract would pick a random index in the Merkle tree (using the previous block hash, accessible from contract code, as a source of randomness), and give X ether to the first entity to supply a transaction with a simplified payment verification-like proof of ownership of the block at that particular index in the tree. When a user wants to re-download their file, they can use a micropayment channel protocol (eg. pay 1 szabo per 32 kilobytes) to recover the file; the most fee-efficient approach is for the payer not to publish the transaction until the end, instead replacing the transaction with a slightly more lucrative one with the same nonce after every 32 kilobytes. + +An important feature of the protocol is that, although it may seem like one is trusting many random nodes not to decide to forget the file, one can reduce that risk down to near-zero by splitting the file into many pieces via secret sharing, and watching the contracts to see each piece is still in some node's possession. If a contract is still paying out money, that provides a cryptographic proof that someone out there is still storing the file. + +### Decentralized Autonomous Organizations + +The general concept of a "decentralized autonomous organization" is that of a virtual entity that has a certain set of members or shareholders which, perhaps with a 67% majority, have the right to spend the entity's funds and modify its code. The members would collectively decide on how the organization should allocate its funds. Methods for allocating a DAO's funds could range from bounties, salaries to even more exotic mechanisms such as an internal currency to reward work. This essentially replicates the legal trappings of a traditional company or nonprofit but using only cryptographic blockchain technology for enforcement. So far much of the talk around DAOs has been around the "capitalist" model of a "decentralized autonomous corporation" (DAC) with dividend-receiving shareholders and tradable shares; an alternative, perhaps described as a "decentralized autonomous community", would have all members have an equal share in the decision making and require 67% of existing members to agree to add or remove a member. The requirement that one person can only have one membership would then need to be enforced collectively by the group. + +A general outline for how to code a DAO is as follows. The simplest design is simply a piece of self-modifying code that changes if two thirds of members agree on a change. Although code is theoretically immutable, one can easily get around this and have de-facto mutability by having chunks of the code in separate contracts, and having the address of which contracts to call stored in the modifiable storage. In a simple implementation of such a DAO contract, there would be three transaction types, distinguished by the data provided in the transaction: + +- `[0,i,K,V]` to register a proposal with index `i` to change the address at storage index `K` to value `V` +- `[1,i]` to register a vote in favor of proposal `i` +- `[2,i]` to finalize proposal `i` if enough votes have been made + +The contract would then have clauses for each of these. It would maintain a record of all open storage changes, along with a list of who voted for them. It would also have a list of all members. When any storage change gets to two thirds of members voting for it, a finalizing transaction could execute the change. A more sophisticated skeleton would also have built-in voting ability for features like sending a transaction, adding members and removing members, and may even provide for [Liquid Democracy](https://wikipedia.org/wiki/Liquid_democracy)-style vote delegation (ie. anyone can assign someone to vote for them, and assignment is transitive so if A assigns B and B assigns C then C determines A's vote). This design would allow the DAO to grow organically as a decentralized community, allowing people to eventually delegate the task of filtering out who is a member to specialists, although unlike in the "current system" specialists can easily pop in and out of existence over time as individual community members change their alignments. + +An alternative model is for a decentralized corporation, where any account can have zero or more shares, and two thirds of the shares are required to make a decision. A complete skeleton would involve asset management functionality, the ability to make an offer to buy or sell shares, and the ability to accept offers (preferably with an order-matching mechanism inside the contract). Delegation would also exist Liquid Democracy-style, generalizing the concept of a "board of directors". + +### Further Applications + +**1. Savings wallets**. Suppose that Alice wants to keep her funds safe, but is worried that she will lose or someone will hack her private key. She puts ether into a contract with Bob, a bank, as follows: + +- Alice alone can withdraw a maximum of 1% of the funds per day. +- Bob alone can withdraw a maximum of 1% of the funds per day, but Alice has the ability to make a transaction with her key shutting off this ability. +- Alice and Bob together can withdraw anything. + +Normally, 1% per day is enough for Alice, and if Alice wants to withdraw more she can contact Bob for help. If Alice's key gets hacked, she runs to Bob to move the funds to a new contract. If she loses her key, Bob will get the funds out eventually. If Bob turns out to be malicious, then she can turn off his ability to withdraw. + +**2. Crop insurance**. One can easily make a financial derivatives contract but using a data feed of the weather instead of any price index. If a farmer in Iowa purchases a derivative that pays out inversely based on the precipitation in Iowa, then if there is a drought, the farmer will automatically receive money and if there is enough rain the farmer will be happy because their crops would do well. This can be expanded to natural disaster insurance generally. + +**3. A decentralized data feed**. For financial contracts for difference, it may actually be possible to decentralize the data feed via a protocol called "[SchellingCoin](http://blog.ethereum.org/2014/03/28/schellingcoin-a-minimal-trust-universal-data-feed/)". SchellingCoin basically works as follows: N parties all put into the system the value of a given datum (eg. the ETH/USD price), the values are sorted, and everyone between the 25th and 75th percentile gets one token as a reward. Everyone has the incentive to provide the answer that everyone else will provide, and the only value that a large number of players can realistically agree on is the obvious default: the truth. This creates a decentralized protocol that can theoretically provide any number of values, including the ETH/USD price, the temperature in Berlin or even the result of a particular hard computation. + +**4. Smart multisignature escrow**. Bitcoin allows multisignature transaction contracts where, for example, three out of a given five keys can spend the funds. Ethereum allows for more granularity; for example, four out of five can spend everything, three out of five can spend up to 10% per day, and two out of five can spend up to 0.5% per day. Additionally, Ethereum multisig is asynchronous - two parties can register their signatures on the blockchain at different times and the last signature will automatically send the transaction. + +**5. Cloud computing**. The EVM technology can also be used to create a verifiable computing environment, allowing users to ask others to carry out computations and then optionally ask for proofs that computations at certain randomly selected checkpoints were done correctly. This allows for the creation of a cloud computing market where any user can participate with their desktop, laptop or specialized server, and spot-checking together with security deposits can be used to ensure that the system is trustworthy (ie. nodes cannot profitably cheat). Although such a system may not be suitable for all tasks; tasks that require a high level of inter-process communication, for example, cannot easily be done on a large cloud of nodes. Other tasks, however, are much easier to parallelize; projects like SETI@home, folding@home and genetic algorithms can easily be implemented on top of such a platform. + +**6. Peer-to-peer gambling**. Any number of peer-to-peer gambling protocols, such as Frank Stajano and Richard Clayton's [Cyberdice](http://www.cl.cam.ac.uk/~fms27/papers/2008-StajanoCla-cyberdice.pdf), can be implemented on the Ethereum blockchain. The simplest gambling protocol is actually simply a contract for difference on the next block hash, and more advanced protocols can be built up from there, creating gambling services with near-zero fees that have no ability to cheat. + +**7. Prediction markets**. Provided an oracle or SchellingCoin, prediction markets are also easy to implement, and prediction markets together with SchellingCoin may prove to be the first mainstream application of [futarchy](http://hanson.gmu.edu/futarchy.html) as a governance protocol for decentralized organizations. + +**8. Onchain decentralized marketplaces**, using the identity and reputation system as a base. + +## Miscellanea And Concerns + +### Modified GHOST Implementation + +The "Greedy Heaviest Observed Subtree" (GHOST) protocol is an innovation first introduced by Yonatan Sompolinsky and Aviv Zohar in [December 2013](https://eprint.iacr.org/2013/881.pdf). The motivation behind GHOST is that blockchains with fast confirmation times currently suffer from reduced security due to a high stale rate - because blocks take a certain time to propagate through the network, if miner A mines a block and then miner B happens to mine another block before miner A's block propagates to B, miner B's block will end up wasted and will not contribute to network security. Furthermore, there is a centralization issue: if miner A is a mining pool with 30% hashpower and B has 10% hashpower, A will have a risk of producing a stale block 70% of the time (since the other 30% of the time A produced the last block and so will get mining data immediately) whereas B will have a risk of producing a stale block 90% of the time. Thus, if the block interval is short enough for the stale rate to be high, A will be substantially more efficient simply by virtue of its size. With these two effects combined, blockchains which produce blocks quickly are very likely to lead to one mining pool having a large enough percentage of the network hashpower to have de facto control over the mining process. + +As described by Sompolinsky and Zohar, GHOST solves the first issue of network security loss by including stale blocks in the calculation of which chain is the "longest"; that is to say, not just the parent and further ancestors of a block, but also the stale descendants of the block's ancestor (in Ethereum jargon, "uncles") are added to the calculation of which block has the largest total proof-of-work backing it. To solve the second issue of centralization bias, we go beyond the protocol described by Sompolinsky and Zohar, and also provide block rewards to stales: a stale block receives 87.5% of its base reward, and the nephew that includes the stale block receives the remaining 12.5%. Transaction fees, however, are not awarded to uncles. + +Ethereum implements a simplified version of GHOST which only goes down seven levels. Specifically, it is defined as follows: + +- A block must specify a parent, and it must specify 0 or more uncles +- An uncle included in block B must have the following properties: + - It must be a direct child of the kth generation ancestor of B, where `2 kC`, or `R > NC`. Note that `R` is the per-operation fee provided by the sender, and is thus a lower bound on the benefit that the sender derives from the transaction, and `NC` is the cost to the entire network together of processing an operation. Hence, miners have the incentive to include only those transactions for which the total utilitarian benefit exceeds the cost. + +However, there are several important deviations from those assumptions in reality: + +1. The miner does pay a higher cost to process the transaction than the other verifying nodes, since the extra verification time delays block propagation and thus increases the chance the block will become a stale. +2. There do exist nonmining full nodes. +3. The mining power distribution may end up radically inegalitarian in practice. +4. Speculators, political enemies and crazies whose utility function includes causing harm to the network do exist, and they can cleverly set up contracts where their cost is much lower than the cost paid by other verifying nodes. + +(1) provides a tendency for the miner to include fewer transactions, and +(2) increases `NC`; hence, these two effects at least partially +cancel each other +out.[How?](https://github.com/ethereum/wiki/issues/447#issuecomment-316972260) +(3) and (4) are the major issue; to solve them we simply institute a +floating cap: no block can have more operations than +`BLK_LIMIT_FACTOR` times the long-term exponential moving average. +Specifically: + +```js +blk.oplimit = floor((blk.parent.oplimit \* (EMAFACTOR - 1) + +floor(parent.opcount \* BLK\_LIMIT\_FACTOR)) / EMA\_FACTOR) +``` + +`BLK_LIMIT_FACTOR` and `EMA_FACTOR` are constants that will be set to 65536 and 1.5 for the time being, but will likely be changed after further analysis. + +There is another factor disincentivizing large block sizes in Bitcoin: blocks that are large will take longer to propagate, and thus have a higher probability of becoming stales. In Ethereum, highly gas-consuming blocks can also take longer to propagate both because they are physically larger and because they take longer to process the transaction state transitions to validate. This delay disincentive is a significant consideration in Bitcoin, but less so in Ethereum because of the GHOST protocol; hence, relying on regulated block limits provides a more stable baseline. + +### Computation And Turing-Completeness + +An important note is that the Ethereum virtual machine is Turing-complete; this means that EVM code can encode any computation that can be conceivably carried out, including infinite loops. EVM code allows looping in two ways. First, there is a `JUMP` instruction that allows the program to jump back to a previous spot in the code, and a `JUMPI` instruction to do conditional jumping, allowing for statements like `while x 50 computational steps. Miners could try to detect such logic bombs ahead of time by maintaining a value alongside each contract specifying the maximum number of computational steps that it can take, and calculating this for contracts calling other contracts recursively, but that would require miners to forbid contracts that create other contracts (since the creation and execution of all 26 contracts above could easily be rolled into a single contract). Another problematic point is that the address field of a message is a variable, so in general it may not even be possible to tell which other contracts a given contract will call ahead of time. Hence, all in all, we have a surprising conclusion: Turing-completeness is surprisingly easy to manage, and the lack of Turing-completeness is equally surprisingly difficult to manage unless the exact same controls are in place - but in that case why not just let the protocol be Turing-complete? + +### Currency And Issuance + +The Ethereum network includes its own built-in currency, ether, which serves the dual purpose of providing a primary liquidity layer to allow for efficient exchange between various types of digital assets and, more importantly, of providing a mechanism for paying transaction fees. For convenience and to avoid future argument (see the current mBTC/uBTC/satoshi debate in Bitcoin), the denominations will be pre-labelled: + +- 1: wei +- 1012: szabo +- 1015: finney +- 1018: ether + +This should be taken as an expanded version of the concept of "dollars" and "cents" or "BTC" and "satoshi". In the near future, we expect "ether" to be used for ordinary transactions, "finney" for microtransactions and "szabo" and "wei" for technical discussions around fees and protocol implementation; the remaining denominations may become useful later and should not be included in clients at this point. + +The issuance model will be as follows: + +- Ether will be released in a currency sale at the price of 1000-2000 ether per BTC, a mechanism intended to fund the Ethereum organization and pay for development that has been used with success by other platforms such as Mastercoin and NXT. Earlier buyers will benefit from larger discounts. The BTC received from the sale will be used entirely to pay salaries and bounties to developers and invested into various for-profit and non-profit projects in the Ethereum and cryptocurrency ecosystem. +- 0.099x the total amount sold (60102216 ETH) will be allocated to the organization to compensate early contributors and pay ETH-denominated expenses before the genesis block. +- 0.099x the total amount sold will be maintained as a long-term reserve. +- 0.26x the total amount sold will be allocated to miners per year forever after that point. + +| Group | At launch | After 1 year | After 5 years | +| ---------------------- | --------- | ------------ | ------------- | +| Currency units | 1.198X | 1.458X | 2.498X | +| Purchasers | 83.5% | 68.6% | 40.0% | +| Reserve spent pre-sale | 8.26% | 6.79% | 3.96% | +| Reserve used post-sale | 8.26% | 6.79% | 3.96% | +| Miners | 0% | 17.8% | 52.0% | + +#### Long-Term Supply Growth Rate (percent) + +![Ethereum inflation](./ethereum-inflation.png) + +_Despite the linear currency issuance, just like with Bitcoin over time the supply growth rate nevertheless tends to zero._ + +The two main choices in the above model are (1) the existence and size of an endowment pool, and (2) the existence of a permanently growing linear supply, as opposed to a capped supply as in Bitcoin. The justification of the endowment pool is as follows. If the endowment pool did not exist, and the linear issuance reduced to 0.217x to provide the same inflation rate, then the total quantity of ether would be 16.5% less and so each unit would be 19.8% more valuable. Hence, in the equilibrium 19.8% more ether would be purchased in the sale, so each unit would once again be exactly as valuable as before. The organization would also then have 1.198x as much BTC, which can be considered to be split into two slices: the original BTC, and the additional 0.198x. Hence, this situation is _exactly equivalent_ to the endowment, but with one important difference: the organization holds purely BTC, and so is not incentivized to support the value of the ether unit. + +The permanent linear supply growth model reduces the risk of what some see as excessive wealth concentration in Bitcoin, and gives individuals living in present and future eras a fair chance to acquire currency units, while at the same time retaining a strong incentive to obtain and hold ether because the "supply growth rate" as a percentage still tends to zero over time. We also theorize that because coins are always lost over time due to carelessness, death, etc, and coin loss can be modeled as a percentage of the total supply per year, that the total currency supply in circulation will in fact eventually stabilize at a value equal to the annual issuance divided by the loss rate (eg. at a loss rate of 1%, once the supply reaches 26X then 0.26X will be mined and 0.26X lost every year, creating an equilibrium). + +Note that in the future, it is likely that Ethereum will switch to a proof-of-stake model for security, reducing the issuance requirement to somewhere between zero and 0.05X per year. In the event that the Ethereum organization loses funding or for any other reason disappears, we leave open a "social contract": anyone has the right to create a future candidate version of Ethereum, with the only condition being that the quantity of ether must be at most equal to `60102216 * (1.198 + 0.26 * n)` where `n` is the number of years after the genesis block. Creators are free to crowd-sell or otherwise assign some or all of the difference between the PoS-driven supply expansion and the maximum allowable supply expansion to pay for development. Candidate upgrades that do not comply with the social contract may justifiably be forked into compliant versions. + +### Mining Centralization + +The Bitcoin mining algorithm works by having miners compute SHA256 on slightly modified versions of the block header millions of times over and over again, until eventually one node comes up with a version whose hash is less than the target (currently around 2192). However, this mining algorithm is vulnerable to two forms of centralization. First, the mining ecosystem has come to be dominated by ASICs (application-specific integrated circuits), computer chips designed for, and therefore thousands of times more efficient at, the specific task of Bitcoin mining. This means that Bitcoin mining is no longer a highly decentralized and egalitarian pursuit, requiring millions of dollars of capital to effectively participate in. Second, most Bitcoin miners do not actually perform block validation locally; instead, they rely on a centralized mining pool to provide the block headers. This problem is arguably worse: as of the time of this writing, the top three mining pools indirectly control roughly 50% of processing power in the Bitcoin network, although this is mitigated by the fact that miners can switch to other mining pools if a pool or coalition attempts a 51% attack. + +The current intent at Ethereum is to use a mining algorithm where miners are required to fetch random data from the state, compute some randomly selected transactions from the last N blocks in the blockchain, and return the hash of the result. This has two important benefits. First, Ethereum contracts can include any kind of computation, so an Ethereum ASIC would essentially be an ASIC for general computation - ie. a better CPU. Second, mining requires access to the entire blockchain, forcing miners to store the entire blockchain and at least be capable of verifying every transaction. This removes the need for centralized mining pools; although mining pools can still serve the legitimate role of evening out the randomness of reward distribution, this function can be served equally well by peer-to-peer pools with no central control. + +This model is untested, and there may be difficulties along the way in avoiding certain clever optimizations when using contract execution as a mining algorithm. However, one notably interesting feature of this algorithm is that it allows anyone to "poison the well", by introducing a large number of contracts into the blockchain specifically designed to stymie certain ASICs. The economic incentives exist for ASIC manufacturers to use such a trick to attack each other. Thus, the solution that we are developing is ultimately an adaptive economic human solution rather than purely a technical one. + +### Scalability + +One common concern about Ethereum is the issue of scalability. Like Bitcoin, Ethereum suffers from the flaw that every transaction needs to be processed by every node in the network. With Bitcoin, the size of the current blockchain rests at about 15 GB, growing by about 1 MB per hour. If the Bitcoin network were to process Visa's 2000 transactions per second, it would grow by 1 MB per three seconds (1 GB per hour, 8 TB per year). Ethereum is likely to suffer a similar growth pattern, worsened by the fact that there will be many applications on top of the Ethereum blockchain instead of just a currency as is the case with Bitcoin, but ameliorated by the fact that Ethereum full nodes need to store just the state instead of the entire blockchain history. + +The problem with such a large blockchain size is centralization risk. If the blockchain size increases to, say, 100 TB, then the likely scenario would be that only a very small number of large businesses would run full nodes, with all regular users using light SPV nodes. In such a situation, there arises the potential concern that the full nodes could band together and all agree to cheat in some profitable fashion (eg. change the block reward, give themselves BTC). Light nodes would have no way of detecting this immediately. Of course, at least one honest full node would likely exist, and after a few hours information about the fraud would trickle out through channels like Reddit, but at that point it would be too late: it would be up to the ordinary users to organize an effort to blacklist the given blocks, a massive and likely infeasible coordination problem on a similar scale as that of pulling off a successful 51% attack. In the case of Bitcoin, this is currently a problem, but there exists a blockchain modification [suggested by Peter Todd](https://web.archive.org/web/20140623061815/http://sourceforge.net/p/bitcoin/mailman/message/31709140/) which will alleviate this issue. + +In the near term, Ethereum will use two additional strategies to cope with this problem. First, because of the blockchain-based mining algorithms, at least every miner will be forced to be a full node, creating a lower bound on the number of full nodes. Second and more importantly, however, we will include an intermediate state tree root in the blockchain after processing each transaction. Even if block validation is centralized, as long as one honest verifying node exists, the centralization problem can be circumvented via a verification protocol. If a miner publishes an invalid block, that block must either be badly formatted, or the state `S[n]` is incorrect. Since `S[0]` is known to be correct, there must be some first state `S[i]` that is incorrect where `S[i-1]` is correct. The verifying node would provide the index `i`, along with a "proof of invalidity" consisting of the subset of Patricia tree nodes needing to process `APPLY(S[i-1],TX[i]) -> S[i]`. Nodes would be able to use those nodes to run that part of the computation, and see that the `S[i]` generated does not match the `S[i]` provided. + +Another, more sophisticated, attack would involve the malicious miners publishing incomplete blocks, so the full information does not even exist to determine whether or not blocks are valid. The solution to this is a challenge-response protocol: verification nodes issue "challenges" in the form of target transaction indices, and upon receiving a node a light node treats the block as untrusted until another node, whether the miner or another verifier, provides a subset of Patricia nodes as a proof of validity. + +## Conclusion + +The Ethereum protocol was originally conceived as an upgraded version of a cryptocurrency, providing advanced features such as on-blockchain escrow, withdrawal limits, financial contracts, gambling markets and the like via a highly generalized programming language. The Ethereum protocol would not "support" any of the applications directly, but the existence of a Turing-complete programming language means that arbitrary contracts can theoretically be created for any transaction type or application. What is more interesting about Ethereum, however, is that the Ethereum protocol moves far beyond just currency. Protocols around decentralized file storage, decentralized computation and decentralized prediction markets, among dozens of other such concepts, have the potential to substantially increase the efficiency of the computational industry, and provide a massive boost to other peer-to-peer protocols by adding for the first time an economic layer. Finally, there is also a substantial array of applications that have nothing to do with money at all. + +The concept of an arbitrary state transition function as implemented by the Ethereum protocol provides for a platform with unique potential; rather than being a closed-ended, single-purpose protocol intended for a specific array of applications in data storage, gambling or finance, Ethereum is open-ended by design, and we believe that it is extremely well-suited to serving as a foundational layer for a very large number of both financial and non-financial protocols in the years to come. + +## Notes and Further Reading + +### Notes + +1. A sophisticated reader may notice that in fact a Bitcoin address is the hash of the elliptic curve public key, and not the public key itself. However, it is in fact perfectly legitimate cryptographic terminology to refer to the pubkey hash as a public key itself. This is because Bitcoin's cryptography can be considered to be a custom digital signature algorithm, where the public key consists of the hash of the ECC pubkey, the signature consists of the ECC pubkey concatenated with the ECC signature, and the verification algorithm involves checking the ECC pubkey in the signature against the ECC pubkey hash provided as a public key and then verifying the ECC signature against the ECC pubkey. +2. Technically, the median of the 11 previous blocks. +3. Internally, 2 and "CHARLIE" are both numbers[fn3](#notes), with the latter being in big-endian base 256 representation. Numbers can be at least 0 and at most 2256-1. + +### Further Reading + +1. [Intrinsic value](http://bitcoinmagazine.com/8640/an-exploration-of-intrinsic-value-what-it-is-why-bitcoin-doesnt-have-it-and-why-bitcoin-does-have-it/) +2. [Smart property](https://en.bitcoin.it/wiki/Smart_Property) +3. [Smart contracts](https://en.bitcoin.it/wiki/Contracts) +4. [B-money](http://www.weidai.com/bmoney.txt) +5. [Reusable proofs of work](https://nakamotoinstitute.org/finney/rpow/) +6. [Secure property titles with owner authority](https://nakamotoinstitute.org/secure-property-titles/) +7. [Bitcoin whitepaper](http://bitcoin.org/bitcoin.pdf) +8. [Namecoin](https://namecoin.org/) +9. [Zooko's triangle](https://wikipedia.org/wiki/Zooko's_triangle) +10. [Colored coins whitepaper](https://docs.google.com/a/buterin.com/document/d/1AnkP_cVZTCMLIzw4DvsW6M8Q2JC0lIzrTLuoWu2z1BE/edit) +11. [Mastercoin whitepaper](https://github.com/mastercoin-MSC/spec) +12. [Decentralized autonomous corporations, Bitcoin Magazine](http://bitcoinmagazine.com/7050/bootstrapping-a-decentralized-autonomous-corporation-part-i/) +13. [Simplified payment verification](https://en.bitcoin.it/wiki/Scalability#Simplified_payment_verification) +14. [Merkle trees](https://wikipedia.org/wiki/Merkle_tree) +15. [Patricia trees](https://wikipedia.org/wiki/Patricia_tree) +16. [GHOST](https://eprint.iacr.org/2013/881.pdf) +17. [StorJ and Autonomous Agents, Jeff Garzik](http://garzikrants.blogspot.ca/2013/01/storj-and-bitcoin-autonomous-agents.html) +18. [Mike Hearn on Smart Property at Turing Festival](https://www.youtube.com/watch?v=MVyv4t0OKe4) +19. [Ethereum RLP](https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP) +20. [Ethereum Merkle Patricia trees](https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-Patricia-Tree) +21. [Peter Todd on Merkle sum trees](https://web.archive.org/web/20140623061815/http://sourceforge.net/p/bitcoin/mailman/message/31709140/) + +_For history of the whitepaper, see [this wiki](https://github.com/ethereum/wiki/blob/old-before-deleting-all-files-go-to-wiki-wiki-instead/old-whitepaper-for-historical-reference.md)._ + +_Ethereum, like many community-driven, open-source software projects, has evolved since its initial inception. To learn about the latest developments of Ethereum, and how changes to the protocol are made, we recommend [this guide](/learn/)._ + +--- + +# Wrapped Eth + +## Wrapped Eth + +# Wrapped ether (WETH) + +Ether (ETH) is the main currency of Ethereum. It's used for several purposes like staking, as a currency, and paying for gas fees for computation. **WETH is effectively an upgraded form of ETH with some additional functionality required by many applications and [ERC-20 tokens](/glossary/#erc-20)**, which are other types of digital assets on Ethereum. To work with these tokens, ETH must follow the same rules they do, known as the ERC-20 standard. + +To bridge this gap, wrapped ETH (WETH) was created. **Wrapped ETH is a smart contract that lets you deposit any amount of ETH into the contract and receive the same amount in minted WETH** that conforms to the ERC-20 token standard. WETH is a representation of ETH that allows you to interact with it as an ERC-20 token, not as the native asset ETH. You will still need native ETH to pay for gas fees, so make sure you save some when depositing. + +You are able to unwrap WETH for ETH by using the WETH smart contract. You can redeem any amount of WETH with the WETH smart contract, and you will receive the same amount in ETH. The WETH deposited is then burned and taken out of the circulating supply of WETH. + +**Roughly ~3% of the circulating ETH supply is locked in the WETH token contract** making it one of the most used [smart contracts](/glossary/#smart-contract). WETH is especially important with users interacting with applications in decentralized finance (DeFi). + +## Why do we need to wrap ETH as an ERC-20? + +[ERC-20](/developers/docs/standards/tokens/erc-20/) defines a standard interface for transferable tokens, so anyone can create tokens that interact seamlessly with applications and tokens that use this standard in Ethereum's ecosystem. Since **ETH predates the ERC-20 standard**, ETH doesn't conform to this specification. This means **you can't easily** exchange ETH for other ERC-20 tokens or **use ETH in apps using the ERC-20 standard**. Wrapping ETH gives you the opportunity to do the following: + +- **Exchange ETH for ERC-20 tokens**: You cannot exchange ETH directly for other ERC-20 tokens. WETH is a representation of ether that complies with the ERC-20 fungible token standard and can be exchanged with other ERC-20 tokens. + +- **Use ETH in dapps**: Because ETH isn’t ERC20-compatible, developers would need to create separate interfaces (one for ETH and another for ERC-20 tokens) in dapps. Wrapping ETH removes this obstacle and enables developers to handle ETH and other tokens within the same dapp. Many decentralized finance applications use this standard, and create markets for exchanging these tokens. + +## Wrapped ether (WETH) vs ether (ETH): What is the difference? + + +| | **Ether (ETH)** | **Wrapped Ether (WETH)** | +|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Supply | The supply of ETH is managed by the Ethereum protocol. The [issuance](/roadmap/merge/issuance) of ETH is handled by Ethereum validators when processing transactions and creating blocks. | WETH is an ERC-20 token whose supply is managed by a smart contract. New units of WETH are issued by the contract after it receives ETH deposits from users, or units of WETH are burned when a user wishes to redeem WETH for ETH. | +| Ownership | Ownership is managed by the Ethereum protocol through your account balance. | Ownership of WETH is managed by the WETH token smart contract, secured by the Ethereum protocol. | +| Gas | Ether (ETH) is the accepted unit of payment for computation on the Ethereum network. Gas fees are denominated in gwei (a unit of ether). | Paying gas with WETH tokens is not natively supported. | + +## Frequently asked questions + + + +You pay gas fees to wrap or unwrap ETH using the WETH contract. + + + + + +WETH is generally considered secure because it is based on a simple, battle-tested smart contract. The WETH contract has also been formally verified, which is the highest security standard for smart contracts on Ethereum. + + + + + +Besides the [canonical implementation of WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) described on this page, there are other variants in the wild. These may be custom tokens created by app developers or versions issued on other blockchains, and may behave differently or have different security properties. **Always double-check the token information to know which WETH implementation you're interacting with.** + + + + + +- [Ethereum Mainnet](https://etherscan.io/token/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) +- [Arbitrum](https://arbiscan.io/token/0x82af49447d8a07e3bd95bd0d56f35241523fbab1) +- [Optimism](https://optimistic.etherscan.io/token/0x4200000000000000000000000000000000000006) + + + +## Further reading + +- [WTF is WETH?](https://weth.tkn.eth.limo/) +- [WETH token information on Blockscout](https://eth.blockscout.com/token/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) +- [Formal Verification of WETH](https://zellic.io/blog/formal-verification-weth) + +--- + +# Zero Knowledge Proofs + +## Zero Knowledge Proofs + +# What are zero-knowledge proofs? + +A zero-knowledge proof is a way of proving the validity of a statement without revealing the statement itself. The ‘prover’ is the party trying to prove a claim, while the ‘verifier’ is responsible for validating the claim. + +Zero-knowledge proofs first appeared in a 1985 paper, “[The knowledge complexity of interactive proof systems](http://people.csail.mit.edu/silvio/Selected%20Scientific%20Papers/Proof%20Systems/The_Knowledge_Complexity_Of_Interactive_Proof_Systems.pdf)” which provides a definition of zero-knowledge proofs widely used today: + +> A zero-knowledge protocol is a method by which one party (the prover) **can prove** to another party (the verifier) **that something is true, without revealing any information** apart from the fact that this specific statement is true. + +Zero-knowledge proofs have improved over the years and they are now being used in several real-world applications. + + + +## Why do we need zero-knowledge proofs? + +Zero-knowledge proofs represented a breakthrough in applied cryptography, as they promised to improve security of information for individuals. Consider how you might prove a claim (e.g., “I am a citizen of X country”) to another party (e.g., a service provider). You’d need to provide “evidence” to back up your claim, such as a national passport or driver’s license. + +But there are problems with this approach, chiefly the lack of privacy. Personally Identifiable Information (PII) shared with third-party services is stored in central databases, which are vulnerable to hacks. With identity theft becoming a critical issue, there are calls for more privacy-protecting means of sharing sensitive information. + +Zero-knowledge proofs solve this problem by **eliminating the need to reveal information to prove validity of claims**. The zero-knowledge protocol uses the statement (called a ‘witness’) as input to generate a succinct proof of its validity. This proof provides strong guarantees that a statement is true without exposing the information used in creating it. + +Going back to our earlier example, the only evidence you need to prove your citizenship claim is a zero-knowledge proof. The verifier only has to check if certain properties of the proof hold true to be convinced that the underlying statement holds true as well. + +## Use-cases for zero-knowledge proofs + +### Anonymous payments + +Credit card payments are often visible to multiple parties, including the payments provider, banks, and other interested parties (e.g., government authorities). While financial surveillance has benefits for identifying illegal activity, it also undermines the privacy of ordinary citizens. + +Cryptocurrencies were intended to provide a means for users to conduct private, peer-to-peer transactions. But most cryptocurrency transactions are openly visible on public blockchains. User identities are often pseudonymous and either wilfully linked to real-world identities (e.g. by including ETH addresses on Twitter or GitHub profiles) or can be associated with real-world identities using basic on and offchain data analysis. + +There are specific “privacy coins” designed for completely anonymous transactions. Privacy-focused blockchains, such as Zcash and Monero, shield transaction details, including sender/receiver addresses, asset type, quantity, and the transaction timeline. + +By baking in zero-knowledge technology into the protocol, privacy-focused [blockchain](/glossary/#blockchain) networks allow [nodes](/glossary/#node) to validate transactions without needing to access transaction data. [EIP-7503](https://eips.ethereum.org/EIPS/eip-7503) is an example of a proposed design that will enable native private transfers of value on the Ethereum blockchain. Such proposals are, however, difficult to implement due to a mixture of security, regulatory, and UX concerns. + +**Zero-knowledge proofs are also being applied to anonymizing transactions on public blockchains**. An example is Tornado Cash, a decentralized, non-custodial service that allows users to conduct private transactions on Ethereum. Tornado Cash uses zero-knowledge proofs to obfuscate transaction details and guarantee financial privacy. Unfortunately, because these are "opt-in" privacy tools they are associated with illicit activity. To overcome this, privacy has to eventually become the default on public blockchains. + +### Identity protection + +Current identity management systems put personal information at risk. Zero-knowledge proofs can help individuals validate identity whilst protecting sensitive details. + +Zero-knowledge proofs are particularly useful in the context of [decentralized identity](/decentralized-identity/). Decentralized identity (also described as ‘self-sovereign identity’) gives the individual the ability to control access to personal identifiers. Proving your citizenship without revealing your tax ID or passport details is a good example of how zero-knowledge technology enables decentralized identity. + +### Proof of Humanity + +One of the most widely used examples of zero-knowledge proofs in action today is the [World ID protocol](https://world.org/blog/world/world-id-faqs), which can be thought of as “a global digital passport for the age of AI.” It allows people to prove they are unique individuals without revealing personal information. This is achieved through a device called the Orb, which scans a person's iris and generates an iris code. The iris code is checked and verified to confirm the person is a biologically unique human being. After verification, an identity commitment generated on the user’s device (and not linked to or derived from the biometric data) is added to a secure list on the blockchain. Then, whenever the user wants to prove they’re a verified human – whether to sign in, vote, or take other actions – they can generate a zero-knowledge proof that confirms their membership in the list. The beauty of using a zero-knowledge proof is that only one statement is revealed: this person is unique. Everything else stays private. + +World ID relies on the [Semaphore protocol](https://docs.semaphore.pse.dev/) developed by the [PSE team](https://pse.dev/) at the Ethereum Foundation. Semaphore is designed to be a lightweight yet powerful way to generate and verify zero-knowledge proofs. It lets users prove they're part of a group (in this case, verified humans) without showing which member of the group they are. Semaphore is also highly flexible, allowing groups to be created based on a wide range of criteria such as identity verification, participation in events, or ownership of credentials. + +### Authentication + +Using online services requires proving your identity and right to access those platforms. This often requires providing personal information, like names, email addresses, birth dates, and so on. You may also need to memorize long passwords or risk losing access. + +Zero-knowledge proofs, however, can simplify authentication for both platforms and users. Once a ZK-proof has been generated using public inputs (e.g., data attesting to the user's membership of the platform) and private inputs (e.g., the user's details), the user can simply present it to authenticate their identity when they need to access the service. This improves the experience for users and frees organizations from the need to store huge amounts of user information. + +### Verifiable computation + +Verifiable computation is another application of zero-knowledge technology for improving blockchain designs. Verifiable computing allows us to outsource computation to another entity while maintaining verifiable results. The entity submits the result along with a proof verifying that the program was executed correctly. + +Verifiable computation is **critical to improving processing speeds on blockchains** without reducing security. Understanding this requires knowing the differences in proposed solutions for scaling Ethereum. + +[Onchain scaling solutions](/developers/docs/scaling/#onchain-scaling), such as sharding, require extensive modification of the blockchain’s base layer. However, this approach is highly complex and errors in implementation can undermine Ethereum’s security model. + +[Offchain scaling solutions](/developers/docs/scaling/#offchain-scaling) don’t require redesigning the core Ethereum protocol. Instead they rely on an outsourced computation model to improve throughput on Ethereum’s base layer. + +Here’s how that works in practice: + +- Instead of processing every transaction, Ethereum offloads execution to a separate chain. + +- After processing transactions, the other chain returns the results to be applied to Ethereum’s state. + +The benefit here is that Ethereum doesn’t have to do any execution and only needs to apply results from outsourced computation to its state. This reduces network congestion and also improves transaction speeds (offchain protocols optimize for faster execution). + +The chain needs a way to validate offchain transactions without re-executing them, or else the value of offchain execution is lost. + +This is where verifiable computation comes into play. When a node executes a transaction outside of Ethereum, it submits a zero-knowledge proof to prove the correctness of offchain execution. This proof (called a [validity proof](/glossary/#validity-proof)) guarantees that a transaction is valid, allowing Ethereum to apply the result to its state—without waiting for anyone to dispute it. + +[Zero-knowledge rollups](/developers/docs/scaling/zk-rollups) and [validiums](/developers/docs/scaling/validium/) are two offchain scaling solutions that use validity proofs to provide secure scalability. These protocols execute thousands of transactions offchain and submit proofs for verification on Ethereum. Those results can be applied immediately once the proof is verified, allowing Ethereum to process more transactions without increasing computation on the base layer. + +### Reducing bribery and collusion in onchain voting + +Blockchain voting schemes have many favorable characteristics: they are fully auditable, secure against attacks, resistant to censorship, and free of geographical constraints. But even onchain voting schemes aren't immune to the problem of **collusion**. + +Defined as “coordinating to limit open competition by deceiving, defrauding, and misleading others,” collusion may take the form of a malicious actor influencing voting by offering bribes. For example, Alice might receive a bribe from Bob to vote for `option B` on a ballot even if she prefers `option A`. + +Bribery and collusion limit the effectiveness of any process that uses voting as a signaling mechanism (especially where users can prove how they voted). This can have significant consequences, especially where the votes are responsible for allocating scarce resources. + +For example, [quadratic funding mechanisms](https://www.radicalxchange.org/concepts/plural-funding/) rely on donations to measure preference for certain options among different public good projects. Each donation counts as a "vote" for a specific project, with projects that receive more votes getting more funds from the matching pool. + +Using onchain voting makes quadratic funding susceptible to collusion: blockchain transactions are public, so bribers can inspect a bribee’s onchain activity to see how they “voted”. This way quadratic funding ceases to be an effective means for allocating funds based on the aggregated preferences of the community. + +Fortunately, newer solutions such as MACI (Minimum Anti-Collusion Infrastructure) are using zero-knowledge proofs to make onchain voting (eg., quadratic funding mechanisms) resistant to bribery and collusion. MACI is a set of smart contracts and scripts that allow a central administrator (called a "coordinator") to aggregate votes and tally results _without_ revealing specifics on how each individual voted. Even so, it is still possible to verify that the votes were counted properly, or confirm that a particular individual participated in the voting round. + +#### How does MACI work with zero-knowledge proofs? + +At the start, the coordinator deploys the MACI contract on Ethereum, after which users can sign up for voting (by registering their public key in the smart contract). Users cast votes by sending messages encrypted with their public key to the smart contract (a valid vote must be signed with the most recent public key associated with the user's identity, among other criteria). Afterward, the coordinator processes all messages once the voting period ends, tallies the votes, and verifies the results onchain. + +In MACI, zero-knowledge proofs are used to ensure correctness of computation by making it impossible for the coordinator to incorrectly process votes and tally results. This is achieved by requiring the coordinator to generate ZK-SNARK proofs verifying that a) all messages were processed correctly b) the final result corresponds to the sum of all _valid_ votes. + +Thus, even without sharing a breakdown of votes per user (as is usually the case), MACI guarantees the integrity of results calculated during the tallying process. This feature is useful in reducing the effectiveness of basic collusion schemes. We can explore this possibility by using the previous example of Bob bribing Alice to vote for an option: + +- Alice registers to vote by sending their public key to a smart contract. +- Alice agrees to vote for `option B` in exchange for a bribe from Bob. +- Alice votes for `option B`. +- Alice secretly sends an encrypted transaction to change the public key associated with her identity. +- Alice sends another (encrypted) message to the smart contract voting for `option A` using the new public key. +- Alice shows Bob a transaction which shows she voted for `option B` (which is invalid since the public key is no longer associated with Alice's identity in the system) +- While processing messages, the coordinator skips Alice's vote for `option B` and counts only the vote for `option A`. Hence, Bob's attempt to collude with Alice and manipulate the onchain vote fails. + +Using MACI _does_ require trusting the coordinator not to collude with bribers or attempt to bribe voters themselves. The coordinator can decrypt user messages (necessary for creating the proof), so they can accurately verify how each person voted. + +But in cases where the coordinator remains honest, MACI represents a powerful tool for guaranteeing the sanctity of onchain voting. This explains its popularity among quadratic funding applications (e.g., [clr.fund](https://clr.fund/#/about/maci)) that rely heavily on the integrity of each individual's voting choices. + +[Learn more about MACI](https://privacy-scaling-explorations.github.io/maci/). + +## How do zero-knowledge proofs work? + +A zero-knowledge proof allows you to prove the truth of a statement without sharing the statement’s contents or revealing how you discovered the truth. To make this possible, zero-knowledge protocols rely on algorithms that take some data as input and return ‘true’ or ‘false’ as output. + +A zero-knowledge protocol must satisfy the following criteria: + +1. **Completeness**: If the input is valid, the zero-knowledge protocol always returns ‘true’. Hence, if the underlying statement is true, and the prover and verifier act honestly, the proof can be accepted. + +2. **Soundness**: If the input is invalid, it is theoretically impossible to fool the zero-knowledge protocol to return ‘true’. Hence, a lying prover cannot trick an honest verifier into believing an invalid statement is valid (except with a tiny margin of probability). + +3. **Zero-knowledge**: The verifier learns nothing about a statement beyond its validity or falsity (they have “zero knowledge” of the statement). This requirement also prevents the verifier from deriving the original input (the statement’s contents) from the proof. + +In basic form, a zero-knowledge proof is made up of three elements: **witness**, **challenge**, and **response**. + +- **Witness**: With a zero-knowledge proof, the prover wants to prove knowledge of some hidden information. The secret information is the “witness” to the proof, and the prover's assumed knowledge of the witness establishes a set of questions that can only be answered by a party with knowledge of the information. Thus, the prover starts the proving process by randomly choosing a question, calculating the answer, and sending it to the verifier. + +- **Challenge**: The verifier randomly picks another question from the set and asks the prover to answer it. + +- **Response**: The prover accepts the question, calculates the answer, and returns it to the verifier. The prover’s response allows the verifier to check if the former really has access to the witness. To ensure the prover isn’t guessing blindly and getting the correct answers by chance, the verifier picks more questions to ask. By repeating this interaction many times, the possibility of the prover faking knowledge of the witness drops significantly until the verifier is satisfied. + +The above describes the structure of an ‘interactive zero-knowledge proof’. Early zero-knowledge protocols used interactive proving, where verifying the validity of a statement required back-and-forth communication between provers and verifiers. + +A good example that illustrates how interactive proofs work is Jean-Jacques Quisquater’s famous [Ali Baba cave story](https://en.wikipedia.org/wiki/Zero-knowledge_proof#The_Ali_Baba_cave). In the story, Peggy (the prover) wants to prove to Victor (the verifier) that she knows the secret phrase to open a magic door without revealing the phrase. + +### Non-interactive zero-knowledge proofs + +While revolutionary, interactive proving had limited usefulness since it required the two parties to be available and interact repeatedly. Even if a verifier was convinced of a prover’s honesty, the proof would be unavailable for independent verification (computing a new proof required a new set of messages between the prover and verifier). + +To solve this problem, Manuel Blum, Paul Feldman, and Silvio Micali suggested the first [non-interactive zero-knowledge proofs](https://dl.acm.org/doi/10.1145/62212.62222) where the prover and verifier have a shared key. This allows the prover to demonstrate their knowledge of some information (i.e., witness) without providing the information itself. + +Unlike interactive proofs, noninteractive proofs required only one round of communication between participants (prover and verifier). The prover passes the secret information to a special algorithm to compute a zero-knowledge proof. This proof is sent to the verifier, who checks that the prover knows the secret information using another algorithm. + +Non-interactive proving reduces communication between prover and verifier, making ZK-proofs more efficient. Moreover, once a proof is generated, it is available for anyone else (with access to the shared key and verification algorithm) to verify. + +Non-interactive proofs represented a breakthrough for zero-knowledge technology and spurred the development of proving systems used today. We discuss these proof types below: + +### Types of zero-knowledge proofs + +#### ZK-SNARKs + +ZK-SNARK is an acronym for **Zero-Knowledge Succinct Non-Interactive Argument of Knowledge**. The ZK-SNARK protocol has the following qualities: + +- **Zero-knowledge**: A verifier can validate the integrity of a statement without knowing anything else about the statement. The only knowledge the verifier has of the statement is whether it is true or false. + +- **Succinct**: The zero-knowledge proof is smaller than the witness and can be verified quickly. + +- **Non-interactive**: The proof is ‘non-interactive’ because the prover and verifier only interact once, unlike interactive proofs that require multiple rounds of communication. + +- **Argument**: The proof satisfies the ‘soundness’ requirement, so cheating is extremely unlikely. + +- **(Of) Knowledge**: The zero-knowledge proof cannot be constructed without access to the secret information (witness). It is difficult, if not impossible, for a prover who doesn’t have the witness to compute a valid zero-knowledge proof. + +The ‘shared key’ mentioned earlier refers to public parameters that the prover and verifier agree to use in generating and verifying proofs. Generating the public parameters (collectively known as the Common Reference String (CRS)) is a sensitive operation because of its importance in the protocol’s security. If the entropy (randomness) used in generating the CRS gets into the hands of a dishonest prover, they can compute false proofs. + +[Multi-party computation (MPC)](https://en.wikipedia.org/wiki/Secure_multi-party_computation) is a way of reducing the risks in generating public parameters. Multiple parties participate in a [trusted setup ceremony](https://zkproof.org/2021/06/30/setup-ceremonies/amp/), where each person contributes some random values to generate the CRS. As long as one honest party destroys their portion of the entropy, the ZK-SNARK protocol retains computational soundness. + +Trusted setups require users to trust the participants in parameter-generation. However, the development of ZK-STARKs has enabled proving protocols that work with a non-trusted setup. + +#### ZK-STARKs + +ZK-STARK is an acronym for **Zero-Knowledge Scalable Transparent Argument of Knowledge**. ZK-STARKs are similar to ZK-SNARKs, except that they are: + +- **Scalable**: ZK-STARK is faster than ZK-SNARK at generating and verifying proofs when the size of the witness is larger. With STARK proofs, prover and verification times only slightly increase as the witness grows (SNARK prover and verifier times increase linearly with witness size). + +- **Transparent**: ZK-STARK relies on publicly verifiable randomness to generate public parameters for proving and verification instead of a trusted setup. Thus, they are more transparent compared to ZK-SNARKs. + +ZK-STARKs produce larger proofs than ZK-SNARKs meaning they generally have higher verification overheads. However, there are cases (such as proving large datasets) where ZK-STARKs may be more cost-effective than ZK-SNARKs. + +## Drawbacks of using zero-knowledge proofs + +### Hardware costs + +Generating zero-knowledge proofs involves very complex calculations best performed on specialized machines. As these machines are expensive, they are often out of the reach of regular individuals. Additionally, applications that want to use zero-knowledge technology must factor in hardware costs—which may increase costs for end-users. + +### Proof verification costs + +Verifying proofs also requires complex computation and increases the costs of implementing zero-knowledge technology in applications. This cost is particularly relevant in the context of proving computation. For example, ZK-rollups pay ~ 500,000 gas to verify a single ZK-SNARK proof on Ethereum, with ZK-STARKs requiring even higher fees. + +### Trust assumptions + +In ZK-SNARK, the Common Reference String (public parameters) is generated once and available for re-use to parties who wish to participate in the zero-knowledge protocol. Public parameters are created via a trusted setup ceremony, where participants are assumed to be honest. + +But there’s really no way for users to assess the honesty of participants and users have to take developers at their word. ZK-STARKs are free from trust assumptions since the randomness used in generating the string is publicly verifiable. In the meantime, researchers are working on non-trusted setups for ZK-SNARKs to increase the security of proving mechanisms. + +### Quantum computing threats + +ZK-SNARK uses elliptic curve cryptography for encryption. While the elliptic curve discrete logarithm problem is assumed to be intractable for now, the development of quantum computers could break this security model in the future. + +ZK-STARK is considered immune to the threat of quantum computing, as it only relies on collision-resistant hash functions for its security. Unlike public-private key pairings used in elliptic curve cryptography, collision-resistant hashing is more difficult for quantum computing algorithms to break. + +## Further reading + +- [Overview of use cases for zero-knowledge proofs](https://pse.dev/projects) — _Privacy and Scaling Explorations Team_ +- [SNARKs vs. STARKS vs. Recursive SNARKs](https://www.alchemy.com/overviews/snarks-vs-starks) — _Alchemy Overviews_ +- [A Zero-Knowledge Proof: Improving Privacy on a Blockchain](https://www.altoros.com/blog/zero-knowledge-proof-improving-privacy-for-a-blockchain/) — _Dmitry Lavrenov_ +- [zk-SNARKs — A Realistic Zero-Knowledge Example and Deep Dive](https://medium.com/coinmonks/zk-snarks-a-realistic-zero-knowledge-example-and-deep-dive-c5e6eaa7131c) — _Adam Luciano_ +- [ZK-STARKs — Create Verifiable Trust, even against Quantum Computers](https://medium.com/coinmonks/zk-starks-create-verifiable-trust-even-against-quantum-computers-dd9c6a2bb13d) — _Adam Luciano_ +- [An approximate introduction to how zk-SNARKs are possible](https://vitalik.eth.limo/general/2021/01/26/snarks.html) — _Vitalik Buterin_ +- [Why Zero Knowledge Proofs (ZKPs) is a Game Changer for Self-Sovereign Identity](https://frankiefab.hashnode.dev/why-zero-knowledge-proofs-zkps-is-a-game-changer-for-self-sovereign-identity) — _Franklin Ohaegbulam_ +- [EIP-7503 Explained: Enabling Private Transfers On Ethereum With ZK Proofs](https://research.2077.xyz/eip-7503-zero-knowledge-wormholes-for-private-ethereum-transactions#introduction) — _Emmanuel Awosika_ + +--- + + +--- + +This llms-full.txt file was generated at 2025-08-04T10:40:27.772Z. +It contains the complete content from Ethereum.org documentation to provide comprehensive context for AI systems. +For the latest version, see: https://ethereum.org/llms-full.txt diff --git a/public/llms.txt b/public/llms.txt index 4f592422c7d..609a60968b9 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -1,263 +1,392 @@ -# Ethereum.org - -> The official Ethereum website providing comprehensive education, resources, and community information about Ethereum - the decentralized world computer that enables smart contracts and decentralized applications. - -Ethereum.org is the primary educational hub for Ethereum, offering beginner-friendly explanations alongside advanced technical documentation. The site covers everything from basic concepts like "What is Ethereum?" to detailed developer guides, staking information, and the latest protocol research. - -## Learn - -### Basics -- [What is Ethereum?](https://ethereum.org/what-is-ethereum/): Introduction to Ethereum and its core concepts -- [What is Ether (ETH)?](https://ethereum.org/eth/): Understanding Ethereum's native cryptocurrency -- [Ethereum Wallets](https://ethereum.org/wallets/): Guide to storing and managing ETH and tokens -- [What is Web3?](https://ethereum.org/content/web3/index.md): Understanding the decentralized web -- [Smart Contracts](https://ethereum.org/content/smart-contracts/index.md): Introduction to programmable contracts - -### Advanced Topics -- [Gas and Fees](https://ethereum.org/gas/): Understanding transaction costs -- [Bridges](https://ethereum.org/content/bridges/index.md): Moving assets between blockchains -- [Zero Knowledge Proofs](https://ethereum.org/content/zero-knowledge-proofs/index.md): Privacy and scaling technology -- [Run a Node](https://ethereum.org/run-a-node/): Operating Ethereum infrastructure -- [Ethereum Security](https://ethereum.org/content/security/index.md): Protecting yourself in the ecosystem - -### Educational Resources -- [Quizzes](https://ethereum.org/quizzes/): Test your Ethereum knowledge -- [Glossary](https://ethereum.org/glossary/): Definitions of key terms - -## Use - -### Getting Started -- [Start with Crypto](https://ethereum.org/start/): Complete beginner's guide -- [Find a Wallet](https://ethereum.org/wallets/find-wallet/): Wallet selection tool -- [Get ETH](https://ethereum.org/get-eth/): How to acquire Ethereum -- [Decentralized Apps (DApps)](https://ethereum.org/dapps/): Applications built on Ethereum - -### Practical Guides -- [Guides Overview](https://ethereum.org/content/guides/index.md): Complete guide collection -- [How to Create an Ethereum Account](https://ethereum.org/content/guides/how-to-create-an-ethereum-account/index.md) -- [How to Use a Wallet](https://ethereum.org/content/guides/how-to-use-a-wallet/index.md): Managing your crypto wallet -- [How to Swap Tokens](https://ethereum.org/content/guides/how-to-swap-tokens/index.md): Exchanging tokens on decentralized exchanges -- [How to Use a Bridge](https://ethereum.org/content/guides/how-to-use-a-bridge/index.md): Moving assets between blockchains -- [How to Revoke Token Access](https://ethereum.org/content/guides/how-to-revoke-token-access/index.md): Managing token permissions - -### Use Cases -- [Stablecoins](https://ethereum.org/stablecoins/): Dollar-pegged cryptocurrencies -- [NFTs](https://ethereum.org/content/nft/index.md): Non-fungible tokens and digital ownership -- [DeFi](https://ethereum.org/content/defi/index.md): Decentralized finance applications -- [Payments](https://ethereum.org/content/payments/index.md): Using ETH for transactions -- [DAOs](https://ethereum.org/content/dao/index.md): Decentralized autonomous organizations - -### Emerging Applications -- [Decentralized Identity](https://ethereum.org/content/decentralized-identity/index.md): Self-sovereign identity -- [Decentralized Social Networks](https://ethereum.org/content/social-networks/index.md): Web3 social platforms -- [Decentralized Science (DeSci)](https://ethereum.org/content/desci/index.md): Research and collaboration -- [Regenerative Finance (ReFi)](https://ethereum.org/content/refi/index.md): Sustainable finance -- [AI Agents](https://ethereum.org/content/ai-agents/index.md): Autonomous AI on blockchain -- [Prediction Markets](https://ethereum.org/content/prediction-markets/index.md): Forecasting platforms -- [Real World Assets](https://ethereum.org/content/real-world-assets/index.md): Tokenizing physical assets +# Ethereum.org Documentation -### Staking -- [Staking Overview](https://ethereum.org/staking/): Earning rewards by validating -- [Solo Staking](https://ethereum.org/content/staking/solo/index.md): Run your own validator for maximum rewards and control -- [Staking as a Service](https://ethereum.org/content/staking/saas/index.md): Managed staking solutions with professional operators -- [Pooled Staking](https://ethereum.org/content/staking/pools/index.md): Stake with others to meet 32 ETH requirement - -### Layer 2 Networks -- [Layer 2 Introduction](https://ethereum.org/layer-2/): Scaling solutions overview -- [Explore Networks](https://ethereum.org/layer-2/networks/): Available L2 options -- [Learn about L2](https://ethereum.org/layer-2/learn/): Technical deep dive - -## Build - -### Developer Hub -- [Developer Home](https://ethereum.org/developers/): Central hub for builders -- [Developer Documentation](https://ethereum.org/developers/docs/): Technical documentation -- [Tutorials](https://ethereum.org/developers/tutorials/): Step-by-step guides -- [Learning Tools](https://ethereum.org/developers/learning-tools/): Interactive education -- [Local Development](https://ethereum.org/developers/local-environment/): Setup guides -- [Community Grants](https://ethereum.org/content/community/grants/index.md): Funding opportunities for developers - -### Documentation -- [Developer Documentation](https://ethereum.org/content/developers/docs/index.md): Complete technical reference - -#### Foundational Topics -- [Intro to Ethereum](https://ethereum.org/content/developers/docs/intro-to-ethereum/index.md): Developer-focused introduction -- [Intro to Ether](https://ethereum.org/content/developers/docs/intro-to-ether/index.md): Understanding ETH as a developer -- [Intro to DApps](https://ethereum.org/content/developers/docs/dapps/index.md): Decentralized applications -- [Web2 vs Web3](https://ethereum.org/content/developers/docs/web2-vs-web3/index.md): Comparing paradigms -- [Accounts](https://ethereum.org/content/developers/docs/accounts/index.md): Externally owned and contract accounts -- [Transactions](https://ethereum.org/content/developers/docs/transactions/index.md): State changes and execution -- [Blocks](https://ethereum.org/content/developers/docs/blocks/index.md): Transaction batching and ordering -- [Ethereum Virtual Machine (EVM)](https://ethereum.org/content/developers/docs/evm/index.md): The execution environment - - [EVM Opcodes](https://ethereum.org/content/developers/docs/evm/opcodes/index.md): Low-level instructions -- [Gas and Fees](https://ethereum.org/content/developers/docs/gas/index.md): Transaction costs and optimization -- [Nodes and Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/index.md): Network infrastructure - - [Running a Node](https://ethereum.org/content/developers/docs/nodes-and-clients/run-a-node/index.md): Setting up infrastructure - - [Client Diversity](https://ethereum.org/content/developers/docs/nodes-and-clients/client-diversity/index.md): Network resilience - - [Nodes as a Service](https://ethereum.org/content/developers/docs/nodes-and-clients/nodes-as-a-service/index.md): Managed node providers - - [Node Architecture](https://ethereum.org/content/developers/docs/nodes-and-clients/node-architecture/index.md): System design - - [Light Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/light-clients/index.md): Lightweight verification - - [Archive Nodes](https://ethereum.org/content/developers/docs/nodes-and-clients/archive-nodes/index.md): Full historical data - - [Bootnodes](https://ethereum.org/content/developers/docs/nodes-and-clients/bootnodes/index.md): Network discovery -- [Networks](https://ethereum.org/content/developers/docs/networks/index.md): Mainnet, testnets, and local networks -- [Consensus Mechanisms](https://ethereum.org/content/developers/docs/consensus-mechanisms/index.md): Network agreement - - [Proof of Stake](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/index.md): Current consensus mechanism - - [Gasper](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/gasper/index.md): Ethereum's consensus protocol - - [Weak Subjectivity](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md): Security assumptions - - [Attestations](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attestations/index.md): Validator voting mechanism - - [Rewards and Penalties](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md): Validator incentives - - [Attack and Defense](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md): Security considerations - - [Keys](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/keys/index.md): Validator key management - - [PoS vs PoW](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md): Consensus comparison - - [Block Proposal](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/block-proposal/index.md): Block creation process - - [PoS FAQs](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/faqs/index.md): Frequently asked questions - - [Proof of Work](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/index.md): Historical consensus mechanism - - [Mining](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/index.md): Block production process - - [Mining Algorithms](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md): Cryptographic algorithms - - [Dagger-Hashimoto](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md): Original algorithm - - [Ethash](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md): Production algorithm - - [Proof of Authority](https://ethereum.org/content/developers/docs/consensus-mechanisms/poa/index.md): Permissioned consensus - -#### Ethereum Stack -- [Ethereum Stack Overview](https://ethereum.org/content/developers/docs/ethereum-stack/index.md): Technology layers -- [Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/index.md): Self-executing programs - - [Smart Contract Languages](https://ethereum.org/content/developers/docs/smart-contracts/languages/index.md): Solidity, Vyper, and others - - [Smart Contract Anatomy](https://ethereum.org/content/developers/docs/smart-contracts/anatomy/index.md): Structure and components - - [Smart Contract Libraries](https://ethereum.org/content/developers/docs/smart-contracts/libraries/index.md): Reusable code - - [Testing Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/testing/index.md): Verification strategies - - [Compiling Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/compiling/index.md): Build process - - [Deploying Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/deploying/index.md): Deployment strategies - - [Verifying Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/verifying/index.md): Source code verification - - [Upgrading Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/upgrading/index.md): Contract upgrade patterns - - [Smart Contract Security](https://ethereum.org/content/developers/docs/smart-contracts/security/index.md): Security best practices - - [Formal Verification](https://ethereum.org/content/developers/docs/smart-contracts/formal-verification/index.md): Mathematical proof methods - - [Composability](https://ethereum.org/content/developers/docs/smart-contracts/composability/index.md): Contract interaction patterns -- [Development Networks](https://ethereum.org/content/developers/docs/development-networks/index.md): Local and test environments -- [Development Frameworks](https://ethereum.org/content/developers/docs/frameworks/index.md): Hardhat, Truffle, and others -- [Ethereum Client APIs](https://ethereum.org/developers/docs/apis/): Interacting with Ethereum - - [JavaScript APIs](https://ethereum.org/content/developers/docs/apis/javascript/index.md): Web3.js and ethers.js - - [Backend APIs](https://ethereum.org/content/developers/docs/apis/backend/index.md): Server-side integration - - [JSON-RPC](https://ethereum.org/content/developers/docs/apis/json-rpc/index.md): Protocol specification -- [Data and Analytics](https://ethereum.org/content/developers/docs/data-and-analytics/index.md): Blockchain data access - - [Block Explorers](https://ethereum.org/content/developers/docs/data-and-analytics/block-explorers/index.md): Data visualization tools -- [Storage](https://ethereum.org/content/developers/docs/storage/index.md): Data persistence strategies -- [IDEs](https://ethereum.org/content/developers/docs/ides/index.md): Development environments -- [Programming Languages](https://ethereum.org/content/developers/docs/programming-languages/index.md): Language-specific resources - - [Dart](https://ethereum.org/content/developers/docs/programming-languages/dart/index.md): Flutter and mobile development - - [Delphi](https://ethereum.org/content/developers/docs/programming-languages/delphi/index.md): Object Pascal programming - - [.NET](https://ethereum.org/content/developers/docs/programming-languages/dot-net/index.md): Microsoft .NET framework - - [Elixir](https://ethereum.org/content/developers/docs/programming-languages/elixir/index.md): Functional programming language - - [Go](https://ethereum.org/content/developers/docs/programming-languages/golang/index.md): Google's programming language - - [Java](https://ethereum.org/content/developers/docs/programming-languages/java/index.md): Enterprise application development - - [JavaScript](https://ethereum.org/content/developers/docs/programming-languages/javascript/index.md): Web3 development - - [Python](https://ethereum.org/content/developers/docs/programming-languages/python/index.md): Backend development - - [Ruby](https://ethereum.org/content/developers/docs/programming-languages/ruby/index.md): Web application development - - [Rust](https://ethereum.org/content/developers/docs/programming-languages/rust/index.md): Systems programming - -#### Advanced Topics -- [Bridges](https://ethereum.org/content/developers/docs/bridges/index.md): Cross-chain interoperability -- [Standards](https://ethereum.org/content/developers/docs/standards/index.md): Ethereum Request for Comments (ERCs) - - [Token Standards](https://ethereum.org/content/developers/docs/standards/tokens/index.md): Ethereum token specifications - - [ERC-20](https://ethereum.org/content/developers/docs/standards/tokens/erc-20/index.md): Fungible token standard - - [ERC-721](https://ethereum.org/content/developers/docs/standards/tokens/erc-721/index.md): Non-fungible token standard - - [ERC-1155](https://ethereum.org/content/developers/docs/standards/tokens/erc-1155/index.md): Multi-token standard -- [MEV](https://ethereum.org/content/developers/docs/mev/index.md): Maximal Extractable Value -- [Oracles](https://ethereum.org/content/developers/docs/oracles/index.md): External data integration -- [Scaling](https://ethereum.org/content/developers/docs/scaling/index.md): Layer 2 solutions - - [Optimistic Rollups](https://ethereum.org/content/developers/docs/scaling/optimistic-rollups/index.md): Fraud proof scaling - - [ZK Rollups](https://ethereum.org/content/developers/docs/scaling/zk-rollups/index.md): Zero-knowledge scaling - - [State Channels](https://ethereum.org/content/developers/docs/scaling/state-channels/index.md): Off-chain computation - - [Sidechains](https://ethereum.org/content/developers/docs/scaling/sidechains/index.md): Independent blockchains - - [Plasma](https://ethereum.org/content/developers/docs/scaling/plasma/index.md): Child chain scaling solution - - [Validium](https://ethereum.org/content/developers/docs/scaling/validium/index.md): Off-chain data availability -- [Data Availability](https://ethereum.org/content/developers/docs/data-availability/index.md): Data accessibility solutions - - [Blockchain Data Storage Strategies](https://ethereum.org/content/developers/docs/data-availability/blockchain-data-storage-strategies/index.md): Storage optimization methods -- [Networking Layer](https://ethereum.org/content/developers/docs/networking-layer/index.md): P2P networking - - [Network Addresses](https://ethereum.org/content/developers/docs/networking-layer/network-addresses/index.md): Node identification - - [Portal Network](https://ethereum.org/content/developers/docs/networking-layer/portal-network/index.md): Light client networking -- [Data Structures and Encoding](https://ethereum.org/content/developers/docs/data-structures-and-encoding/index.md): Low-level data formats - - [Patricia Merkle Trie](https://ethereum.org/content/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md): Ethereum's data structure - - [RLP](https://ethereum.org/content/developers/docs/data-structures-and-encoding/rlp/index.md): Recursive Length Prefix encoding - - [SSZ](https://ethereum.org/content/developers/docs/data-structures-and-encoding/ssz/index.md): Simple Serialize format - - [Web3 Secret Storage](https://ethereum.org/content/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md): Key storage specification - -#### Design Fundamentals -- [Design and UX](https://ethereum.org/content/developers/docs/design-and-ux/index.md): User experience for Web3 - - [Heuristics for Web3](https://ethereum.org/content/developers/docs/design-and-ux/heuristics-for-web3/index.md): UX design principles - - [DEX Design Best Practices](https://ethereum.org/content/developers/docs/design-and-ux/dex-design-best-practice/index.md): Decentralized exchange UX +> Ethereum.org is the official documentation and learning resource for Ethereum. It provides comprehensive guides, tutorials, and reference materials for developers, users, and community members to understand and interact with the Ethereum blockchain. -### Enterprise -- [Enterprise Ethereum](https://ethereum.org/enterprise/): Business adoption and use cases +## Overview + +Ethereum.org contains these primary sections: + +- [About](https://ethereum.org/content/about/index.md): Core information about Ethereum and the website +- [AI Agents](https://ethereum.org/content/ai-agents/index.md): Resources on AI agents in the Ethereum ecosystem +- [Bridges](https://ethereum.org/content/bridges/index.md): Cross-chain bridging documentation and guides +- [Community](https://ethereum.org/content/community/get-involved/index.md): Community resources, events, and involvement opportunities +- [Contributing](https://ethereum.org/content/contributing/index.md): Guidelines and resources for contributing to Ethereum.org +- [DeFi](https://ethereum.org/content/defi/index.md): Decentralized Finance resources and guides +- [Developers](https://ethereum.org/content/developers/docs/index.md): Comprehensive developer documentation and tutorials +- [Staking](https://ethereum.org/content/staking/solo/index.md): Everything about Ethereum staking + +## Core Resources -## Participate +### About Ethereum + +### 10years + +- [10years > Terms And Conditions](https://ethereum.org/content/10years/terms-and-conditions/index.md) + +### About + +- [About](https://ethereum.org/content/about/index.md) + +### Ai agents + +- [Ai Agents](https://ethereum.org/content/ai-agents/index.md) + +### Bridges + +- [Bridges](https://ethereum.org/content/bridges/index.md) ### Community -- [Community Hub](https://ethereum.org/community/): Get involved with Ethereum -- [Ethereum Online](https://ethereum.org/content/community/online/index.md): Virtual communities and platforms -- [Ethereum Events](https://ethereum.org/content/community/events/index.md): Meetups and conferences worldwide -- [Community Grants](https://ethereum.org/content/community/grants/index.md): Funding opportunities for ecosystem projects -- [Bug Bounty Program](https://ethereum.org/bug-bounty/): Security vulnerability rewards -- [Code of Conduct](https://ethereum.org/content/community/code-of-conduct/index.md): Community guidelines and expectations -- [Open Research](https://ethereum.org/content/community/research/index.md): Academic research and collaboration + +- [Community > Code Of Conduct](https://ethereum.org/content/community/code-of-conduct/index.md) +- [Community > Events](https://ethereum.org/content/community/events/index.md) +- [Community > Events > Organizing](https://ethereum.org/content/community/events/organizing/index.md) +- [Community > Get Involved](https://ethereum.org/content/community/get-involved/index.md) +- [Community > Grants](https://ethereum.org/content/community/grants/index.md) +- [Community > Language Resources](https://ethereum.org/content/community/language-resources/index.md) +- [Community > Online](https://ethereum.org/content/community/online/index.md) +- [Community > Research](https://ethereum.org/content/community/research/index.md) +- [Community > Support](https://ethereum.org/content/community/support/index.md) ### Contributing -- [Contributing Guide](https://ethereum.org/content/contributing/index.md): How to contribute to ethereum.org -- [Translation Program](https://ethereum.org/content/contributing/translation-program/index.md): Localization efforts and language support -- [Content Resources](https://ethereum.org/content/contributing/content-resources/index.md): Writing guidelines and standards -- [Design Contributions](https://ethereum.org/content/contributing/design/index.md): Design resources and style guides -### About -- [About Ethereum.org](https://ethereum.org/content/about/index.md): Mission, vision, and team -- [Ethereum Foundation](https://ethereum.org/content/foundation/index.md): Supporting organization and governance -- [Ethereum Brand Assets](https://ethereum.org/assets/): Official logos and branding guidelines - -### External Resources -- [Ethereum Foundation Blog](https://blog.ethereum.org/): Official announcements and updates -- [Ethereum Support Program (ESP)](https://esp.ethereum.foundation): Funding for ecosystem projects -- [Devcon](https://devcon.org/): Annual Ethereum developer conference - -## Research - -### Foundational Documents -- [Ethereum Whitepaper](https://ethereum.org/content/whitepaper/index.md): Original vision document by Vitalik Buterin -- [Ethereum Improvement Proposals (EIPs)](https://ethereum.org/content/eips/index.md): Protocol upgrade specifications -- [Ethereum History](https://ethereum.org/content/history/index.md): Timeline and key milestones - -### Protocol Development -- [Ethereum Roadmap](https://ethereum.org/roadmap/): Future development plans and priorities -- [Roadmap Security](https://ethereum.org/content/roadmap/security/index.md): Security improvements and cryptographic advances -- [Roadmap Scaling](https://ethereum.org/content/roadmap/scaling/index.md): Scalability solutions and layer 2 integration -- [Roadmap User Experience](https://ethereum.org/content/roadmap/user-experience/index.md): UX improvements and account abstraction -- [Roadmap Future-Proofing](https://ethereum.org/content/roadmap/future-proofing/index.md): Long-term sustainability and quantum resistance - -### Research Areas -- [Open Research](https://ethereum.org/content/community/research/index.md): Academic research and collaboration opportunities -- [Governance](https://ethereum.org/content/governance/index.md): Protocol governance and decision-making processes -- [Energy Consumption](https://ethereum.org/content/energy-consumption/index.md): Environmental impact and sustainability -- [Trillion Dollar Security](https://ethereum.org/trillion-dollar-security/): Ethereum security analysis and economics - -## Key Resources - -### Official Documentation -- [Developer Documentation](https://ethereum.org/content/developers/docs/index.md): Complete technical reference -- [Ethereum Improvement Proposals](https://ethereum.org/content/eips/index.md): Protocol specifications -- [Ethereum Whitepaper](https://ethereum.org/content/whitepaper/index.md): Original design document - -### Tools and Services -- [Wallet Finder](https://ethereum.org/wallets/find-wallet/): Wallet recommendation tool -- [DApp Browser](https://ethereum.org/dapps/): Decentralized application directory -- [Node Setup Guides](https://ethereum.org/run-a-node/): Infrastructure guides -- [Get ETH](https://ethereum.org/get-eth/): Acquisition methods - -### Educational Content -- [Beginner's Guide](https://ethereum.org/what-is-ethereum/): Start here for basics -- [Interactive Tutorials](https://ethereum.org/developers/tutorials/): Hands-on learning -- [Quiz Platform](https://ethereum.org/quizzes/): Knowledge assessment -- [Glossary](https://ethereum.org/glossary/): Comprehensive definitions - -## Legal and Policies - -### Terms and Policies -- [Privacy Policy](https://ethereum.org/content/privacy-policy/index.md): Data protection and privacy practices -- [Terms of Use](https://ethereum.org/content/terms-of-use/index.md): Website usage terms and conditions -- [Cookie Policy](https://ethereum.org/content/cookie-policy/index.md): Information about cookie usage and tracking +- [Contributing > Adding Desci Projects](https://ethereum.org/content/contributing/adding-desci-projects/index.md) +- [Contributing > Adding Developer Tools](https://ethereum.org/content/contributing/adding-developer-tools/index.md) +- [Contributing > Adding Exchanges](https://ethereum.org/content/contributing/adding-exchanges/index.md) +- [Contributing > Adding Glossary Terms](https://ethereum.org/content/contributing/adding-glossary-terms/index.md) +- [Contributing > Adding Layer 2s](https://ethereum.org/content/contributing/adding-layer-2s/index.md) +- [Contributing > Adding Products](https://ethereum.org/content/contributing/adding-products/index.md) +- [Contributing > Adding Resources](https://ethereum.org/content/contributing/adding-resources/index.md) +- [Contributing > Adding Staking Products](https://ethereum.org/content/contributing/adding-staking-products/index.md) +- [Contributing > Adding Wallets](https://ethereum.org/content/contributing/adding-wallets/index.md) +- [Contributing > Content Resources](https://ethereum.org/content/contributing/content-resources/index.md) +- [Contributing > Design Principles](https://ethereum.org/content/contributing/design-principles/index.md) +- [Contributing > Design > Adding Design Resources](https://ethereum.org/content/contributing/design/adding-design-resources/index.md) +- [Contributing > Design](https://ethereum.org/content/contributing/design/index.md) +- [Contributing](https://ethereum.org/content/contributing/index.md) +- [Contributing > Quizzes](https://ethereum.org/content/contributing/quizzes/index.md) +- [Contributing > Style Guide > Content Standardization](https://ethereum.org/content/contributing/style-guide/content-standardization/index.md) +- [Contributing > Style Guide](https://ethereum.org/content/contributing/style-guide/index.md) +- [Contributing > Translation Program > Content Buckets](https://ethereum.org/content/contributing/translation-program/content-buckets/index.md) +- [Contributing > Translation Program > Faq](https://ethereum.org/content/contributing/translation-program/faq/index.md) +- [Contributing > Translation Program > How To Translate](https://ethereum.org/content/contributing/translation-program/how-to-translate/index.md) +- [Contributing > Translation Program](https://ethereum.org/content/contributing/translation-program/index.md) +- [Contributing > Translation Program > Mission And Vision](https://ethereum.org/content/contributing/translation-program/mission-and-vision/index.md) +- [Contributing > Translation Program > Playbook](https://ethereum.org/content/contributing/translation-program/playbook/index.md) +- [Contributing > Translation Program > Resources](https://ethereum.org/content/contributing/translation-program/resources/index.md) +- [Contributing > Translation Program > Translatathon > Details](https://ethereum.org/content/contributing/translation-program/translatathon/details/index.md) +- [Contributing > Translation Program > Translatathon](https://ethereum.org/content/contributing/translation-program/translatathon/index.md) +- [Contributing > Translation Program > Translatathon > Terms And Conditions](https://ethereum.org/content/contributing/translation-program/translatathon/terms-and-conditions/index.md) +- [Contributing > Translation Program > Translatathon > Translatathon Hubs](https://ethereum.org/content/contributing/translation-program/translatathon/translatathon-hubs/index.md) +- [Contributing > Translation Program > Translators Guide](https://ethereum.org/content/contributing/translation-program/translators-guide/index.md) + +### Cookie policy + +- [Cookie Policy](https://ethereum.org/content/cookie-policy/index.md) + +### Dao + +- [Dao](https://ethereum.org/content/dao/index.md) + +### Decentralized identity + +- [Decentralized Identity](https://ethereum.org/content/decentralized-identity/index.md) + +### Defi + +- [Defi](https://ethereum.org/content/defi/index.md) + +### Desci + +- [Desci](https://ethereum.org/content/desci/index.md) + +### Developers + +- [Developers > Docs > Accounts](https://ethereum.org/content/developers/docs/accounts/index.md) +- [Developers > Docs > Apis > Backend](https://ethereum.org/content/developers/docs/apis/backend/index.md) +- [Developers > Docs > Apis > Javascript](https://ethereum.org/content/developers/docs/apis/javascript/index.md) +- [Developers > Docs > Apis > Json Rpc](https://ethereum.org/content/developers/docs/apis/json-rpc/index.md) +- [Developers > Docs > Blocks](https://ethereum.org/content/developers/docs/blocks/index.md) +- [Developers > Docs > Bridges](https://ethereum.org/content/developers/docs/bridges/index.md) +- [Developers > Docs > Consensus Mechanisms](https://ethereum.org/content/developers/docs/consensus-mechanisms/index.md) +- [Developers > Docs > Consensus Mechanisms > Poa](https://ethereum.org/content/developers/docs/consensus-mechanisms/poa/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Attack And Defense](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Attestations](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attestations/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Block Proposal](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/block-proposal/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Faqs](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/faqs/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Gasper](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/gasper/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Keys](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/keys/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Pos Vs Pow](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Rewards And Penalties](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md) +- [Developers > Docs > Consensus Mechanisms > Pos > Weak Subjectivity](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md) +- [Developers > Docs > Consensus Mechanisms > Pow](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/index.md) +- [Developers > Docs > Consensus Mechanisms > Pow > Mining](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/index.md) +- [Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms > Dagger Hashimoto](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md) +- [Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms > Ethash](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md) +- [Developers > Docs > Consensus Mechanisms > Pow > Mining > Mining Algorithms](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md) +- [Developers > Docs > Dapps](https://ethereum.org/content/developers/docs/dapps/index.md) +- [Developers > Docs > Data And Analytics > Block Explorers](https://ethereum.org/content/developers/docs/data-and-analytics/block-explorers/index.md) +- [Developers > Docs > Data And Analytics](https://ethereum.org/content/developers/docs/data-and-analytics/index.md) +- [Developers > Docs > Data Availability > Blockchain Data Storage Strategies](https://ethereum.org/content/developers/docs/data-availability/blockchain-data-storage-strategies/index.md) +- [Developers > Docs > Data Availability](https://ethereum.org/content/developers/docs/data-availability/index.md) +- [Developers > Docs > Data Structures And Encoding](https://ethereum.org/content/developers/docs/data-structures-and-encoding/index.md) +- [Developers > Docs > Data Structures And Encoding > Patricia Merkle Trie](https://ethereum.org/content/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md) +- [Developers > Docs > Data Structures And Encoding > Rlp](https://ethereum.org/content/developers/docs/data-structures-and-encoding/rlp/index.md) +- [Developers > Docs > Data Structures And Encoding > Ssz](https://ethereum.org/content/developers/docs/data-structures-and-encoding/ssz/index.md) +- [Developers > Docs > Data Structures And Encoding > Web3 Secret Storage](https://ethereum.org/content/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md) +- [Developers > Docs > Design And Ux > Dex Design Best Practice](https://ethereum.org/content/developers/docs/design-and-ux/dex-design-best-practice/index.md) +- [Developers > Docs > Design And Ux > Heuristics For Web3](https://ethereum.org/content/developers/docs/design-and-ux/heuristics-for-web3/index.md) +- [Developers > Docs > Design And Ux](https://ethereum.org/content/developers/docs/design-and-ux/index.md) +- [Developers > Docs > Development Networks](https://ethereum.org/content/developers/docs/development-networks/index.md) +- [Developers > Docs > Ethereum Stack](https://ethereum.org/content/developers/docs/ethereum-stack/index.md) +- [Developers > Docs > Evm](https://ethereum.org/content/developers/docs/evm/index.md) +- [Developers > Docs > Evm > Opcodes](https://ethereum.org/content/developers/docs/evm/opcodes/index.md) +- [Developers > Docs > Frameworks](https://ethereum.org/content/developers/docs/frameworks/index.md) +- [Developers > Docs > Gas](https://ethereum.org/content/developers/docs/gas/index.md) +- [Developers > Docs > Ides](https://ethereum.org/content/developers/docs/ides/index.md) +- [Developers > Docs](https://ethereum.org/content/developers/docs/index.md) +- [Developers > Docs > Intro To Ether](https://ethereum.org/content/developers/docs/intro-to-ether/index.md) +- [Developers > Docs > Intro To Ethereum](https://ethereum.org/content/developers/docs/intro-to-ethereum/index.md) +- [Developers > Docs > Mev](https://ethereum.org/content/developers/docs/mev/index.md) +- [Developers > Docs > Networking Layer](https://ethereum.org/content/developers/docs/networking-layer/index.md) +- [Developers > Docs > Networking Layer > Network Addresses](https://ethereum.org/content/developers/docs/networking-layer/network-addresses/index.md) +- [Developers > Docs > Networking Layer > Portal Network](https://ethereum.org/content/developers/docs/networking-layer/portal-network/index.md) +- [Developers > Docs > Networks](https://ethereum.org/content/developers/docs/networks/index.md) +- [Developers > Docs > Nodes And Clients > Archive Nodes](https://ethereum.org/content/developers/docs/nodes-and-clients/archive-nodes/index.md) +- [Developers > Docs > Nodes And Clients > Bootnodes](https://ethereum.org/content/developers/docs/nodes-and-clients/bootnodes/index.md) +- [Developers > Docs > Nodes And Clients > Client Diversity](https://ethereum.org/content/developers/docs/nodes-and-clients/client-diversity/index.md) +- [Developers > Docs > Nodes And Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/index.md) +- [Developers > Docs > Nodes And Clients > Light Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/light-clients/index.md) +- [Developers > Docs > Nodes And Clients > Node Architecture](https://ethereum.org/content/developers/docs/nodes-and-clients/node-architecture/index.md) +- [Developers > Docs > Nodes And Clients > Nodes As A Service](https://ethereum.org/content/developers/docs/nodes-and-clients/nodes-as-a-service/index.md) +- [Developers > Docs > Nodes And Clients > Run A Node](https://ethereum.org/content/developers/docs/nodes-and-clients/run-a-node/index.md) +- [Developers > Docs > Oracles](https://ethereum.org/content/developers/docs/oracles/index.md) +- [Developers > Docs > Programming Languages > Dart](https://ethereum.org/content/developers/docs/programming-languages/dart/index.md) +- [Developers > Docs > Programming Languages > Delphi](https://ethereum.org/content/developers/docs/programming-languages/delphi/index.md) +- [Developers > Docs > Programming Languages > Dot Net](https://ethereum.org/content/developers/docs/programming-languages/dot-net/index.md) +- [Developers > Docs > Programming Languages > Elixir](https://ethereum.org/content/developers/docs/programming-languages/elixir/index.md) +- [Developers > Docs > Programming Languages > Golang](https://ethereum.org/content/developers/docs/programming-languages/golang/index.md) +- [Developers > Docs > Programming Languages](https://ethereum.org/content/developers/docs/programming-languages/index.md) +- [Developers > Docs > Programming Languages > Java](https://ethereum.org/content/developers/docs/programming-languages/java/index.md) +- [Developers > Docs > Programming Languages > Javascript](https://ethereum.org/content/developers/docs/programming-languages/javascript/index.md) +- [Developers > Docs > Programming Languages > Python](https://ethereum.org/content/developers/docs/programming-languages/python/index.md) +- [Developers > Docs > Programming Languages > Ruby](https://ethereum.org/content/developers/docs/programming-languages/ruby/index.md) +- [Developers > Docs > Programming Languages > Rust](https://ethereum.org/content/developers/docs/programming-languages/rust/index.md) +- [Developers > Docs > Scaling](https://ethereum.org/content/developers/docs/scaling/index.md) +- [Developers > Docs > Scaling > Optimistic Rollups](https://ethereum.org/content/developers/docs/scaling/optimistic-rollups/index.md) +- [Developers > Docs > Scaling > Plasma](https://ethereum.org/content/developers/docs/scaling/plasma/index.md) +- [Developers > Docs > Scaling > Sidechains](https://ethereum.org/content/developers/docs/scaling/sidechains/index.md) +- [Developers > Docs > Scaling > State Channels](https://ethereum.org/content/developers/docs/scaling/state-channels/index.md) +- [Developers > Docs > Scaling > Validium](https://ethereum.org/content/developers/docs/scaling/validium/index.md) +- [Developers > Docs > Scaling > Zk Rollups](https://ethereum.org/content/developers/docs/scaling/zk-rollups/index.md) +- [Developers > Docs > Smart Contracts > Anatomy](https://ethereum.org/content/developers/docs/smart-contracts/anatomy/index.md) +- [Developers > Docs > Smart Contracts > Compiling](https://ethereum.org/content/developers/docs/smart-contracts/compiling/index.md) +- [Developers > Docs > Smart Contracts > Composability](https://ethereum.org/content/developers/docs/smart-contracts/composability/index.md) +- [Developers > Docs > Smart Contracts > Deploying](https://ethereum.org/content/developers/docs/smart-contracts/deploying/index.md) +- [Developers > Docs > Smart Contracts > Formal Verification](https://ethereum.org/content/developers/docs/smart-contracts/formal-verification/index.md) +- [Developers > Docs > Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/index.md) +- [Developers > Docs > Smart Contracts > Languages](https://ethereum.org/content/developers/docs/smart-contracts/languages/index.md) +- [Developers > Docs > Smart Contracts > Libraries](https://ethereum.org/content/developers/docs/smart-contracts/libraries/index.md) +- [Developers > Docs > Smart Contracts > Security](https://ethereum.org/content/developers/docs/smart-contracts/security/index.md) +- [Developers > Docs > Smart Contracts > Testing](https://ethereum.org/content/developers/docs/smart-contracts/testing/index.md) +- [Developers > Docs > Smart Contracts > Upgrading](https://ethereum.org/content/developers/docs/smart-contracts/upgrading/index.md) +- [Developers > Docs > Smart Contracts > Verifying](https://ethereum.org/content/developers/docs/smart-contracts/verifying/index.md) +- [Developers > Docs > Standards](https://ethereum.org/content/developers/docs/standards/index.md) +- [Developers > Docs > Standards > Tokens > Erc 1155](https://ethereum.org/content/developers/docs/standards/tokens/erc-1155/index.md) +- [Developers > Docs > Standards > Tokens > Erc 20](https://ethereum.org/content/developers/docs/standards/tokens/erc-20/index.md) +- [Developers > Docs > Standards > Tokens > Erc 223](https://ethereum.org/content/developers/docs/standards/tokens/erc-223/index.md) +- [Developers > Docs > Standards > Tokens > Erc 4626](https://ethereum.org/content/developers/docs/standards/tokens/erc-4626/index.md) +- [Developers > Docs > Standards > Tokens > Erc 721](https://ethereum.org/content/developers/docs/standards/tokens/erc-721/index.md) +- [Developers > Docs > Standards > Tokens > Erc 777](https://ethereum.org/content/developers/docs/standards/tokens/erc-777/index.md) +- [Developers > Docs > Standards > Tokens](https://ethereum.org/content/developers/docs/standards/tokens/index.md) +- [Developers > Docs > Storage](https://ethereum.org/content/developers/docs/storage/index.md) +- [Developers > Docs > Transactions](https://ethereum.org/content/developers/docs/transactions/index.md) +- [Developers > Docs > Web2 Vs Web3](https://ethereum.org/content/developers/docs/web2-vs-web3/index.md) +- [Developers > Tutorials > A Developers Guide To Ethereum Part One](https://ethereum.org/content/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md) +- [Developers > Tutorials > All You Can Cache](https://ethereum.org/content/developers/tutorials/all-you-can-cache/index.md) +- [Developers > Tutorials > Calling A Smart Contract From Javascript](https://ethereum.org/content/developers/tutorials/calling-a-smart-contract-from-javascript/index.md) +- [Developers > Tutorials > Creating A Wagmi Ui For Your Contract](https://ethereum.org/content/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md) +- [Developers > Tutorials > Deploying Your First Smart Contract](https://ethereum.org/content/developers/tutorials/deploying-your-first-smart-contract/index.md) +- [Developers > Tutorials > Develop And Test Dapps With A Multi Client Local Eth Testnet](https://ethereum.org/content/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md) +- [Developers > Tutorials > Downsizing Contracts To Fight The Contract Size Limit](https://ethereum.org/content/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md) +- [Developers > Tutorials > Eip 1271 Smart Contract Signatures](https://ethereum.org/content/developers/tutorials/eip-1271-smart-contract-signatures/index.md) +- [Developers > Tutorials > Erc 721 Vyper Annotated Code](https://ethereum.org/content/developers/tutorials/erc-721-vyper-annotated-code/index.md) +- [Developers > Tutorials > Erc20 Annotated Code](https://ethereum.org/content/developers/tutorials/erc20-annotated-code/index.md) +- [Developers > Tutorials > Erc20 With Safety Rails](https://ethereum.org/content/developers/tutorials/erc20-with-safety-rails/index.md) +- [Developers > Tutorials > Ethereum For Web2 Auth](https://ethereum.org/content/developers/tutorials/ethereum-for-web2-auth/index.md) +- [Developers > Tutorials > Getting Started With Ethereum Development Using Alchemy](https://ethereum.org/content/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md) +- [Developers > Tutorials > Guide To Smart Contract Security Tools](https://ethereum.org/content/developers/tutorials/guide-to-smart-contract-security-tools/index.md) +- [Developers > Tutorials > Hello World Smart Contract Fullstack](https://ethereum.org/content/developers/tutorials/hello-world-smart-contract-fullstack/index.md) +- [Developers > Tutorials > Hello World Smart Contract](https://ethereum.org/content/developers/tutorials/hello-world-smart-contract/index.md) +- [Developers > Tutorials > How To Implement An Erc721 Market](https://ethereum.org/content/developers/tutorials/how-to-implement-an-erc721-market/index.md) +- [Developers > Tutorials > How To Mint An Nft](https://ethereum.org/content/developers/tutorials/how-to-mint-an-nft/index.md) +- [Developers > Tutorials > How To Mock Solidity Contracts For Testing](https://ethereum.org/content/developers/tutorials/how-to-mock-solidity-contracts-for-testing/index.md) +- [Developers > Tutorials > How To Use Echidna To Test Smart Contracts](https://ethereum.org/content/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/index.md) +- [Developers > Tutorials > How To Use Manticore To Find Smart Contract Bugs](https://ethereum.org/content/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/index.md) +- [Developers > Tutorials > How To Use Slither To Find Smart Contract Bugs](https://ethereum.org/content/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/index.md) +- [Developers > Tutorials > How To Use Tellor As Your Oracle](https://ethereum.org/content/developers/tutorials/how-to-use-tellor-as-your-oracle/index.md) +- [Developers > Tutorials > How To View Nft In Metamask](https://ethereum.org/content/developers/tutorials/how-to-view-nft-in-metamask/index.md) +- [Developers > Tutorials > How To Write And Deploy An Nft](https://ethereum.org/content/developers/tutorials/how-to-write-and-deploy-an-nft/index.md) +- [Developers > Tutorials > Interact With Other Contracts From Solidity](https://ethereum.org/content/developers/tutorials/interact-with-other-contracts-from-solidity/index.md) +- [Developers > Tutorials > Ipfs Decentralized Ui](https://ethereum.org/content/developers/tutorials/ipfs-decentralized-ui/index.md) +- [Developers > Tutorials > Kickstart Your Dapp Frontend Development With Create Eth App](https://ethereum.org/content/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/index.md) +- [Developers > Tutorials > Learn Foundational Ethereum Topics With Sql](https://ethereum.org/content/developers/tutorials/learn-foundational-ethereum-topics-with-sql/index.md) +- [Developers > Tutorials > Logging Events Smart Contracts](https://ethereum.org/content/developers/tutorials/logging-events-smart-contracts/index.md) +- [Developers > Tutorials > Merkle Proofs For Offline Data Integrity](https://ethereum.org/content/developers/tutorials/merkle-proofs-for-offline-data-integrity/index.md) +- [Developers > Tutorials > Monitoring Geth With Influxdb And Grafana](https://ethereum.org/content/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/index.md) +- [Developers > Tutorials > Nft Minter](https://ethereum.org/content/developers/tutorials/nft-minter/index.md) +- [Developers > Tutorials > Optimism Std Bridge Annotated Code](https://ethereum.org/content/developers/tutorials/optimism-std-bridge-annotated-code/index.md) +- [Developers > Tutorials > Reverse Engineering A Contract](https://ethereum.org/content/developers/tutorials/reverse-engineering-a-contract/index.md) +- [Developers > Tutorials > Run Node Raspberry Pi](https://ethereum.org/content/developers/tutorials/run-node-raspberry-pi/index.md) +- [Developers > Tutorials > Scam Token Tricks](https://ethereum.org/content/developers/tutorials/scam-token-tricks/index.md) +- [Developers > Tutorials > Secret State](https://ethereum.org/content/developers/tutorials/secret-state/index.md) +- [Developers > Tutorials > Secure Development Workflow](https://ethereum.org/content/developers/tutorials/secure-development-workflow/index.md) +- [Developers > Tutorials > Send Token Ethersjs](https://ethereum.org/content/developers/tutorials/send-token-ethersjs/index.md) +- [Developers > Tutorials > Sending Transactions Using Web3 And Alchemy](https://ethereum.org/content/developers/tutorials/sending-transactions-using-web3-and-alchemy/index.md) +- [Developers > Tutorials > Server Components](https://ethereum.org/content/developers/tutorials/server-components/index.md) +- [Developers > Tutorials > Set Up Web3js To Use Ethereum In Javascript](https://ethereum.org/content/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/index.md) +- [Developers > Tutorials > Short Abi](https://ethereum.org/content/developers/tutorials/short-abi/index.md) +- [Developers > Tutorials > Smart Contract Security Guidelines](https://ethereum.org/content/developers/tutorials/smart-contract-security-guidelines/index.md) +- [Developers > Tutorials > Testing Erc 20 Tokens With Waffle](https://ethereum.org/content/developers/tutorials/testing-erc-20-tokens-with-waffle/index.md) +- [Developers > Tutorials > The Graph Fixing Web3 Data Querying](https://ethereum.org/content/developers/tutorials/the-graph-fixing-web3-data-querying/index.md) +- [Developers > Tutorials > Token Integration Checklist](https://ethereum.org/content/developers/tutorials/token-integration-checklist/index.md) +- [Developers > Tutorials > Transfers And Approval Of Erc 20 Tokens From A Solidity Smart Contract](https://ethereum.org/content/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/index.md) +- [Developers > Tutorials > Understand The Erc 20 Token Smart Contract](https://ethereum.org/content/developers/tutorials/understand-the-erc-20-token-smart-contract/index.md) +- [Developers > Tutorials > Uniswap V2 Annotated Code](https://ethereum.org/content/developers/tutorials/uniswap-v2-annotated-code/index.md) +- [Developers > Tutorials > Using Websockets](https://ethereum.org/content/developers/tutorials/using-websockets/index.md) +- [Developers > Tutorials > Waffle Dynamic Mocking And Testing Calls](https://ethereum.org/content/developers/tutorials/waffle-dynamic-mocking-and-testing-calls/index.md) +- [Developers > Tutorials > Waffle Say Hello World With Hardhat And Ethers](https://ethereum.org/content/developers/tutorials/waffle-say-hello-world-with-hardhat-and-ethers/index.md) +- [Developers > Tutorials > Waffle Test Simple Smart Contract](https://ethereum.org/content/developers/tutorials/waffle-test-simple-smart-contract/index.md) +- [Developers > Tutorials > Yellow Paper Evm](https://ethereum.org/content/developers/tutorials/yellow-paper-evm/index.md) + +### Eips + +- [Eips](https://ethereum.org/content/eips/index.md) + +### Energy consumption + +- [Energy Consumption](https://ethereum.org/content/energy-consumption/index.md) + +### Enterprise + +- [Enterprise > Use Cases](https://ethereum.org/content/enterprise/use-cases/index.md) + +### Eth + +- [Eth > Supply](https://ethereum.org/content/eth/supply/index.md) + +### Foundation + +- [Foundation](https://ethereum.org/content/foundation/index.md) + +### Glossary + +- [Glossary](https://ethereum.org/content/glossary/index.md) + +### Governance + +- [Governance](https://ethereum.org/content/governance/index.md) + +### Guides + +- [Guides > How To Create An Ethereum Account](https://ethereum.org/content/guides/how-to-create-an-ethereum-account/index.md) +- [Guides > How To Id Scam Tokens](https://ethereum.org/content/guides/how-to-id-scam-tokens/index.md) +- [Guides > How To Revoke Token Access](https://ethereum.org/content/guides/how-to-revoke-token-access/index.md) +- [Guides > How To Swap Tokens](https://ethereum.org/content/guides/how-to-swap-tokens/index.md) +- [Guides > How To Use A Bridge](https://ethereum.org/content/guides/how-to-use-a-bridge/index.md) +- [Guides > How To Use A Wallet](https://ethereum.org/content/guides/how-to-use-a-wallet/index.md) +- [Guides](https://ethereum.org/content/guides/index.md) + +### History + +- [History](https://ethereum.org/content/history/index.md) + +### Nft + +- [Nft](https://ethereum.org/content/nft/index.md) + +### Payments + +- [Payments](https://ethereum.org/content/payments/index.md) + +### Prediction markets + +- [Prediction Markets](https://ethereum.org/content/prediction-markets/index.md) + +### Privacy policy + +- [Privacy Policy](https://ethereum.org/content/privacy-policy/index.md) + +### Real world assets + +- [Real World Assets](https://ethereum.org/content/real-world-assets/index.md) + +### Refi + +- [Refi](https://ethereum.org/content/refi/index.md) + +### Roadmap + +- [Roadmap > Account Abstraction](https://ethereum.org/content/roadmap/account-abstraction/index.md) +- [Roadmap > Beacon Chain](https://ethereum.org/content/roadmap/beacon-chain/index.md) +- [Roadmap > Danksharding](https://ethereum.org/content/roadmap/danksharding/index.md) +- [Roadmap > Dencun](https://ethereum.org/content/roadmap/dencun/index.md) +- [Roadmap > Future Proofing](https://ethereum.org/content/roadmap/future-proofing/index.md) +- [Roadmap > Merge](https://ethereum.org/content/roadmap/merge/index.md) +- [Roadmap > Merge > Issuance](https://ethereum.org/content/roadmap/merge/issuance/index.md) +- [Roadmap > Pbs](https://ethereum.org/content/roadmap/pbs/index.md) +- [Roadmap > Pectra > 7702](https://ethereum.org/content/roadmap/pectra/7702/index.md) +- [Roadmap > Pectra](https://ethereum.org/content/roadmap/pectra/index.md) +- [Roadmap > Pectra > Maxeb](https://ethereum.org/content/roadmap/pectra/maxeb/index.md) +- [Roadmap > Scaling](https://ethereum.org/content/roadmap/scaling/index.md) +- [Roadmap > Secret Leader Election](https://ethereum.org/content/roadmap/secret-leader-election/index.md) +- [Roadmap > Security](https://ethereum.org/content/roadmap/security/index.md) +- [Roadmap > Single Slot Finality](https://ethereum.org/content/roadmap/single-slot-finality/index.md) +- [Roadmap > Statelessness](https://ethereum.org/content/roadmap/statelessness/index.md) +- [Roadmap > User Experience](https://ethereum.org/content/roadmap/user-experience/index.md) +- [Roadmap > Verkle Trees](https://ethereum.org/content/roadmap/verkle-trees/index.md) + +### Security + +- [Security](https://ethereum.org/content/security/index.md) + +### Smart contracts + +- [Smart Contracts](https://ethereum.org/content/smart-contracts/index.md) + +### Social networks + +- [Social Networks](https://ethereum.org/content/social-networks/index.md) + +### Staking + +- [Staking > Dvt](https://ethereum.org/content/staking/dvt/index.md) +- [Staking > Pools](https://ethereum.org/content/staking/pools/index.md) +- [Staking > Saas](https://ethereum.org/content/staking/saas/index.md) +- [Staking > Solo](https://ethereum.org/content/staking/solo/index.md) +- [Staking > Withdrawals](https://ethereum.org/content/staking/withdrawals/index.md) + +### Terms of use + +- [Terms Of Use](https://ethereum.org/content/terms-of-use/index.md) + +### Web3 + +- [Web3](https://ethereum.org/content/web3/index.md) + +### Whitepaper + +- [Whitepaper](https://ethereum.org/content/whitepaper/index.md) + +### Wrapped eth + +- [Wrapped Eth](https://ethereum.org/content/wrapped-eth/index.md) + +### Zero knowledge proofs + +- [Zero Knowledge Proofs](https://ethereum.org/content/zero-knowledge-proofs/index.md) + +--- + +This document was rendered at 2025-08-04T10:40:27.725Z. +For the latest version of this document, see [https://ethereum.org/llms.txt](https://ethereum.org/llms.txt). diff --git a/src/scripts/generate-llms-files.js b/src/scripts/generate-llms-files.js new file mode 100644 index 00000000000..64da85b86f2 --- /dev/null +++ b/src/scripts/generate-llms-files.js @@ -0,0 +1,341 @@ +const fs = require("fs") +const path = require("path") + +// ============================================================================= +// CONFIGURATION +// ============================================================================= + +const CONFIG = { + baseUrl: "https://ethereum.org", + contentDir: "public/content", + outputDir: "public", + tempFile: "all_content_files.txt", +} + +// ============================================================================= +// UTILITY FUNCTIONS +// ============================================================================= + +function log(message, type = "info") { + const prefix = { + info: "📝", + success: "✅", + error: "❌", + warning: "⚠️", + step: "🚀", + } + console.log(`${prefix[type]} ${message}`) +} + +function createTitle(relativePath) { + const pathParts = relativePath.split("/") + let title = pathParts[pathParts.length - 1] + .replace(/\.md$/, "") + .replace(/index$/, "") + + if (!title || title === "") { + title = pathParts[pathParts.length - 2] || pathParts[0] + } + + // Create breadcrumb for nested content + if (pathParts.length > 2) { + const breadcrumb = pathParts.slice(0, -1).join(" > ").replace(/-/g, " ") + title = `${breadcrumb}` + } else if (pathParts.length === 2) { + title = pathParts[0] + } + + return title.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()) +} + +function readMarkdownContent(filePath) { + try { + if (!fs.existsSync(filePath)) { + return null + } + + let markdownContent = fs.readFileSync(filePath, "utf-8") + + // Remove frontmatter (YAML between --- blocks) + markdownContent = markdownContent.replace(/^---[\s\S]*?---\n/, "") + + // Clean up any remaining metadata or special formatting + markdownContent = markdownContent + .replace(/import\s+.*from.*['"].*['"];?\n/g, "") // Remove import statements + .replace(/<[^>]+>/g, "") // Remove HTML tags + .replace(/\{[^}]+\}/g, "") // Remove JSX/React components + .trim() + + return markdownContent + } catch (error) { + log(`Error reading ${filePath}: ${error.message}`, "error") + return null + } +} + +// ============================================================================= +// MAIN FUNCTIONS +// ============================================================================= + +function findMarkdownFiles(dir, baseDir = dir) { + const files = [] + + if (!fs.existsSync(dir)) { + log(`Directory ${dir} does not exist`, "error") + return files + } + + const items = fs.readdirSync(dir) + + for (const item of items) { + const fullPath = path.join(dir, item) + const stat = fs.statSync(fullPath) + + if (stat.isDirectory()) { + // Skip certain directories including translations + if ( + item === "node_modules" || + item === ".git" || + item === ".next" || + item === "dist" || + item === "translations" + ) { + continue + } + + // Recursively search subdirectories + files.push(...findMarkdownFiles(fullPath, baseDir)) + } else if (stat.isFile() && item.endsWith(".md")) { + files.push(fullPath) + } + } + + return files +} + +function generateLlmsTxt(files) { + log("Generating llms.txt (URL directory)", "step") + + // Group files by category + const categorizedFiles = {} + + files.forEach((filePath) => { + const relativePath = filePath.replace(CONFIG.contentDir + "/", "") + const pathParts = relativePath.split("/") + const mainCategory = pathParts[0] + + if (!categorizedFiles[mainCategory]) { + categorizedFiles[mainCategory] = [] + } + + categorizedFiles[mainCategory].push({ + filePath, + relativePath, + pathParts, + }) + }) + + // Start building content + let content = `# Ethereum.org Documentation + +> Ethereum.org is the official documentation and learning resource for Ethereum. It provides comprehensive guides, tutorials, and reference materials for developers, users, and community members to understand and interact with the Ethereum blockchain. + +## Overview + +Ethereum.org contains these primary sections: + +- [About](https://ethereum.org/content/about/index.md): Core information about Ethereum and the website +- [AI Agents](https://ethereum.org/content/ai-agents/index.md): Resources on AI agents in the Ethereum ecosystem +- [Bridges](https://ethereum.org/content/bridges/index.md): Cross-chain bridging documentation and guides +- [Community](https://ethereum.org/content/community/get-involved/index.md): Community resources, events, and involvement opportunities +- [Contributing](https://ethereum.org/content/contributing/index.md): Guidelines and resources for contributing to Ethereum.org +- [DeFi](https://ethereum.org/content/defi/index.md): Decentralized Finance resources and guides +- [Developers](https://ethereum.org/content/developers/docs/index.md): Comprehensive developer documentation and tutorials +- [Staking](https://ethereum.org/content/staking/solo/index.md): Everything about Ethereum staking + +## Core Resources + +### About Ethereum + +` + + // Process main categories (excluding translations to keep file manageable) + Object.keys(categorizedFiles) + .filter((category) => category !== "translations") // Exclude all translations + .sort() + .forEach((category) => { + const displayName = + category.charAt(0).toUpperCase() + category.slice(1).replace(/-/g, " ") + content += `### ${displayName}\n\n` + + // Sort files within category - prioritize index files + const sortedFiles = categorizedFiles[category].sort((a, b) => { + if ( + a.relativePath.endsWith("index.md") && + !b.relativePath.endsWith("index.md") + ) + return -1 + if ( + !a.relativePath.endsWith("index.md") && + b.relativePath.endsWith("index.md") + ) + return 1 + return a.relativePath.localeCompare(b.relativePath) + }) + + sortedFiles.forEach((fileInfo) => { + const title = createTitle(fileInfo.relativePath) + const url = `${CONFIG.baseUrl}/content/${fileInfo.relativePath}` + content += `- [${title}](${url})\n` + }) + + content += `\n` + }) + + // Add footer + content += `---\n\n` + content += `This document was rendered at ${new Date().toISOString()}.\n` + content += `For the latest version of this document, see [https://ethereum.org/llms.txt](https://ethereum.org/llms.txt).\n` + + return content +} + +function generateLlmsFullTxt(files) { + log("Generating llms-full.txt (full content)", "step") + + // Start building content + let content = `# Ethereum.org Documentation (Full Content) + +> Ethereum.org is the official documentation and learning resource for Ethereum. This file contains the complete content of all documentation pages, making it easy for AI systems to access comprehensive information about Ethereum in a single file. + +## Overview + +This llms-full.txt file contains the complete text content from documentation pages on Ethereum.org, including: + +- Core Ethereum concepts and introduction materials +- Comprehensive developer documentation and tutorials +- Technical specifications and standards +- Staking guides and validator information +- Community resources and contribution guidelines +- Roadmap and future development plans +- Use case examples and applications + +The content is organized by main topics and includes the full text of each page for complete context. + +--- + +` + + // Group files by category to provide some structure + const categorizedFiles = {} + files.forEach((filePath) => { + const relativePath = filePath.replace(CONFIG.contentDir + "/", "") + const category = relativePath.split("/")[0] + if (!categorizedFiles[category]) { + categorizedFiles[category] = [] + } + categorizedFiles[category].push({ + filePath, + relativePath, + }) + }) + + log("Processing all markdown files by category...", "info") + + Object.keys(categorizedFiles) + .filter((category) => category !== "translations") // Exclude all translations for English-only content + .sort() + .forEach((category) => { + content += `# ${category.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())}\n\n` + + categorizedFiles[category].forEach((fileInfo) => { + const markdownContent = readMarkdownContent(fileInfo.filePath) + if (markdownContent) { + const title = createTitle(fileInfo.relativePath) + content += `## ${title}\n\n` + content += `${markdownContent}\n\n---\n\n` + } + }) + }) + + // Add footer + content += `\n---\n\nThis llms-full.txt file was generated at ${new Date().toISOString()}.\n` + content += `It contains the complete content from Ethereum.org documentation to provide comprehensive context for AI systems.\n` + content += `For the latest version, see: https://ethereum.org/llms-full.txt\n` + + return content +} + +function main() { + try { + console.log("============================================================") + console.log("🌟 ETHEREUM.ORG LLMS FILES GENERATOR") + console.log("============================================================") + console.log( + "This script will generate both llms.txt and llms-full.txt files" + ) + console.log("and place them in the public directory.") + console.log("") + + log("Starting generation...", "step") + + // Check prerequisites + if (!fs.existsSync(CONFIG.contentDir)) { + throw new Error(`Content directory not found: ${CONFIG.contentDir}`) + } + + const markdownFiles = findMarkdownFiles(CONFIG.contentDir) + markdownFiles.sort() + + log(`Found ${markdownFiles.length} markdown files`, "success") + + // Generate files + const llmsTxt = generateLlmsTxt(markdownFiles) + const llmsFullTxt = generateLlmsFullTxt(markdownFiles) + + // Ensure public directory exists + const publicDir = path.join(process.cwd(), CONFIG.outputDir) + if (!fs.existsSync(publicDir)) { + fs.mkdirSync(publicDir, { recursive: true }) + } + + // Write files + const llmsTxtPath = path.join(publicDir, "llms.txt") + const llmsFullTxtPath = path.join(publicDir, "llms-full.txt") + + fs.writeFileSync(llmsTxtPath, llmsTxt) + fs.writeFileSync(llmsFullTxtPath, llmsFullTxt) + + log( + `Generated llms.txt: ${(Buffer.byteLength(llmsTxt, "utf-8") / 1024).toFixed(2)} KB`, + "success" + ) + log( + `Generated llms-full.txt: ${(Buffer.byteLength(llmsFullTxt, "utf-8") / 1024 / 1024).toFixed(2)} MB`, + "success" + ) + + console.log("") + console.log("============================================================") + console.log("🎉 GENERATION COMPLETE!") + console.log("============================================================") + console.log("✅ Files created:") + console.log(` - ${llmsTxtPath}`) + console.log(` - ${llmsFullTxtPath}`) + console.log("") + console.log("🌐 URLs will be available at:") + console.log(" - https://ethereum.org/llms.txt") + console.log(" - https://ethereum.org/llms-full.txt") + console.log("============================================================") + } catch (error) { + log(`Error: ${error.message}`, "error") + console.error(error) + process.exit(1) + } +} + +if (require.main === module) { + main() +} + +module.exports = { generateLlmsTxt, generateLlmsFullTxt, findMarkdownFiles }