├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── tutorial_request.md │ └── tutorial_issue.md ├── workflows │ ├── secrets_scanner.yaml │ └── checks.yml └── PULL_REQUEST_TEMPLATE.md ├── tutorials ├── zksync-cli-quickstart │ ├── code │ │ ├── .env.example │ │ ├── contracts │ │ │ └── Greeter.sol │ │ ├── package.json │ │ ├── hardhat.config.ts │ │ ├── LICENSE │ │ ├── test │ │ │ └── main.test.ts │ │ ├── deploy │ │ │ ├── use-greeter.ts │ │ │ └── deploy-greeter.ts │ │ ├── README.md │ │ └── .gitignore │ └── TUTORIAL.md ├── web3modal │ ├── code │ │ ├── .eslintrc.json │ │ ├── src │ │ │ ├── app │ │ │ │ ├── favicon.ico │ │ │ │ ├── page.module.css │ │ │ │ ├── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── globals.css │ │ │ └── context │ │ │ │ └── Web3Modal.tsx │ │ ├── next.config.js │ │ ├── .gitignore │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── README.md │ └── TUTORIAL.md ├── zkSync-RedStone-stable-price-marketplace-tutorial │ ├── code │ │ ├── .env.example │ │ ├── src │ │ │ ├── constants.ts │ │ │ ├── config │ │ │ │ ├── zkSyncTestnet-addresses.json │ │ │ │ ├── marketplace-abi.json │ │ │ │ └── nft-abi.json │ │ │ ├── index.tsx │ │ │ ├── components │ │ │ │ ├── Card.tsx │ │ │ │ └── App.tsx │ │ │ ├── styles.scss │ │ │ └── core │ │ │ │ └── blockchain.ts │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── img │ │ │ │ ├── nft-icon.png │ │ │ │ ├── redstone-logo.png │ │ │ │ └── nft-in-cart-icon.png │ │ │ └── index.html │ │ ├── docs │ │ │ └── img │ │ │ │ ├── my-nfts.png │ │ │ │ ├── orders.png │ │ │ │ ├── redstone-requests.png │ │ │ │ └── stable-marketplace-app.png │ │ ├── contracts │ │ │ ├── ExampleNFT.sol │ │ │ ├── StableMarketplace.sol │ │ │ └── Marketplace.sol │ │ ├── tsconfig.json │ │ ├── test │ │ │ ├── common.ts │ │ │ ├── example-nft.test.ts │ │ │ ├── stable-marketplace.test.ts │ │ │ └── marketplace.test.ts │ │ ├── LICENSE │ │ ├── hardhat.config.ts │ │ ├── package.json │ │ ├── deploy │ │ │ └── deploy.ts │ │ └── README.md │ └── TUTORIAL.md ├── TUTORIAL_TEMPLATE.md ├── README.md └── the-graph │ ├── TUTORIAL.md │ └── code │ └── pepe_abi.json ├── community-tutorials.png ├── .markdownlint.json ├── package.json ├── cspell.json ├── tutorials.json ├── .gitignore ├── cspell-zksync.txt ├── README.md └── yarn.lock /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @matter-labs/devxp -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/.env.example: -------------------------------------------------------------------------------- 1 | WALLET_PRIVATE_KEY= 2 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/.env.example: -------------------------------------------------------------------------------- 1 | WALLET_PRIVATE_KEY= 2 | -------------------------------------------------------------------------------- /community-tutorials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/community-tutorials.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const zkSyncLocalTestnetChainId = 270; 2 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/web3modal/code/src/app/favicon.ico -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/app/page.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: space-between; 5 | align-items: center; 6 | padding: 6rem; 7 | min-height: 100vh; 8 | } -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/favicon.ico -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/my-nfts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/my-nfts.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/orders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/orders.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/nft-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/nft-icon.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/config/zkSyncTestnet-addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "nft": "0x650AaaA087062454DCd8F0D3946e855fDa054f86", 3 | "marketplace": "0x5C4660B6b4C0eA53E10fe0Bb354362f391bA2F68" 4 | } 5 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import styles from './page.module.css' 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/redstone-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/redstone-logo.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/redstone-requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/redstone-requests.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/nft-in-cart-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/img/nft-in-cart-icon.png -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/stable-marketplace-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkSync-Community-Hub/tutorials/HEAD/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/docs/img/stable-marketplace-app.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: zkync-developers Discussion 4 | url: https://github.com/zkSync-Community-Hub/zkync-developers/discussions 5 | about: Please provide feedback, and ask questions here. -------------------------------------------------------------------------------- /tutorials/web3modal/code/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | webpack: (config) => { 4 | config.externals.push( 5 | "pino-pretty", 6 | "lokijs", 7 | "encoding" 8 | ); 9 | return config; 10 | } 11 | } 12 | 13 | module.exports = nextConfig 14 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./components/App"; 4 | 5 | const rootElement = document.getElementById("root"); 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | rootElement 11 | ); 12 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/contracts/Greeter.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: Unlicense 2 | pragma solidity ^0.8.0; 3 | 4 | contract Greeter { 5 | string private greeting; 6 | 7 | constructor(string memory _greeting) { 8 | greeting = _greeting; 9 | } 10 | 11 | function greet() public view returns (string memory) { 12 | return greeting; 13 | } 14 | 15 | function setGreeting(string memory _greeting) public { 16 | greeting = _greeting; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/ExampleNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 6 | 7 | contract ExampleNFT is ERC721Enumerable { 8 | uint256 private nextTokenId = 1; 9 | 10 | constructor() ERC721("ExampleNFT", "ENFT") {} 11 | 12 | function mint() external { 13 | _mint(msg.sender, nextTokenId); 14 | nextTokenId++; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { PropsWithChildren } from 'react' 3 | import './globals.css' 4 | import { Web3Modal } from '../context/Web3Modal' 5 | 6 | export const metadata: Metadata = { 7 | title: 'Web3Modal & zkSync', 8 | description: 'Web3Modal & zkSync Tutorial', 9 | } 10 | 11 | export default function RootLayout({children}: PropsWithChildren) { 12 | return ( 13 | 14 | 15 | 16 | {children} 17 | 18 | 19 | 20 | ) 21 | } -------------------------------------------------------------------------------- /.github/workflows/secrets_scanner.yaml: -------------------------------------------------------------------------------- 1 | name: Leaked Secrets Scan 2 | on: [pull_request] 3 | jobs: 4 | TruffleHog: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout code 8 | uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3 9 | with: 10 | fetch-depth: 0 11 | - name: TruffleHog OSS 12 | uses: trufflesecurity/trufflehog@4a77688097d83259a4ebf1b26d4daec8e130e57b 13 | with: 14 | path: ./ 15 | base: ${{ github.event.repository.default_branch }} 16 | head: HEAD 17 | extra_args: --debug --only-verified 18 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/app/globals.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | 7 | html, 8 | body { 9 | max-width: 100vw; 10 | overflow-x: hidden; 11 | } 12 | 13 | body { 14 | color: rgb(var(--foreground-rgb)); 15 | background: linear-gradient( 16 | to bottom, 17 | transparent, 18 | rgb(var(--background-end-rgb)) 19 | ) 20 | rgb(var(--background-start-rgb)); 21 | } 22 | 23 | a { 24 | color: inherit; 25 | text-decoration: none; 26 | } 27 | 28 | @media (prefers-color-scheme: dark) { 29 | html { 30 | color-scheme: dark; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "fenced-code-language": false, 4 | "no-duplicate-header": false, 5 | "first-header-h1": false, 6 | "first-line-h1": false, 7 | "no-inline-html": false, 8 | "ol-prefix": false, 9 | "MD026": { 10 | "punctuation": ".,;:!。,;:!:" 11 | }, 12 | "MD013": false, 13 | "MD001": false, 14 | "MD051": false, 15 | "MD025": false, 16 | "MD036": false, 17 | "MD003": false, 18 | "MD007": { 19 | "indent": 2, 20 | "code_blocks": false, 21 | "headings": false, 22 | "tables": false 23 | }, 24 | "no-hard-tabs": false, 25 | "whitespace": false 26 | } 27 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-route", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@web3modal/wagmi": "^3.1.0", 13 | "next": "13.5.6", 14 | "react": "^18", 15 | "react-dom": "^18", 16 | "viem": "^1.17.1", 17 | "wagmi": "^1.4.5" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^18", 22 | "@types/react-dom": "^18", 23 | "eslint": "^8", 24 | "eslint-config-next": "13.5.6", 25 | "typescript": "^5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tutorials", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "git@github.com:zkSync-Community-Hub/tutorials.git", 6 | "author": "Dustin Brickwood ", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "cspell": "^6.31.2", 10 | "markdownlint": "^0.29.0", 11 | "markdownlint-cli": "^0.35.0", 12 | "prettier": "^3.0.0" 13 | }, 14 | "scripts": { 15 | "lint:fmt": "prettier --check \"tutorials/**/*.md\"", 16 | "lint:mdl": "markdownlint -c .markdownlint.json \"tutorials/**/*.md\"", 17 | "lint:spell": "cspell tutorials/**/*.md", 18 | "fix:fmt": "prettier --write \"tutorials/**/*.md\"", 19 | "fix:mdl": "yarn lint:mdl --fix" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "skipLibCheck": true, 8 | "resolveJsonModule": true, 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "outDir": "dist", 12 | "declaration": true, 13 | "declarationMap": true, 14 | "incremental": true, 15 | "composite": true, 16 | "jsx": "react-jsx" 17 | }, 18 | "include": [ 19 | "./src", 20 | "./test", 21 | "./typechain-types", 22 | "package.json", 23 | "src/**/*.json", 24 | "./artifacts/**/*.json" 25 | ], 26 | "files": ["./hardhat.config.ts"] 27 | } 28 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/test/common.ts: -------------------------------------------------------------------------------- 1 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 2 | import { Contract } from "zksync-web3"; 3 | 4 | export const DEPLOYER_WALLET_PK = 5 | "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; 6 | 7 | export const BUYER_RICH_WALLET_PK = 8 | "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3"; 9 | 10 | export const SELLER_RICH_WALLET_PK = 11 | "0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e"; 12 | 13 | export const deployContract = async ( 14 | deployer: Deployer, 15 | contractName: string 16 | ): Promise => { 17 | const artifact = await deployer.loadArtifact(contractName); 18 | return await deployer.deploy(artifact); 19 | }; 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Tutorial submission 2 | 3 | ## Title of the tutorial 4 | Please provide the title of your tutorial. 5 | - 6 | 7 | ## Brief tutorial description 8 | Provide a brief description of your tutorial, including what it covers and what readers can learn from it. 9 | - 10 | 11 | ## Checklist 12 | Please ensure you've completed the following tasks: 13 | 14 | - [ ] I confirm that this tutorial is an original work and hasn't been published elsewhere. 15 | - [ ] I confirm that I am the rightful intellectual property owner (author) of this submission. 16 | - [ ] The tutorial includes referenced and relevant external sources (if applicable). 17 | - [ ] The tutorial includes working code snippets to illustrate concepts. 18 | - [ ] I have adhered to the tutorial guidelines provided in the repository. -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "en", 3 | "ignorePaths": [ 4 | "node_modules/**", 5 | ".github/**", 6 | ".firebase/**", 7 | ".yarn/**", 8 | "dist/**" 9 | ], 10 | "dictionaries": [ 11 | "typescript", 12 | "cpp", 13 | "npm", 14 | "filetypes", 15 | "cpp", 16 | "en_GB", 17 | "en_US", 18 | "node", 19 | "bash", 20 | "fonts", 21 | "npm", 22 | "cryptocurrencies", 23 | "companies", 24 | "rust", 25 | "html", 26 | "css", 27 | "entities", 28 | "softwareTerms", 29 | "misc", 30 | "fullstack", 31 | "softwareTerms", 32 | "zksync" 33 | ], 34 | "dictionaryDefinitions": [ 35 | { 36 | "name": "zksync", 37 | "addWords": true, 38 | "path": "./cspell-zksync.txt" 39 | } 40 | ], 41 | "allowCompoundWords": true 42 | } 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tutorial_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tutorial Request 3 | about: Suggest a new tutorial for the community. 4 | title: '' 5 | labels: 'tutorial-request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Tutorial Topic 11 | 12 | 13 | ## Why this topic should be covered 14 | 15 | 16 | ## Additional Information 17 | 18 | 19 | ## Are you willing to write the tutorial? 20 | 21 | 22 | ## Existing related tutorials or resources 23 | 24 | 25 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/StableMarketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.4; 3 | 4 | import "./Marketplace.sol"; 5 | 6 | /* 7 | StableMarketplace contract should extend MainDemoConsumerBase contract 8 | For being able to use redstone oracles data, more inf: 9 | https://docs.redstone.finance/docs/smart-contract-devs/get-started/redstone-core#1-adjust-your-smart-contracts 10 | */ 11 | contract StableMarketplace is Marketplace { 12 | /* 13 | `_getPriceFromOrder` function should uses the `getOracleNumericValueFromTxMsg` function, 14 | which fetches signed data from tx calldata and verifies its signature 15 | */ 16 | function _getPriceFromOrder( 17 | SellOrder memory order 18 | ) internal view override returns (uint256) { 19 | // TO IMPLEMENT 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/src/context/Web3Modal.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { PropsWithChildren } from 'react' 4 | 5 | import { WagmiConfig } from 'wagmi' 6 | import { createWeb3Modal, defaultWagmiConfig } from '@web3modal/wagmi/react' 7 | import { zkSync, zkSyncTestnet } from 'wagmi/chains' 8 | 9 | const projectId = '0c2c1ade52d105f1294e5b6fecffbf1b' 10 | 11 | const metadata = { 12 | name: 'Web3Modal & zkSync', 13 | description: 'Web3Modal & zkSync Tutorial', 14 | url: 'https://web3modal.com', 15 | icons: ['https://avatars.githubusercontent.com/u/37784886'] 16 | } 17 | const chains = [zkSync, zkSyncTestnet] 18 | const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata }) 19 | 20 | createWeb3Modal({ wagmiConfig, projectId, chains, defaultChain: zkSync }) 21 | 22 | export function Web3Modal({ children }: PropsWithChildren) { 23 | return( 24 | 25 | {children} 26 | 27 | ) 28 | } -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zksync-hardhat-template", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "git@github.com:matter-labs/zksync-hardhat-template.git", 6 | "author": "Antonio ", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "@matterlabs/hardhat-zksync-deploy": "^0.6.3", 10 | "@matterlabs/hardhat-zksync-solc": "^0.3.17", 11 | "@types/chai": "^4.3.4", 12 | "@types/mocha": "^10.0.1", 13 | "chai": "^4.3.7", 14 | "dotenv": "^16.0.3", 15 | "ethers": "^5.7.2", 16 | "hardhat": "^2.12.4", 17 | "mocha": "^10.2.0", 18 | "ts-node": "^10.9.1", 19 | "typescript": "^4.9.4", 20 | "zksync-web3": "^0.14.3" 21 | }, 22 | "scripts": { 23 | "test": "NODE_ENV=test hardhat test --network zkSyncTestnet", 24 | "deploy": "yarn hardhat deploy-zksync --script deploy-greeter.ts", 25 | "greet": "yarn hardhat deploy-zksync --script use-greeter.ts" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { HardhatUserConfig } from "hardhat/config"; 2 | 3 | import "@matterlabs/hardhat-zksync-deploy"; 4 | import "@matterlabs/hardhat-zksync-solc"; 5 | 6 | // dynamically changes endpoints for local tests 7 | const zkSyncTestnet = 8 | process.env.NODE_ENV == "test" 9 | ? { 10 | url: "http://localhost:3050", 11 | ethNetwork: "http://localhost:8545", 12 | zksync: true, 13 | } 14 | : { 15 | url: "https://zksync2-testnet.zksync.dev", 16 | ethNetwork: "goerli", 17 | zksync: true, 18 | }; 19 | 20 | const config: HardhatUserConfig = { 21 | zksolc: { 22 | version: "1.3.10", 23 | compilerSource: "binary", 24 | settings: {}, 25 | }, 26 | defaultNetwork: "zkSyncTestnet", 27 | networks: { 28 | hardhat: { 29 | zksync: false, 30 | }, 31 | zkSyncTestnet, 32 | }, 33 | solidity: { 34 | version: "0.8.17", 35 | }, 36 | }; 37 | 38 | export default config; 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tutorial_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tutorial Issue 3 | about: Use this template for reporting issues with our tutorials 4 | title: "" 5 | labels: tutorial-issue 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Tutorial Name** 11 | Please specify the name of the tutorial or the link if available: 12 | 13 | **Issue Description** 14 | A clear and concise description of what the issue is: 15 | 16 | **Steps to Reproduce** 17 | Please provide the steps that led to the issue: 18 | 19 | 1. 20 | 2. 21 | 3. 22 | 4. 23 | 5. 24 | 25 | **Expected Outcome** 26 | A brief explanation of what you expected to happen: 27 | 28 | **Actual Outcome** 29 | A brief explanation of what actually happened: 30 | 31 | **Screenshots** 32 | If applicable, add screenshots to help explain your problem: 33 | 34 | **Additional Information** 35 | Any other information that you think would be helpful for us to understand the issue: 36 | 37 | **Possible Solution** 38 | If you have any suggestions for resolving the issue, feel free to share: 39 | 40 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/components/Card.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | image: string; 3 | tokenId: string; 4 | onButtonClick: (tokenId: string) => void; 5 | buttonText: string; 6 | price?: string; 7 | buttonTextColor?: string; 8 | } 9 | 10 | export function Card(props: Props) { 11 | return ( 12 |
13 |
14 | 15 |
NFT #{props.tokenId}
16 |
17 | 18 |
{props.price ? `$${props.price}` : ``}
19 | 20 |
21 | props.onButtonClick(props.tokenId)} 26 | > 27 | {props.buttonText} 28 | 29 |
30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Antonio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 RedStone Finance 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/test/main.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { Wallet, Provider, Contract } from 'zksync-web3'; 3 | import * as hre from 'hardhat'; 4 | import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; 5 | 6 | const RICH_WALLET_PK = 7 | '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; 8 | 9 | async function deployGreeter(deployer: Deployer): Promise { 10 | const artifact = await deployer.loadArtifact('Greeter'); 11 | return await deployer.deploy(artifact, ['Hi']); 12 | } 13 | 14 | describe('Greeter', function () { 15 | it("Should return the new greeting once it's changed", async function () { 16 | const provider = Provider.getDefaultProvider(); 17 | 18 | const wallet = new Wallet(RICH_WALLET_PK, provider); 19 | const deployer = new Deployer(hre, wallet); 20 | 21 | const greeter = await deployGreeter(deployer); 22 | 23 | expect(await greeter.greet()).to.eq('Hi'); 24 | 25 | const setGreetingTx = await greeter.setGreeting('Hola, mundo!'); 26 | // wait until the transaction is mined 27 | await setGreetingTx.wait(); 28 | 29 | expect(await greeter.greet()).to.equal('Hola, mundo!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { HardhatUserConfig } from "hardhat/config"; 2 | 3 | import "@matterlabs/hardhat-zksync-deploy"; 4 | import "@matterlabs/hardhat-zksync-solc"; 5 | import "@matterlabs/hardhat-zksync-verify"; 6 | import "@matterlabs/hardhat-zksync-chai-matchers" 7 | 8 | // dynamically changes endpoints for local tests 9 | const zkSyncTestnet = 10 | process.env.NODE_ENV == "test" 11 | ? { 12 | url: "http://localhost:3050", 13 | ethNetwork: "http://localhost:8545", 14 | zksync: true, 15 | } 16 | : { 17 | url: "https://zksync2-testnet.zksync.dev", 18 | ethNetwork: "goerli", 19 | zksync: true, 20 | // contract verification endpoint 21 | verifyURL: 22 | "https://zksync2-testnet-explorer.zksync.dev/contract_verification", 23 | }; 24 | 25 | const config: HardhatUserConfig = { 26 | zksolc: { 27 | version: "latest", 28 | settings: {}, 29 | }, 30 | defaultNetwork: "zkSyncTestnet", 31 | networks: { 32 | hardhat: { 33 | zksync: false, 34 | }, 35 | zkSyncTestnet, 36 | }, 37 | solidity: { 38 | version: "0.8.17", 39 | }, 40 | }; 41 | 42 | export default config; 43 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Stable NFT marketplace 12 | 13 | 14 | 15 | 18 |
19 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tutorials/TUTORIAL_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | ### Introduction 4 | 5 | 11 | 12 | ## Prerequisites 13 | 14 | 19 | 20 | ## Build time 21 | 22 | ### Step 1 — Doing the First Thing 23 | 24 | 29 | 30 | ```bash 31 | # Example command 32 | echo "Hello, World!" 33 | ``` 34 | 35 | 38 | 39 | ```bash 40 | Hello, World! 41 | ``` 42 | 43 | ### Step 2 — Doing the Next Thing 44 | 45 | 46 | 47 | ## Conclusion 48 | 49 | 53 | -------------------------------------------------------------------------------- /tutorials.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "zkSync Era quickstart with zksync-cli", 4 | "description": 5 | "Use the zksync-cli to deploy your first smart contract to zkSync Era testnet.", 6 | "tags": ["cli", "testnet", "smart contract"], 7 | "time": "1 hour", 8 | "author": "A. Ufano", 9 | "slug": "zksync-cli-quickstart" 10 | }, 11 | { 12 | "title": "Use Redstone to feed offchain data to smart contracts", 13 | "description": "By the end of this tutorial you will understand how to integrate your dApp built on zkSync with RedStone oracles.", 14 | "tags": ["oracle", "redstone", "smart contract"], 15 | "time": "2 to 3 hours", 16 | "author": "C. Haliniarz", 17 | "slug": "zkSync-RedStone-stable-price-marketplace-tutorial" 18 | }, 19 | { 20 | "title": "Deploy a Subgraph Tracking a Specific Address on zkSync", 21 | "description": "learn how to deploy a subgraph that tracks a specific address on zkSync Era mainnet. Deploying graphs is a great way to query data from network historically and in real-time.", 22 | "tags": ["graph", "indexer", "subgraph"], 23 | "time": "1 hour", 24 | "author": "D. Huisman", 25 | "slug": "the-graph" 26 | }, 27 | { 28 | "title": "Web3Modal & zkSync Era", 29 | "description": "learn how to create a website and connect to zkSync ERA with your wallet.", 30 | "tags": ["wallets", "website", "web3modal"], 31 | "time": "20 minutes", 32 | "author": "Glitch-txs", 33 | "slug": "web3modal" 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /tutorials/web3modal/code/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /tutorials/README.md: -------------------------------------------------------------------------------- 1 | # 📘 zkSync Era Community Tutorials 2 | 3 | This repository hosts a collection of community tutorials that help developers understand and build applications on zkSync Era. 4 | 5 | ## 📋 Tutorial Requirements 6 | 7 | - 🏗️ All tutorials must showcase how to develop applications on zkSync Era. 8 | - 🔄 Tutorials must take a neutral stance and refrain from promoting projects. 9 | - 📝 Tutorials must be original and NOT a work that was previously published. 10 | - 👩‍💻 You must be the rightful intellectual property owner (author) of your submission. 11 | - 🔗 Tutorials can contain relevant external sources, only when referenced accordingly. 12 | - 🛠️ Tutorials must have working code to support the tutorial. 13 | - 📖 Tutorials must be provided following the [guidelines in this repository](#tutorial-guidelines). 14 | 15 | ## 📚 Tutorial Guidelines 16 | 17 | To submit a tutorial, please follow the guidelines below: 18 | 19 | 1. 📂 Create a new folder inside `tutorials` with the name of your tutorial in _kebab-case_, e.g., `my-awesome-tutorial`. 20 | 2. 📄 In this folder, create a `TUTORIAL.md`. The tutorial must follow the prescribed structure, which includes a title, introduction, prerequisites, build steps, and a conclusion. 21 | 3. 📝 Ensure to specify the exact versions of packages and compilers used to build the project in the prerequisites section. 22 | 4. 📁 Create a `code` folder with any code necessary to support the tutorial. 23 | 5. 🖼️ Create an `images` folder with any images necessary to support the tutorial. 24 | 25 | Refer to the [TUTORIAL_TEMPLATE](./tutorials/TUTORIAL_TEMPLATE.md) and [zksync-cli-quickstart tutorial](./tutorials/zksync-cli-quickstart/) as a reference while creating your tutorial. 26 | 27 | We welcome all contributions and thank you for your interest in creating tutorials for zkSync Era! 😊 28 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/deploy/use-greeter.ts: -------------------------------------------------------------------------------- 1 | import { Provider } from "zksync-web3"; 2 | import * as ethers from "ethers"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | 5 | // load env file 6 | import dotenv from "dotenv"; 7 | dotenv.config(); 8 | 9 | // load contract artifact. Make sure to compile first! 10 | import * as ContractArtifact from "../artifacts-zk/contracts/Greeter.sol/Greeter.json"; 11 | 12 | const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ""; 13 | 14 | if (!PRIVATE_KEY) 15 | throw "⛔️ Private key not detected! Add it to the .env file!"; 16 | 17 | // Address of the contract on zksync testnet 18 | const CONTRACT_ADDRESS = ""; 19 | 20 | if (!CONTRACT_ADDRESS) throw "⛔️ Contract address not provided"; 21 | 22 | // An example of a deploy script that will deploy and call a simple contract. 23 | export default async function (hre: HardhatRuntimeEnvironment) { 24 | console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`); 25 | 26 | // Initialize the provider. 27 | // @ts-ignore 28 | const provider = new Provider(hre.userConfig.networks?.zkSyncTestnet?.url); 29 | const signer = new ethers.Wallet(PRIVATE_KEY, provider); 30 | 31 | // Initialise contract instance 32 | const contract = new ethers.Contract( 33 | CONTRACT_ADDRESS, 34 | ContractArtifact.abi, 35 | signer 36 | ); 37 | 38 | // Read message from contract 39 | console.log(`The message is ${await contract.greet()}`); 40 | 41 | // send transaction to update the message 42 | const newMessage = "Hello people!"; 43 | const tx = await contract.setGreeting(newMessage); 44 | 45 | console.log(`Transaction to change the message is ${tx.hash}`); 46 | await tx.wait(); 47 | 48 | // Read message after transaction 49 | console.log(`The message now is ${await contract.greet()}`); 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: checks 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | links: 11 | name: links 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node-version: [18.x] 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Link Checker 20 | id: lychee 21 | uses: lycheeverse/lychee-action@v1.8.0 22 | 23 | format: 24 | name: format 25 | runs-on: ubuntu-latest 26 | strategy: 27 | matrix: 28 | node-version: [18.x] 29 | steps: 30 | - uses: actions/checkout@v3 31 | - name: Use Node.js ${{ matrix.node-version }} 32 | uses: actions/setup-node@v3 33 | with: 34 | node-version: ${{ matrix.node-version }} 35 | - name: prettier 36 | run: | 37 | yarn install 38 | yarn lint:fmt 39 | 40 | spelling: 41 | name: spelling 42 | runs-on: ubuntu-latest 43 | strategy: 44 | matrix: 45 | node-version: [18.x] 46 | steps: 47 | - uses: actions/checkout@v3 48 | - name: Use Node.js ${{ matrix.node-version }} 49 | uses: actions/setup-node@v3 50 | with: 51 | node-version: ${{ matrix.node-version }} 52 | - name: cspell 53 | run: | 54 | yarn install 55 | yarn lint:spell 56 | 57 | lint: 58 | name: lint 59 | runs-on: ubuntu-latest 60 | strategy: 61 | matrix: 62 | node-version: [18.x] 63 | steps: 64 | - uses: actions/checkout@v3 65 | - name: Use Node.js ${{ matrix.node-version }} 66 | uses: actions/setup-node@v3 67 | with: 68 | node-version: ${{ matrix.node-version }} 69 | - name: lint 70 | run: | 71 | yarn install 72 | yarn lint:mdl -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/README.md: -------------------------------------------------------------------------------- 1 | # zkSync Hardhat project 2 | 3 | This project was scaffolded with [zksync-cli](https://github.com/matter-labs/zksync-cli). 4 | 5 | ## Project structure 6 | 7 | - `/contracts`: smart contracts. 8 | - `/deploy`: deployment and contract interaction scripts. 9 | - `/test`: test files 10 | - `hardhat.config.ts`: configuration file. 11 | 12 | ## Commands 13 | 14 | - `yarn hardhat compile` will compile the contracts. 15 | - `yarn run deploy` will execute the deployment script `/deploy/deploy-greeter.ts`. Requires [environment variable setup](#environment-variables). 16 | - `yarn run greet` will execute the script `/deploy/use-greeter.ts` which interacts with the Greeter contract deployed. 17 | - `yarn test`: run tests. **Check test requirements below.** 18 | 19 | Both `yarn run deploy` and `yarn run greet` are configured in the `package.json` file and run `yarn hardhat deploy-zksync`. 20 | 21 | ### Environment variables 22 | 23 | In order to prevent users to leak private keys, this project includes the `dotenv` package which is used to load environment variables. It's used to load the wallet private key, required to run the deploy script. 24 | 25 | To use it, rename `.env.example` to `.env` and enter your private key. 26 | 27 | ``` 28 | WALLET_PRIVATE_KEY=123cde574ccff.... 29 | ``` 30 | 31 | ### Local testing 32 | 33 | In order to run test, you need to start the zkSync local environment. Please check [this section of the docs](https://v2-docs.zksync.io/api/hardhat/testing.html#prerequisites) which contains all the details. 34 | 35 | If you do not start the zkSync local environment, the tests will fail with error `Error: could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.7.2)` 36 | 37 | ## Official Links 38 | 39 | - [Website](https://zksync.io/) 40 | - [Documentation](https://v2-docs.zksync.io/dev/) 41 | - [GitHub](https://github.com/matter-labs) 42 | - [Twitter](https://twitter.com/zksync) 43 | - [Discord](https://discord.gg/nMaPGrDDwk) 44 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stable-price-marketplace", 3 | "version": "1.0.0", 4 | "main": "src/index.ts", 5 | "repository": "https://github.com/redstone-finance/stable-price-marketplace", 6 | "author": "cehali ", 7 | "license": "MIT", 8 | "scripts": { 9 | "app:start": "GENERATE_SOURCEMAP=false react-scripts start", 10 | "app:build": "GENERATE_SOURCEMAP=false react-scripts build", 11 | "app:eject": "react-scripts eject", 12 | "test": "NODE_ENV=test hardhat test --network zkSyncTestnet", 13 | "deploy:local": "NODE_ENV=test hardhat deploy-zksync --script deploy.ts", 14 | "deploy": "yarn hardhat deploy-zksync --script deploy.ts", 15 | "compile": "hardhat compile" 16 | }, 17 | "dependencies": { 18 | "@redstone-finance/evm-connector": "^0.2.6", 19 | "ethers": "^5.7.2", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-scripts": "5.0.1", 23 | "sass": "^1.66.1" 24 | }, 25 | "devDependencies": { 26 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11", 27 | "@matterlabs/hardhat-zksync-chai-matchers": "^0.1.3", 28 | "@matterlabs/hardhat-zksync-deploy": "^0.6.3", 29 | "@matterlabs/hardhat-zksync-solc": "^0.4.1", 30 | "@matterlabs/hardhat-zksync-verify": "^0.1.8", 31 | "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", 32 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 33 | "@types/chai": "^4.3.5", 34 | "@types/mocha": "^10.0.1", 35 | "@types/react": "^18.2.20", 36 | "@types/react-dom": "^18.2.7", 37 | "chai": "^4.3.7", 38 | "dotenv": "^16.3.1", 39 | "ethers": "^5.7.2", 40 | "hardhat": "^2.17.1", 41 | "mocha": "^10.2.0", 42 | "ts-node": "^10.9.1", 43 | "typescript": "^5.1.6", 44 | "zksync-web3": "^0.14.3" 45 | }, 46 | "browserslist": { 47 | "production": [ 48 | ">0.2%", 49 | "not dead", 50 | "not op_mini all" 51 | ], 52 | "development": [ 53 | "last 1 chrome version", 54 | "last 1 firefox version", 55 | "last 1 safari version" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .vscode 9 | 10 | # hardhat artifacts 11 | artifacts 12 | cache 13 | 14 | # zksync artifacts 15 | artifacts-zk 16 | cache-zk 17 | 18 | # Diagnostic reports (https://nodejs.org/api/report.html) 19 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 20 | 21 | # Runtime data 22 | pids 23 | *.pid 24 | *.seed 25 | *.pid.lock 26 | 27 | # Directory for instrumented libs generated by jscoverage/JSCover 28 | lib-cov 29 | 30 | # Coverage directory used by tools like istanbul 31 | coverage 32 | *.lcov 33 | 34 | # nyc test coverage 35 | .nyc_output 36 | 37 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 38 | .grunt 39 | 40 | # Bower dependency directory (https://bower.io/) 41 | bower_components 42 | 43 | # node-waf configuration 44 | .lock-wscript 45 | 46 | # Compiled binary addons (https://nodejs.org/api/addons.html) 47 | build/Release 48 | 49 | # Dependency directories 50 | node_modules/ 51 | jspm_packages/ 52 | 53 | # TypeScript v1 declaration files 54 | typings/ 55 | 56 | # TypeScript cache 57 | *.tsbuildinfo 58 | 59 | # Optional npm cache directory 60 | .npm 61 | 62 | # Optional eslint cache 63 | .eslintcache 64 | 65 | # Microbundle cache 66 | .rpt2_cache/ 67 | .rts2_cache_cjs/ 68 | .rts2_cache_es/ 69 | .rts2_cache_umd/ 70 | 71 | # Optional REPL history 72 | .node_repl_history 73 | 74 | # Output of 'npm pack' 75 | *.tgz 76 | 77 | # Yarn Integrity file 78 | .yarn-integrity 79 | 80 | # dotenv environment variables file 81 | .env 82 | .env.test 83 | 84 | # parcel-bundler cache (https://parceljs.org/) 85 | .cache 86 | 87 | # Next.js build output 88 | .next 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # Serverless directories 104 | .serverless/ 105 | 106 | # FuseBox cache 107 | .fusebox/ 108 | 109 | # DynamoDB Local files 110 | .dynamodb/ 111 | 112 | # TernJS port file 113 | .tern-port 114 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # zkSync Era quickstart with zksync-cli 2 | 3 | ## Introduction 4 | 5 | In this tutorial we'll use the zksync-cli to deploy our first smart contract to zkSync Era testnet. 6 | 7 | ## Requirements 8 | 9 | Here are the system requirements and the versions I used: 10 | 11 | - Node.js (v16.17.1) and NPM 12 | - Yarn (v1.22.19) 13 | 14 | Additionally, you'd need an account with ETH on zkSync Era testnet. You can use the [faucet from the official portal](https://goerli.portal.zksync.io/faucet). 15 | 16 | ## Build time 17 | 18 | 1. Install the zksync-cli with: 19 | 20 | ```sh 21 | npm i -g zksync-cli@latest 22 | ``` 23 | 24 | 2. Create a sample project 25 | 26 | ```sh 27 | zksync-cli create quickstart && cd quickstart 28 | ``` 29 | 30 | This commands clones an existing template project inside a new folder named `quickstart`. 31 | 32 | The template project has the following structure: 33 | 34 | - `hardhat.config.ts`: Hardhat configuration file that imports the zksync required plugins. 35 | - `contracts`: folder with a `Greeter.sol` smart contract. 36 | - `deploy`: folder with scripts to deploy and interact with the smart contract. 37 | 38 | 3. Compile the contract with: 39 | 40 | ```sh 41 | yarn hardhat compile 42 | ``` 43 | 44 | Once compiled, the `artifacts-zk` and `cache-zk` folders will be generated. 45 | 46 | 4. Rename the `.env.example` file to `.env` and enter your account private key in it. This is the account that will pay for the deployment of the smart contract. 47 | 48 | ```text 49 | WALLET_PRIVATE_KEY=abcdef123456.... 50 | ``` 51 | 52 | 5. Deploy the contract with: 53 | 54 | ```sh 55 | yarn hardhat deploy-zksync --script deploy-greeter.ts 56 | ``` 57 | 58 | You'll see something like this: 59 | 60 | ```sh 61 | Running deploy script for the Greeter contract 62 | The deployment is estimated to cost 0.00004848225 ETH 63 | Constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 64 | Greeter was deployed to 0x922a36d29b1e991DB35b8e14C08828eC31E64Ac0 65 | ``` 66 | 67 | Congrats, you've deployed a contract to zkSync Era testnet. You can see the contract in the [zkSync Explorer](https://goerli.explorer.zksync.io/) 68 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/test/example-nft.test.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Provider, Wallet } from "zksync-web3"; 2 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 3 | import * as hre from "hardhat"; 4 | import { expect } from "chai"; 5 | import { SELLER_RICH_WALLET_PK, BUYER_RICH_WALLET_PK, deployContract } from "./common"; 6 | 7 | describe("ExampleNFT", function () { 8 | let exampleNFTContract: Contract; 9 | let owner: Wallet; 10 | 11 | it("Should deploy ExampleNFT", async function () { 12 | const provider = Provider.getDefaultProvider(); 13 | const wallet = new Wallet(SELLER_RICH_WALLET_PK, provider); 14 | const deployer = new Deployer(hre, wallet); 15 | exampleNFTContract = await deployContract(deployer, "ExampleNFT"); 16 | owner = new Wallet(SELLER_RICH_WALLET_PK, provider); 17 | }); 18 | 19 | it("Should mint 2 NFTs", async function () { 20 | // Mint first NFT 21 | const mintTx1 = await exampleNFTContract.mint(); 22 | await mintTx1.wait(); 23 | 24 | // Mint second NFT 25 | const mintTx2 = await exampleNFTContract.mint(); 26 | await mintTx2.wait(); 27 | 28 | // Verify NFT ownership 29 | const ownerAddress = await owner.getAddress(); 30 | expect(await exampleNFTContract.ownerOf(1)).to.equal(ownerAddress); 31 | expect(await exampleNFTContract.ownerOf(2)).to.equal(ownerAddress); 32 | }); 33 | 34 | it("User1 should approve spending and User2 should spend", async function () { 35 | // User1 approves 36 | const provider = Provider.getDefaultProvider(); 37 | const user1 = owner; 38 | const user1Address = await user1.getAddress(); 39 | const user2 = new Wallet(BUYER_RICH_WALLET_PK, provider); 40 | const user2Address = await user2.getAddress(); 41 | const tokenId = 1; 42 | const approveTx = await exampleNFTContract.approve( 43 | user2Address, 44 | tokenId, 45 | ); 46 | await approveTx.wait(); 47 | 48 | // User2 transfers 49 | const transferTx = await exampleNFTContract.transferFrom( 50 | user1Address, 51 | user2Address, 52 | tokenId, 53 | ); 54 | await transferTx.wait(); 55 | 56 | // Checking ownership 57 | const newOwner = await exampleNFTContract.ownerOf(tokenId); 58 | expect(newOwner).to.equal(user2Address); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .vscode 9 | 10 | # hardhat artifacts 11 | artifacts 12 | cache 13 | 14 | # zksync artifacts 15 | artifacts-zk 16 | cache-zk 17 | 18 | # Diagnostic reports (https://nodejs.org/api/report.html) 19 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 20 | 21 | # Runtime data 22 | pids 23 | *.pid 24 | *.seed 25 | *.pid.lock 26 | 27 | # Directory for instrumented libs generated by jscoverage/JSCover 28 | lib-cov 29 | 30 | # Coverage directory used by tools like istanbul 31 | coverage 32 | *.lcov 33 | 34 | # nyc test coverage 35 | .nyc_output 36 | 37 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 38 | .grunt 39 | 40 | # Bower dependency directory (https://bower.io/) 41 | bower_components 42 | 43 | # node-waf configuration 44 | .lock-wscript 45 | 46 | # Compiled binary addons (https://nodejs.org/api/addons.html) 47 | build/Release 48 | 49 | # Dependency directories 50 | node_modules/ 51 | jspm_packages/ 52 | 53 | # TypeScript v1 declaration files 54 | typings/ 55 | 56 | # TypeScript cache 57 | *.tsbuildinfo 58 | 59 | # Optional npm cache directory 60 | .npm 61 | 62 | # Optional eslint cache 63 | .eslintcache 64 | 65 | # Microbundle cache 66 | .rpt2_cache/ 67 | .rts2_cache_cjs/ 68 | .rts2_cache_es/ 69 | .rts2_cache_umd/ 70 | 71 | # Optional REPL history 72 | .node_repl_history 73 | 74 | # Output of 'npm pack' 75 | *.tgz 76 | 77 | # Yarn Integrity file 78 | .yarn-integrity 79 | 80 | # dotenv environment variables file 81 | .env 82 | .env.test 83 | 84 | # parcel-bundler cache (https://parceljs.org/) 85 | .cache 86 | 87 | # Next.js build output 88 | .next 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # Serverless directories 104 | .serverless/ 105 | 106 | # FuseBox cache 107 | .fusebox/ 108 | 109 | # DynamoDB Local files 110 | .dynamodb/ 111 | 112 | # TernJS port file 113 | .tern-port 114 | -------------------------------------------------------------------------------- /cspell-zksync.txt: -------------------------------------------------------------------------------- 1 | // zkSync-related words 2 | matterlabs 3 | zkweb 4 | zksync 5 | zkscan 6 | zkscrypto 7 | libzkscrypto 8 | pubkey 9 | pubdata 10 | keccak 11 | musig 12 | WASM 13 | jsrpc 14 | backends 15 | ethsig 16 | ethop 17 | decentralization 18 | rollups 19 | zkrollup 20 | unencrypted 21 | permissionless 22 | trustlessness 23 | IERC 24 | Schnorr 25 | MuSig 26 | Merkle 27 | decentralised 28 | mainchain 29 | offchain 30 | processed 31 | zcli 32 | blockchains 33 | sidechain 34 | sidechains 35 | tokenomics 36 | validator's 37 | CHAINID 38 | // Names 39 | Vyper 40 | stimate 41 | samount 42 | Stichting 43 | Kingsfordweg 44 | RSIN 45 | ABDK 46 | Alef 47 | Zcon 48 | Paypal 49 | Numio 50 | MLTT 51 | USDCs 52 | dapi 53 | validiums 54 | validium 55 | Validium 56 | sharded 57 | 58 | // Used libraries 59 | numberish 60 | arrayify 61 | hexlify 62 | markdownlint 63 | ethersproject 64 | nomicfoundation 65 | nomiclabs 66 | Consensys 67 | zkforge 68 | zkcast 69 | Eigen 70 | IPFS 71 | viem 72 | Wagmi 73 | 74 | // Used programming language words 75 | printf 76 | charsets 77 | println 78 | fatalf 79 | allowfullscreen 80 | inttypes 81 | zbin 82 | Panicf 83 | Deri 84 | DERI 85 | Furucombo 86 | kwargs 87 | scaleb 88 | isinstance 89 | mload 90 | secp 91 | porco 92 | rosso 93 | insize 94 | MLOAD 95 | 96 | // ETC 97 | gitter 98 | signup 99 | signups 100 | precompiled 101 | checkmark 102 | Vitalik 103 | Buterin 104 | roadmap 105 | majeure 106 | conveniens 107 | reimplementing 108 | subsecond 109 | supermajority 110 | gemeente 111 | unauthorised 112 | Ethereum's 113 | SDKs 114 | EVM's 115 | EVM 116 | Göerli 117 | ETHUSDC 118 | USDCUSD 119 | ETHUS 120 | USDCUS 121 | ETHUSD 122 | Arbitrum 123 | Adamantium 124 | Immunefi 125 | Winternitz 126 | ewasm 127 | Evmla 128 | UUPS 129 | Uups 130 | 131 | // crypto events 132 | Edcon 133 | 134 | // Famous crypto people 135 | Gluchowski 136 | Vitalik's 137 | Buterin's 138 | multisignature 139 | onchain 140 | convertion 141 | Keyhash 142 | Armeabi 143 | scijava 144 | gluk 145 | 146 | bytecode 147 | timeframe 148 | mkdir 149 | zksolc 150 | zksyncrobot 151 | precompiles 152 | vyper 153 | zkvyper 154 | undol 155 | applyl 156 | Upgradability 157 | Initializable 158 | Hola 159 | mundo 160 | ISTN 161 | Zerion 162 | pepe 163 | PEPE 164 | Arweave 165 | Streamr 166 | TLDR 167 | -------------------------------------------------------------------------------- /tutorials/zksync-cli-quickstart/code/deploy/deploy-greeter.ts: -------------------------------------------------------------------------------- 1 | import { Wallet, utils } from "zksync-web3"; 2 | import * as ethers from "ethers"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 5 | 6 | // load env file 7 | import dotenv from "dotenv"; 8 | dotenv.config(); 9 | 10 | // load wallet private key from env file 11 | const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ""; 12 | 13 | if (!PRIVATE_KEY) 14 | throw "⛔️ Private key not detected! Add it to the .env file!"; 15 | 16 | // An example of a deploy script that will deploy and call a simple contract. 17 | export default async function (hre: HardhatRuntimeEnvironment) { 18 | console.log(`Running deploy script for the Greeter contract`); 19 | 20 | // Initialize the wallet. 21 | const wallet = new Wallet(PRIVATE_KEY); 22 | 23 | // Create deployer object and load the artifact of the contract you want to deploy. 24 | const deployer = new Deployer(hre, wallet); 25 | const artifact = await deployer.loadArtifact("Greeter"); 26 | 27 | // Estimate contract deployment fee 28 | const greeting = "Hi there!"; 29 | const deploymentFee = await deployer.estimateDeployFee(artifact, [greeting]); 30 | 31 | // ⚠️ OPTIONAL: You can skip this block if your account already has funds in L2 32 | // Deposit funds to L2 33 | // const depositHandle = await deployer.zkWallet.deposit({ 34 | // to: deployer.zkWallet.address, 35 | // token: utils.ETH_ADDRESS, 36 | // amount: deploymentFee.mul(2), 37 | // }); 38 | // // Wait until the deposit is processed on zkSync 39 | // await depositHandle.wait(); 40 | 41 | // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. 42 | // `greeting` is an argument for contract constructor. 43 | const parsedFee = ethers.utils.formatEther(deploymentFee.toString()); 44 | console.log(`The deployment is estimated to cost ${parsedFee} ETH`); 45 | 46 | const greeterContract = await deployer.deploy(artifact, [greeting]); 47 | 48 | //obtain the Constructor Arguments 49 | console.log( 50 | "constructor args:" + greeterContract.interface.encodeDeploy([greeting]) 51 | ); 52 | 53 | // Show the contract info. 54 | const contractAddress = greeterContract.address; 55 | console.log(`${artifact.contractName} was deployed to ${contractAddress}`); 56 | } 57 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/deploy/deploy.ts: -------------------------------------------------------------------------------- 1 | import hre from "hardhat"; 2 | import fs from "fs"; 3 | import { ethers } from "ethers"; 4 | import { Wallet } from "zksync-web3"; 5 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 6 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 7 | import dotenv from "dotenv"; 8 | 9 | dotenv.config(); 10 | 11 | // load wallet private key from env file 12 | const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ""; 13 | 14 | if (!PRIVATE_KEY) 15 | throw "⛔️ Private key not detected! Add it to the .env file!"; 16 | 17 | 18 | export default async function (hre: HardhatRuntimeEnvironment) { 19 | const wallet = new Wallet(PRIVATE_KEY); 20 | const deployer = new Deployer(hre, wallet); 21 | 22 | const nftContract = await deployContract("ExampleNFT", deployer); 23 | const marketplaceContract = await deployContract("StableMarketplace", deployer); 24 | 25 | // Update JSON file with addresses 26 | updateAddressesFile({ 27 | nft: nftContract.address, 28 | marketplace: marketplaceContract.address, 29 | }); 30 | } 31 | 32 | export const deployContract = async (contractName: string, deployer: Deployer) => { 33 | console.log(`Running deploy script for the PriceChecker contract`); 34 | 35 | // const artifact = await deployer.loadArtifact("PriceChecker"); 36 | const artifact = await deployer.loadArtifact(contractName); 37 | 38 | // Estimate contract deployment fee 39 | const deploymentFee = await deployer.estimateDeployFee(artifact, []); 40 | 41 | // ⚠️ OPTIONAL: You can skip this block if your account already has funds in L2 42 | // Deposit funds to L2 43 | // const depositHandle = await deployer.zkWallet.deposit({ 44 | // to: deployer.zkWallet.address, 45 | // token: utils.ETH_ADDRESS, 46 | // amount: deploymentFee.mul(2), 47 | // }); 48 | // // Wait until the deposit is processed on zkSync 49 | // await depositHandle.wait(); 50 | 51 | // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. 52 | // `greeting` is an argument for contract constructor. 53 | const parsedFee = ethers.utils.formatEther(deploymentFee.toString()); 54 | console.log(`The deployment is estimated to cost ${parsedFee} ETH`); 55 | 56 | const contract = await deployer.deploy(artifact); 57 | 58 | // Show the contract info. 59 | const contractAddress = contract.address; 60 | console.log(`${artifact.contractName} was deployed to ${contractAddress}`); 61 | return contract; 62 | } 63 | 64 | function updateAddressesFile(addresses: { nft: string; marketplace: string }) { 65 | const addressesFilePath = `./src/config/${hre.network.name}-addresses.json`; 66 | console.log(`Saving addresses to ${addressesFilePath}`); 67 | fs.writeFileSync( 68 | addressesFilePath, 69 | JSON.stringify(addresses, null, 2) + "\n" 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/Marketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 5 | 6 | contract Marketplace { 7 | enum OrderStatus { 8 | ACTIVE, 9 | CANCELED, 10 | EXECUTED 11 | } 12 | 13 | struct SellOrder { 14 | address nftContractAddress; 15 | uint256 tokenId; 16 | address creator; 17 | uint256 price; 18 | OrderStatus status; 19 | } 20 | 21 | SellOrder[] private sellOrders; 22 | 23 | function postSellOrder( 24 | address nftContractAddress, 25 | uint256 tokenId, 26 | uint256 price 27 | ) external { 28 | // Check if tokenId is owned by tx sender 29 | IERC721 nftContract = IERC721(nftContractAddress); 30 | require(nftContract.ownerOf(tokenId) == msg.sender); 31 | 32 | // Transfer NFT token to the contract address 33 | // Sender needs to approve the transfer before posting sell order 34 | nftContract.transferFrom(msg.sender, address(this), tokenId); 35 | 36 | // Save order in the sellOrders mapping 37 | sellOrders.push( 38 | SellOrder( 39 | nftContractAddress, 40 | tokenId, 41 | msg.sender, 42 | price, 43 | OrderStatus.ACTIVE 44 | ) 45 | ); 46 | } 47 | 48 | function cancelOrder(uint256 orderId) external { 49 | SellOrder storage order = sellOrders[orderId]; 50 | 51 | // Only order creator can cancel the order 52 | require(order.creator == msg.sender); 53 | 54 | // Transfer NFT back to order creator 55 | IERC721 nftContract = IERC721(order.nftContractAddress); 56 | nftContract.transferFrom(address(this), msg.sender, order.tokenId); 57 | 58 | // Update order status 59 | order.status = OrderStatus.CANCELED; 60 | } 61 | 62 | function buy(uint256 orderId) external payable { 63 | // Order must exist and be in the active state 64 | SellOrder storage order = sellOrders[orderId]; 65 | require(order.status == OrderStatus.ACTIVE); 66 | 67 | // Check transfered ETH value 68 | uint256 expectedEthAmount = _getPriceFromOrder(order); 69 | require(expectedEthAmount <= msg.value); 70 | 71 | // Transfer NFT to buyer 72 | IERC721 nftContract = IERC721(order.nftContractAddress); 73 | nftContract.transferFrom(address(this), msg.sender, order.tokenId); 74 | 75 | // Mark order as executed 76 | order.status = OrderStatus.EXECUTED; 77 | } 78 | 79 | function _getPriceFromOrder( 80 | SellOrder memory order 81 | ) internal view virtual returns (uint256) { 82 | return order.price; 83 | } 84 | 85 | // Getters for the UI 86 | function getPrice(uint256 orderId) public view returns (uint256) { 87 | SellOrder storage order = sellOrders[orderId]; 88 | return _getPriceFromOrder(order); 89 | } 90 | 91 | function getAllOrders() public view returns (SellOrder[] memory) { 92 | return sellOrders; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/styles.scss: -------------------------------------------------------------------------------- 1 | .App { 2 | font-family: 'Poppins', sans-serif; 3 | text-align: center; 4 | color: #333; 5 | 6 | #logo { 7 | position: fixed; 8 | top: 30px; 9 | left: 30px; 10 | font-size: 18px; 11 | font-weight: 500; 12 | color: #3e80c8; 13 | border-bottom: 3px solid #3e80c8; 14 | } 15 | 16 | .card-with-shadow { 17 | // Blue version 18 | box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(164, 201, 250, 0.4) 0px 0px 0px 4px; 19 | 20 | // Light shadow version 21 | // box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; 22 | 23 | padding: 14px; 24 | border-radius: 25px; 25 | } 26 | 27 | .increase-on-hover { 28 | transition: all ease 0.3s; 29 | &:hover { 30 | transform: scale(1.04); 31 | } 32 | } 33 | 34 | #wallet-connector { 35 | position: fixed; 36 | top: 30px; 37 | right: 30px; 38 | color: #3e80c8; 39 | a { 40 | color: #3e80c8; 41 | } 42 | } 43 | 44 | #powered-by-redstone { 45 | position: fixed; 46 | 47 | // Near logo 48 | // top: 90px; 49 | // left: 48px; 50 | 51 | // Bottom left 52 | bottom: 30px; 53 | left: 30px; 54 | 55 | font-size: 12px; 56 | // text-align: left; 57 | 58 | img { 59 | position: relative; 60 | top: 5px; 61 | left: 4px; 62 | } 63 | } 64 | 65 | #main-content { 66 | max-width: 800px; 67 | margin: auto; 68 | margin-top: 30px; 69 | display: grid; 70 | grid-template-columns: 50% 50%; 71 | padding: 0; 72 | 73 | h2 { 74 | border-bottom: 1px solid #ddd; 75 | padding-top: 20px; 76 | padding-bottom: 20px; 77 | margin-top: 0; 78 | font-weight: 400; 79 | } 80 | 81 | .cards-container { 82 | display: flex; 83 | flex-wrap: wrap; 84 | justify-content: center; 85 | 86 | .card { 87 | width: 300px; 88 | height: 80px; 89 | 90 | // Light gray line shadow border 91 | box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px; 92 | 93 | // Light shadow version 94 | // box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; 95 | 96 | margin: 8px; 97 | margin-bottom: 10px; 98 | display: flex; 99 | padding: 0px 25px; 100 | justify-content: space-between; 101 | align-items: center; 102 | position: relative; 103 | } 104 | } 105 | 106 | #nft-secion { 107 | border-right: 1px solid #ddd; 108 | min-height: 120vh; 109 | 110 | .mint-new-nft-link { 111 | margin-top: 20px; 112 | color: #777; 113 | } 114 | } 115 | 116 | .nft-token-id { 117 | font-size: 18px; 118 | } 119 | 120 | img.nft-icon { 121 | width: 50px; 122 | height: 50px; 123 | margin-right: 20px; 124 | } 125 | 126 | .nft-card { 127 | .left { 128 | display: flex; 129 | align-items: center; 130 | } 131 | 132 | .price { 133 | font-size: 14px; 134 | } 135 | } 136 | } 137 | 138 | a.button { 139 | color: #555; 140 | text-decoration: none; 141 | } 142 | 143 | a.button:hover { 144 | font-weight: 500; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Community tutorials 2 | 3 | ## 🚨 [DEPRECATED] This repository is no longer maintained 4 | This repository is deprecated and no longer actively maintained. 5 | Please use the [community-code repository](https://github.com/zksync-community-hub/community-code) instead. 6 | 7 | This repository contains different tutorials submitted by community members. Tutorials will be referenced in the [zkSync Community Code documentation website](https://code.zksync.io/). 8 | 9 | We encourage authors to keep their tutorials updated. 10 | 11 | ### zkSync Tutorials 12 | 13 | For tutorials created and maintained by the zkSync team, [check out this repository here](https://github.com/matter-labs/tutorials). 14 | 15 | ## Tutorial requirements 16 | 17 | - All tutorials must showcase how to develop applications on zkSync Era. 18 | - Tutorials must take a neutral stance and refrain from promoting projects. 19 | - Tutorials must be an original and NOT a work that was previously published. 20 | - You must be the rightful intellectual property owner (author) of your submission. 21 | - Tutorials can contain relevant external sources, only when referenced accordingly. 22 | - Tutorials must have working code to support the tutorial. 23 | - Tutorials must be provided following the [guidelines in this repository](#tutorial-guidelines). 24 | 25 | ## Tutorial guidelines 26 | 27 | - Create a new folder inside `tutorials` with the name of your tutorial in *kebab-case*, e.g. `my-awesome-tutorial`. 28 | - In this folder, create a `TUTORIAL.md`. The tutorial must follow this structure: 29 | - Title (Level 1 heading) 30 | - Introduction (Level 3 heading): explain what is going to be built in this tutorial. 31 | - Prerequisites (Level 2 heading): system and technical requirements. **Indicate the specific versions of packages and compilers used to build the project.** 32 | - Build time! (Level 2 heading): step-by-step details on how to build the project. 33 | - Step 1 — Doing the First Thing (Level 3 heading) 34 | - Step 2 — Doing the Next Thing (Level 3 heading) 35 | - Step n — Doing the Last Thing (Level 3 heading) 36 | - Conclusion (Level 2 heading): summarize what the reader has accomplished by following your tutorial. 37 | - Create a `code` folder with any code to support the tutorial. 38 | - Create an `images` folder with any images to support the tutorial. 39 | - If your tutorial contains images, make sure to compress them using https://squoosh.app/ before adding them to the `images` folder. 40 | - Add the tutorial details to the `tutorials.json` file. Each tutorial must have: 41 | 42 | ```json 43 | { 44 | "title": "", // 60 characters max 45 | "description": "", // 280 characters max 46 | "tags": [ // 4 tags max. Examples: oracles, devtools, nfts, tokens, indexers, 47 | "", 48 | "" 49 | ], 50 | "time": "", // time taken to complete tutorial in hours, e.g. "1 hour", "2 to 4 hours" 51 | "author": "", // person, project, or company 52 | "slug": "" // the tutorial folder name inside `/tutorials` 53 | } 54 | ``` 55 | 56 | Use the [TUTORIAL_TEMPLATE](./tutorials/TUTORIAL_TEMPLATE.md) and [zksync-cli-quickstart tutorial](./tutorials/zksync-cli-quickstart/) as a reference. 57 | 58 | ## How to submit a tutorial 59 | 60 | - Clone this repo. 61 | - Create a new branch and [add your tutorial following the guidelines](#tutorial-guidelines). 62 | - Make sure [your tutorial follows the requirements](#tutorial-requirements) 63 | - Create a pull request. 64 | 65 | ## Linting, Formatting, and Spell Check 66 | 67 | Before submitting your tutorial, ensure that your content adheres to the repository's standards by running the following checks: 68 | 69 | - Formatting with Prettier: `yarn lint:fmt` 70 | - Spell Check: `yarn lint:spell` - If lint:spell doesn't recognize a word, and you’re sure that it’s correct, consider adding it to cspell-zksync.txt. 71 | - Linting: `yarn lint:mdl` 72 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/config/marketplace-abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "orderId", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "buy", 11 | "outputs": [], 12 | "stateMutability": "payable", 13 | "type": "function" 14 | }, 15 | { 16 | "inputs": [ 17 | { 18 | "internalType": "uint256", 19 | "name": "orderId", 20 | "type": "uint256" 21 | } 22 | ], 23 | "name": "cancelOrder", 24 | "outputs": [], 25 | "stateMutability": "nonpayable", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "getAllOrders", 31 | "outputs": [ 32 | { 33 | "components": [ 34 | { 35 | "internalType": "address", 36 | "name": "nftContractAddress", 37 | "type": "address" 38 | }, 39 | { 40 | "internalType": "uint256", 41 | "name": "tokenId", 42 | "type": "uint256" 43 | }, 44 | { 45 | "internalType": "address", 46 | "name": "creator", 47 | "type": "address" 48 | }, 49 | { 50 | "internalType": "uint256", 51 | "name": "price", 52 | "type": "uint256" 53 | }, 54 | { 55 | "internalType": "enum Marketplace.OrderStatus", 56 | "name": "status", 57 | "type": "uint8" 58 | } 59 | ], 60 | "internalType": "struct Marketplace.SellOrder[]", 61 | "name": "", 62 | "type": "tuple[]" 63 | } 64 | ], 65 | "stateMutability": "view", 66 | "type": "function" 67 | }, 68 | { 69 | "inputs": [], 70 | "name": "getMaxBlockTimestampDelay", 71 | "outputs": [ 72 | { 73 | "internalType": "uint256", 74 | "name": "", 75 | "type": "uint256" 76 | } 77 | ], 78 | "stateMutability": "view", 79 | "type": "function" 80 | }, 81 | { 82 | "inputs": [], 83 | "name": "getMaxDataTimestampDelay", 84 | "outputs": [ 85 | { 86 | "internalType": "uint256", 87 | "name": "", 88 | "type": "uint256" 89 | } 90 | ], 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "inputs": [ 96 | { 97 | "internalType": "uint256", 98 | "name": "orderId", 99 | "type": "uint256" 100 | } 101 | ], 102 | "name": "getPrice", 103 | "outputs": [ 104 | { 105 | "internalType": "uint256", 106 | "name": "", 107 | "type": "uint256" 108 | } 109 | ], 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "inputs": [ 115 | { 116 | "internalType": "address", 117 | "name": "_signer", 118 | "type": "address" 119 | } 120 | ], 121 | "name": "isSignerAuthorized", 122 | "outputs": [ 123 | { 124 | "internalType": "bool", 125 | "name": "", 126 | "type": "bool" 127 | } 128 | ], 129 | "stateMutability": "pure", 130 | "type": "function" 131 | }, 132 | { 133 | "inputs": [ 134 | { 135 | "internalType": "uint256", 136 | "name": "_receivedTimestamp", 137 | "type": "uint256" 138 | } 139 | ], 140 | "name": "isTimestampValid", 141 | "outputs": [ 142 | { 143 | "internalType": "bool", 144 | "name": "", 145 | "type": "bool" 146 | } 147 | ], 148 | "stateMutability": "view", 149 | "type": "function" 150 | }, 151 | { 152 | "inputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "nftContractAddress", 156 | "type": "address" 157 | }, 158 | { 159 | "internalType": "uint256", 160 | "name": "tokenId", 161 | "type": "uint256" 162 | }, 163 | { 164 | "internalType": "uint256", 165 | "name": "price", 166 | "type": "uint256" 167 | } 168 | ], 169 | "name": "postSellOrder", 170 | "outputs": [], 171 | "stateMutability": "nonpayable", 172 | "type": "function" 173 | } 174 | ] 175 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/test/stable-marketplace.test.ts: -------------------------------------------------------------------------------- 1 | import * as hre from "hardhat"; 2 | import { Provider, Wallet } from "zksync-web3"; 3 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 4 | import { BigNumber, Contract, ethers } from "ethers"; 5 | import { WrapperBuilder } from "@redstone-finance/evm-connector"; 6 | import { expect } from "chai"; 7 | import { DEPLOYER_WALLET_PK, SELLER_RICH_WALLET_PK, BUYER_RICH_WALLET_PK, deployContract } from "./common"; 8 | 9 | describe("Stable marketplace core functions test", function () { 10 | let stableMarketplaceContract: Contract, 11 | exampleNFTContract: Contract, 12 | nftContractAddress: string, 13 | marketplaceAddress: string, 14 | wrappedMarketplaceContract: Contract, 15 | seller: Wallet, 16 | buyer: Wallet; 17 | 18 | const tokenId = 1; 19 | 20 | it("Should deploy contracts", async function () { 21 | const provider = Provider.getDefaultProvider(); 22 | const wallet = new Wallet(DEPLOYER_WALLET_PK, provider); 23 | const deployer = new Deployer(hre, wallet); 24 | 25 | // Deploy marketplace contract 26 | stableMarketplaceContract = await deployContract(deployer, "StableMarketplace") 27 | marketplaceAddress = stableMarketplaceContract.address; 28 | 29 | // Deploy NFT contract 30 | exampleNFTContract = await deployContract(deployer, "ExampleNFT") 31 | nftContractAddress = exampleNFTContract.address; 32 | 33 | // Should map users 34 | seller = new Wallet(SELLER_RICH_WALLET_PK, provider);; 35 | buyer = new Wallet(BUYER_RICH_WALLET_PK, provider); 36 | }); 37 | 38 | it("Should mint NFT", async function () { 39 | // Mint first NFT 40 | const mintTx1 = await exampleNFTContract.mint(); 41 | await mintTx1.wait(); 42 | }); 43 | 44 | it("Seller should post sell order for token 2 with stable USD price", async function () { 45 | // Approve NFT transfer 46 | const approveTx = await exampleNFTContract.approve( 47 | stableMarketplaceContract.address, 48 | tokenId 49 | ); 50 | await approveTx.wait(); 51 | 52 | // Post sell order 53 | const usdPrice = ethers.utils.parseEther("100"); 54 | const postOrderTx = await stableMarketplaceContract.postSellOrder( 55 | nftContractAddress, 56 | tokenId, 57 | usdPrice 58 | ); 59 | await postOrderTx.wait(); 60 | 61 | // Check NFT owner (marketplace should own the NFT now) 62 | expect(await exampleNFTContract.ownerOf(tokenId)).to.equal( 63 | marketplaceAddress 64 | ); 65 | }); 66 | 67 | it("Should wrap marketplace contract with redstone wrapper", async function () { 68 | const contract = stableMarketplaceContract.connect(buyer); 69 | wrappedMarketplaceContract = WrapperBuilder.wrap(contract).usingDataService( 70 | { 71 | dataServiceId: "redstone-main-demo", 72 | uniqueSignersCount: 1, 73 | dataFeeds: ["ETH"], 74 | }, 75 | ); 76 | }); 77 | 78 | it("Should get all orders", async function () { 79 | const allOrders = await stableMarketplaceContract.getAllOrders(); 80 | expect(allOrders.length).to.equal(1); 81 | expect(allOrders[0].tokenId.toString()).to.equal("1"); 82 | }); 83 | 84 | it("Buying should fail with smaller amount then seller requested", async function () { 85 | const orderId = 0; 86 | 87 | // Get expected ETH amount 88 | const expectedEthAmount = await wrappedMarketplaceContract.getPrice( 89 | orderId 90 | ); 91 | logExpectedAmount(expectedEthAmount); 92 | 93 | // Trying to buy (should fail) 94 | await expect( 95 | wrappedMarketplaceContract.buy(orderId, { 96 | value: expectedEthAmount.mul(99).div(100), 97 | }) 98 | ).to.be.reverted; 99 | }); 100 | 101 | it("Buyer should buy token for USD price expressed in ETH", async function () { 102 | const orderId = 0; 103 | 104 | // Get expected ETH amount 105 | const expectedEthAmount = await wrappedMarketplaceContract.getPrice( 106 | orderId 107 | ); 108 | logExpectedAmount(expectedEthAmount); 109 | 110 | // Send buy tx from user 2 wallet 111 | const buyTx = await wrappedMarketplaceContract.buy(orderId, { 112 | value: expectedEthAmount.mul(101).div(100), // a buffer for price movements 113 | }); 114 | await buyTx.wait(); 115 | 116 | // Check NFT owner 117 | const nftOwner = await exampleNFTContract.ownerOf(tokenId); 118 | expect(nftOwner).to.equal(buyer.address); 119 | }); 120 | }); 121 | 122 | function logExpectedAmount(amount: BigNumber) { 123 | console.log( 124 | `Expected ETH amount: ${ethers.utils.formatEther(amount.toString())}` 125 | ); 126 | } 127 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/test/marketplace.test.ts: -------------------------------------------------------------------------------- 1 | import * as hre from "hardhat"; 2 | import { Contract, Provider, Wallet } from "zksync-web3"; 3 | import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; 4 | import { BigNumber, ethers } from "ethers"; 5 | import { expect } from "chai"; 6 | import { DEPLOYER_WALLET_PK, SELLER_RICH_WALLET_PK, BUYER_RICH_WALLET_PK, deployContract } from "./common"; 7 | 8 | describe("Marketplace core functions test", function () { 9 | let marketplaceContract: Contract, 10 | exampleNFTContract: Contract, 11 | nftContractAddress: string, 12 | marketplaceAddress: string, 13 | seller: Wallet, 14 | buyer: Wallet; 15 | 16 | const tokenId = 1; 17 | 18 | it("Should deploy contracts", async function () { 19 | const provider = Provider.getDefaultProvider(); 20 | const wallet = new Wallet(DEPLOYER_WALLET_PK, provider); 21 | const deployer = new Deployer(hre, wallet); 22 | 23 | // Deploy marketplace contract 24 | marketplaceContract = await deployContract(deployer, "Marketplace") 25 | marketplaceAddress = marketplaceContract.address; 26 | 27 | // Deploy NFT contract 28 | exampleNFTContract = await deployContract(deployer, "ExampleNFT") 29 | nftContractAddress = exampleNFTContract.address; 30 | 31 | // Should map users 32 | seller = new Wallet(SELLER_RICH_WALLET_PK, provider);; 33 | buyer = new Wallet(BUYER_RICH_WALLET_PK, provider); 34 | }); 35 | 36 | it("Should mint NFT", async function () { 37 | // Mint first NFT 38 | const mintTx1 = await exampleNFTContract.mint(); 39 | await mintTx1.wait(); 40 | }); 41 | 42 | it("Seller should post sell order for token 1 with ETH price", async function () { 43 | // Approve NFT transfer 44 | const approveTx = await exampleNFTContract.approve( 45 | marketplaceContract.address, 46 | tokenId 47 | ); 48 | await approveTx.wait(); 49 | 50 | // Post sell order 51 | const ethPrice = ethers.utils.parseEther("1"); 52 | const postOrderTx = await marketplaceContract.postSellOrder( 53 | nftContractAddress, 54 | tokenId, 55 | ethPrice 56 | ); 57 | await postOrderTx.wait(); 58 | 59 | // Check NFT owner (marketplace should own the NFT now) 60 | expect(await exampleNFTContract.ownerOf(tokenId)).to.equal( 61 | marketplaceAddress 62 | ); 63 | }); 64 | 65 | it("Should get all orders", async function () { 66 | const allOrders = await marketplaceContract.getAllOrders(); 67 | expect(allOrders.length).to.equal(1); 68 | expect(allOrders[0].tokenId.toString()).to.equal("1"); 69 | }); 70 | 71 | it("Buying should fail with smaller amount then seller requested", async function () { 72 | const orderId = 0; 73 | 74 | // Get expected ETH amount 75 | const expectedEthAmount = await marketplaceContract.getPrice(orderId); 76 | logExpectedAmount(expectedEthAmount); 77 | 78 | await expect( 79 | marketplaceContract.connect(buyer).buy(orderId, { 80 | value: expectedEthAmount.mul(99).div(100), // We reduce the value by 1% 81 | }) 82 | ).to.be.reverted; 83 | }); 84 | 85 | it("Buyer should buy token 1 for ETH price", async function () { 86 | const orderId = 0; 87 | 88 | // Get expected ETH amount 89 | const expectedEthAmount = await marketplaceContract.getPrice(orderId); 90 | logExpectedAmount(expectedEthAmount); 91 | 92 | // Send buy tx from buyer's wallet 93 | const buyTx = await marketplaceContract.connect(buyer).buy(orderId, { 94 | value: expectedEthAmount.mul(101).div(100), // a buffer for price movements 95 | }); 96 | await buyTx.wait(); 97 | 98 | // Check NFT owner 99 | const nftOwner = await exampleNFTContract.ownerOf(tokenId); 100 | expect(nftOwner).to.equal(buyer.address); 101 | }); 102 | 103 | it("Should post and cancel order", async function () { 104 | const tokenId = 1; 105 | 106 | // Approve NFT transfer 107 | const approveTx = await exampleNFTContract 108 | .connect(buyer) 109 | .approve(marketplaceContract.address, tokenId); 110 | await approveTx.wait(); 111 | 112 | // Post sell order 113 | const ethPrice = ethers.utils.parseEther("1"); 114 | const postOrderTx = await marketplaceContract 115 | .connect(buyer) 116 | .postSellOrder(nftContractAddress, tokenId, ethPrice); 117 | await postOrderTx.wait(); 118 | 119 | // Cancel order 120 | const cancelTx = await marketplaceContract.connect(buyer).cancelOrder(1); 121 | await cancelTx.wait(); 122 | }); 123 | }); 124 | 125 | function logExpectedAmount(amount: BigNumber) { 126 | console.log( 127 | `Expected ETH amount: ${ethers.utils.formatEther(amount.toString())}` 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /tutorials/web3modal/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # Create a website and connect to zkSync ERA with your wallet 2 | 3 | ### Introduction 4 | 5 | In this tutorial, you will learn how to create a website and connect to zkSync ERA with your wallet. We are going to use Next.js for this example but you can use any other frontend framework. 6 | 7 | The Web3Modal SDK allows you to easily connect your Web3 dapp with wallets. It provides a simple and intuitive interface for dapps to request actions such as signing transactions and interacting with smart contracts on the blockchain. 8 | 9 | ## Prerequisites 10 | 11 | - Node.js (^18.17.1) and NPM 12 | - An wallet that supports zkSync Era 13 | 14 | ## Build time 15 | 16 | ### Step 1 — Installation 17 | 18 | Let’s create our app now, we’re going to be using Next.js, Wagmi and Web3Modal v3 for this tutorial 19 | 20 | Let’s start a new project by running 21 | 22 | ```sh 23 | npx create-next-app 24 | ``` 25 | 26 | Now we’ll install Wagmi and Web3Modal which will help us to showcase a modal with different wallets that users can connect to. 27 | 28 | ```sh 29 | npm install @web3modal/wagmi wagmi viem 30 | ``` 31 | 32 | ### Step 2 — Implementation: Web3Modal.tsx file 33 | 34 | Let's create a `Web3Modal.tsx` file inside a `context` folder, and we’ll import the following dependencies from Web3Modal and Wagmi 35 | 36 | ```ts 37 | import { createWeb3Modal, defaultWagmiConfig } from "@web3modal/wagmi/react"; 38 | 39 | import { WagmiConfig } from "wagmi"; 40 | import { zkSync, zkSyncTestnet } from "wagmi/chains"; 41 | ``` 42 | 43 | We now need to get a Project ID from [WalletConnect’s Cloud website](https://cloud.walletconnect.com/) 44 | 45 | ```ts 46 | const projectId = "YOUR_PROJECT_ID"; 47 | ``` 48 | 49 | Once that’s done we can create our wagmiConfig instance 50 | 51 | ```ts 52 | const metadata = { 53 | name: "Web3Modal & zkSync", 54 | description: "Web3Modal & zkSync Tutorial", 55 | url: "https://web3modal.com", 56 | icons: ["https://avatars.githubusercontent.com/u/37784886"], 57 | }; 58 | const chains = [zkSync, zkSyncTestnet]; 59 | const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata }); 60 | ``` 61 | 62 | Now we can create a Web3Modal instance to initiate our modal, let's also add zkSync as the default chain. 63 | 64 | ```ts 65 | createWeb3Modal({ wagmiConfig, projectId, chains, defaultChain: zkSync }); 66 | ``` 67 | 68 | We’ll now add the WagmiConfig component, this is how our Web3Modal.tsx file should look like 69 | 70 | ```ts 71 | "use client"; 72 | 73 | import { PropsWithChildren } from "react"; 74 | 75 | import { WagmiConfig } from "wagmi"; 76 | import { createWeb3Modal, defaultWagmiConfig } from "@web3modal/wagmi/react"; 77 | import { zkSync, zkSyncTestnet } from "wagmi/chains"; 78 | 79 | const projectId = "YOUR_PROJECT_ID"; 80 | 81 | const metadata = { 82 | name: "Web3Modal & zkSync", 83 | description: "Web3Modal & zkSync Tutorial", 84 | url: "https://web3modal.com", 85 | icons: ["https://avatars.githubusercontent.com/u/37784886"], 86 | }; 87 | const chains = [zkSync, zkSyncTestnet]; 88 | const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata }); 89 | 90 | createWeb3Modal({ wagmiConfig, projectId, chains, defaultChain: zkSync }); 91 | 92 | export function Web3Modal({ children }: PropsWithChildren) { 93 | return {children}; 94 | } 95 | ``` 96 | 97 | ### Step 3 — Implementation: layout.tsx file 98 | 99 | Now in our `app/layout.tsx` file we'll import our Web3Modal component 100 | 101 | ```ts 102 | import type { Metadata } from "next"; 103 | import { PropsWithChildren } from "react"; 104 | import "./globals.css"; 105 | 106 | import { Web3Modal } from "./context/Web3Modal"; 107 | 108 | export const metadata: Metadata = { 109 | title: "Web3Modal & zkSync", 110 | description: "Web3Modal & zkSync Tutorial", 111 | }; 112 | 113 | export default function RootLayout({ children }: PropsWithChildren) { 114 | return ( 115 | 116 | 117 | {children} 118 | 119 | 120 | ); 121 | } 122 | ``` 123 | 124 | ### Step 3 — Implementation: page.tsx file 125 | 126 | Now we can add the Web3Modal button web component anywhere in our application 127 | 128 | ```ts 129 | import styles from "./page.module.css"; 130 | 131 | export default function Home() { 132 | return ( 133 |
134 | 135 |
136 | ); 137 | } 138 | ``` 139 | 140 | ## Conclusion 141 | 142 | In this tutorial, you learned how to create a website and connect to zkSync ERA with your wallet. You can now continue this project with [Wagmi hooks and functions](https://wagmi.sh/react/hooks/useContractRead) to start interacting directly with zkSync ERA in your new website. 143 | -------------------------------------------------------------------------------- /tutorials/the-graph/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # Deploy a zkSync Subgraph Tracking a Specific Address 2 | 3 | ### Introduction 4 | 5 | In this tutorial, you will learn how to deploy a subgraph that tracks a specific address on zkSync Era mainnet. Deploying graphs is a great way to query data from network historically and in real-time. 6 | 7 | The Graph is a decentralized protocol for indexing and querying data from blockchains. The Graph serves queries over data that is easily stored, decentralized, and secured by the blockchain. You will learn how to deploy a subgraph that tracks a specific address on zkSync Era mainnet. You can use this subgraph to query data from zkSync Era mainnet. 8 | 9 | ## Prerequisites 10 | 11 | - Node.js (^18.17.1) and NPM 12 | - Yarn (^1.22.19) 13 | - An account with ETH on zkSync Era testnet 14 | 15 | ## Build time 16 | 17 | ### Step 1 — Visit theGraph Studio and Connect Wallet 18 | 19 | - Visit 20 | - Connect your wallet 21 | 22 | ### Step 2 — Create a new Subgraph 23 | 24 | - Click on the button to create a new subgraph 25 | - Enter the name of the subgraph 26 | - Select the network you want to deploy the subgraph on, in this case: `zkSync Era (Subgraph Only)` 27 | 28 | ### Step 3 — Install the Graph CLI 29 | 30 | - Install the Graph CLI with `npm install -g @graphprotocol/graph-cli` 31 | - Initialize the Graph project with `graph init --studio zksync-thegraph-tutorial` 32 | - Select `Ethereum` as the protocol 33 | - Select `zksync-era` as the Ethereum network 34 | - Provide the contract address you wish to track, for this tutorial, the PEPE token: `0xFD282F16a64c6D304aC05d1A58Da15bed0467c71` 35 | - Provide an abi filepath for the contract, in this case the `pepe_abi.json` file, as a path from this project root if this is your current working directory: `./code/pepe_abi.json` 36 | - Provide a block number to start indexing from, say `13761747` (using a higher block number will lead to a quicker graph deployment if you're following this tutorial in the future) 37 | - Approve the next steps and skip adding another contract 38 | 39 | ### Step 4 — Authenticate and Deploy the Subgraph 40 | 41 | - Authenticate with `graph auth --studio ` (you can find this command with the access token in the studio, which you can copy and paste) 42 | - Change directory to the subgraph with `cd zksync-thegraph-tutorial` 43 | - Build the subgraph with `graph codegen && graph build` 44 | - Deploy the subgraph with `graph deploy --studio zksync-thegraph-tutorial` 45 | 46 | ### Step 5 — Query the Subgraph 47 | 48 | - Visit the [studio](https://thegraph.com/studio/) and then the section for the overview on this created subgraph and click on the `Playground` tab 49 | - The tab will already have a pre-written query for you, which you can run by clicking on the `play` button. The query will look as follows: 50 | 51 | ```graphql 52 | { 53 | approvals(first: 5) { 54 | id 55 | owner 56 | spender 57 | value 58 | } 59 | bridgeBurns(first: 5) { 60 | id 61 | _account 62 | _amount 63 | blockNumber 64 | } 65 | } 66 | ``` 67 | 68 | - You can also write your own query, for example, to query the `approvals` table for a specific `owner` address, you can write the following query: 69 | 70 | ```graphql 71 | { 72 | approvals(where: { owner: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" }) { 73 | id 74 | owner 75 | spender 76 | value 77 | } 78 | } 79 | ``` 80 | 81 | - You can also query the `bridgeBurns` table for a specific `account` address, you can write the following query: 82 | 83 | ```graphql 84 | { 85 | bridgeBurns( 86 | where: { _account: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" } 87 | ) { 88 | id 89 | _account 90 | _amount 91 | blockNumber 92 | } 93 | } 94 | ``` 95 | 96 | - You can also query the `bridgeMints` table for a specific `account` address, you can write the following query: 97 | 98 | ```graphql 99 | { 100 | bridgeMints( 101 | where: { _account: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" } 102 | ) { 103 | id 104 | _account 105 | _amount 106 | blockNumber 107 | } 108 | } 109 | ``` 110 | 111 | - You can interact with this subgraph by querying the data from the subgraph. You can also use this subgraph to build a frontend application that interacts with the subgraph. 112 | 113 | ## Conclusion 114 | 115 | In this tutorial, you learned how to deploy a subgraph that tracks a specific address on zkSync Era testnet. You can now use this subgraph to query data from zkSync Era mainnet in realtime and historically. You can also use this subgraph to build a frontend application that interacts with the subgraph and is reliant on data from the blockchain. 116 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Card } from "./Card"; 3 | import blockchain from "../core/blockchain"; 4 | import "../styles.scss"; 5 | 6 | interface Order { 7 | orderId: string; 8 | tokenId: string; 9 | usdPrice: string; 10 | creator: string; 11 | } 12 | 13 | export default function App() { 14 | // App state 15 | const [address, setAddress] = useState(null); 16 | const [orders, setOrders] = useState([]); 17 | const [ownedNfts, setOwnedNfts] = useState([]); 18 | 19 | // On page load 20 | useEffect(() => { 21 | const onPageLoad = async () => { 22 | await connectOrUpdateWallet(); 23 | updateOwnedNfts(); 24 | updateOrders(); 25 | blockchain.onAddressChange(async () => { 26 | await connectOrUpdateWallet(); 27 | await updateOwnedNfts(); 28 | }); 29 | }; 30 | onPageLoad().catch(console.error); 31 | }, []); 32 | 33 | async function connectOrUpdateWallet() { 34 | await blockchain.connectWallet(); 35 | const address = await blockchain.getUserAddress(); 36 | setAddress(address ?? null); 37 | } 38 | 39 | async function updateOwnedNfts() { 40 | const address = await blockchain.getUserAddress(); 41 | if (address) { 42 | const tokenIds = await blockchain.getOwnedNfts(address); 43 | setOwnedNfts((tokenIds ?? []).map((tokenId) => tokenId.toNumber())); 44 | } 45 | } 46 | 47 | async function updateOrders() { 48 | const orders = await blockchain.getAllOrders(); 49 | setOrders(orders); 50 | } 51 | 52 | async function mintNft() { 53 | await blockchain.mintNft(); 54 | await updateOwnedNfts(); 55 | } 56 | 57 | async function sellButtonClicked(tokenId: string) { 58 | const usdPrice = Number( 59 | prompt(`Please enter USD price for your NFT #${tokenId}`) 60 | ); 61 | await blockchain.postOrder({ tokenId, usdPrice }); 62 | await updateOrders(); 63 | await updateOwnedNfts(); 64 | } 65 | 66 | async function buyButtonClicked(orderId: string) { 67 | await blockchain.buy(orderId); 68 | await updateOrders(); 69 | await updateOwnedNfts(); 70 | } 71 | 72 | async function cancelButtonClicked(orderId: string) { 73 | await blockchain.cancelOrder(orderId); 74 | updateOrders(); 75 | updateOwnedNfts(); 76 | } 77 | 78 | function getOrderButtonDetails(order: Order) { 79 | return order.creator === address 80 | ? { 81 | text: "CANCEL", 82 | handler: cancelButtonClicked, 83 | color: "#F57C00", 84 | } 85 | : { 86 | text: `BUY`, 87 | handler: buyButtonClicked, 88 | color: "#0F9D58", 89 | }; 90 | } 91 | 92 | return ( 93 |
94 | {/* MAIN VIEW */} 95 |
96 | {/* MY TOKENS (LEFT SIDE) */} 97 |
98 |

My tokens

99 |
100 | {(ownedNfts ?? []).map((tokenId) => ( 101 | 109 | ))} 110 | 111 | 112 | + Mint new NFT 113 | 114 |
115 |
116 | 117 | {/* ORDERS (RIGHT SIDE) */} 118 |
119 |

Orders

120 |
121 | {(orders ?? []).map((order) => { 122 | const buttonDetails = getOrderButtonDetails(order); 123 | return ( 124 | buttonDetails.handler(order.orderId)} 131 | buttonTextColor={buttonDetails.color} 132 | /> 133 | ); 134 | })} 135 |
136 |
137 |
138 | 139 | {/* LOGO */} 140 | 141 | 142 | {/* WALLET SELECTOR */} 143 |
144 | {address ? ( 145 | blockchain.shortenAddress(address) 146 | ) : ( 147 | 148 | Connect wallet 149 | 150 | )} 151 |
152 | 153 | {/* POWERED BY REDSTONE MARK */} 154 |
155 | Powered by 156 | 157 | redstone-logo 158 | 159 |
160 |
161 | ); 162 | } 163 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/README.md: -------------------------------------------------------------------------------- 1 | # Example dApp - Stable price NFT marketplace 2 | 3 | This repo is designed to show how to build a dApp that uses [RedStone oracles](https://redstone.finance/) on [zkSync](https://zksync.io/). 4 | 5 | The repo contains an implementation of an NFT marketplace dApp with so-called "stable" price. It means that sellers can create sell orders (offers), specifying the price amount in USD. But buyers are able to pay with native coins, the required amount of which is calculated dynamically at the moment of the order execution. Repo lacks few crucial parts which will demonstrate how to integrate RedStone oracles and deploy dApp on zkSync Era Testnet. 6 | 7 | ## 🧑‍💻 Implementation 8 | 9 | We use [hardhat](https://hardhat.org/), version prepared for working on [zkSync](https://github.com/matter-labs/hardhat-zksync), and [ethers.js](https://docs.ethers.io/v5/) for deployment scripts and contract tests. Frontend is implemented in [React](https://reactjs.org/). 10 | 11 | ### Code structure 12 | 13 | ```bash 14 | ├── contracts # Solidity contracts 15 | │ ├── ExampleNFT.sol # Example ERC721 contract 16 | │ ├── Marketplace.sol # Simple NFT marketplace contract 17 | │ ├── StableMarketplace.sol # NFT marketplace contract with stable price 18 | │ └── ... 19 | ├── public # Folder with public html files and images for React app 20 | ├── deploy # Contract deployment script 21 | ├── src # React app source code 22 | │ ├── components 23 | │ │ ├── App.tsx # Main React component 24 | │ ├── core 25 | │ │ ├── blockchain.ts # TS module responsible for interaction with blockchain and contracts 26 | │ ├── config/ # Folder with contract ABIs and deployed contract addresses 27 | │ └── ... 28 | ├── test # Contract tests 29 | └── ... 30 | ``` 31 | 32 | ### Contracts 33 | 34 | #### ExampleNFT.sol 35 | 36 | `ExampleNFT` is a simple ERC721 contract with automated sequential token id assignment 37 | 38 | ```js 39 | function mint() external { 40 | _mint(msg.sender, nextTokenId); 41 | nextTokenId++; 42 | } 43 | ``` 44 | 45 | This contract extends `ERC721Enumerable` implementation created by the `@openzeppelin` team, which adds view functions for listing all tokens and tokens owned by a user. 46 | 47 | #### Marketplace.sol 48 | 49 | `Marketplace` is an NFT marketplace contract, which allows to post sell orders for any NFT token that follows [EIP-721 non-fungible token standard](https://eips.ethereum.org/EIPS/eip-721). It has the following functions: 50 | 51 | ```js 52 | 53 | // Created a new sell order 54 | // This function requires approval for transfer on the specified NFT token 55 | function postSellOrder(address nftContractAddress, uint256 tokenId, uint256 price) external {} 56 | 57 | // Only order creator can call this function 58 | function cancelOrder(uint256 orderId) external {} 59 | 60 | // Allows to get info about all orders (including canceled, and executed ones) 61 | function getAllOrders() public view returns (SellOrder[] memory) {} 62 | 63 | // Returns expected price in ETH for the given order 64 | function getPrice(uint256 orderId) public view returns (uint256) {} 65 | 66 | // Requires sending at least the minimal amount of ETH 67 | function buy(uint256 orderId) external payable {} 68 | 69 | ``` 70 | 71 | The implementation is quite straightforward, so we won't describe it here. You can check the full contract code in the [contracts/Marketplace.sol.](contracts/Marketplace.sol) 72 | 73 | #### StableMarketplace.sol 74 | 75 | `StableMarketplace` is the marketplace contract with the stable price support. It extends the `Marketplace.sol` implementation and only overrides its `_getPriceFromOrder` function. 76 | This contract will integrate RedStone oracles functionalities and will be described later. 77 | 78 | ### Frontend 79 | 80 | You can check the code of the React app in the `src` folder. We tried to simplify it as much as possible and leave only the core marketplace functions. 81 | 82 | The main UI logic is located in the `App.tsx` file, and the contract interaction logic is in the `blockchain.ts` file. 83 | 84 | If you take a look into the `blockchain.ts` file code, you'll notice that each contract call that needs to process RedStone data is made on a contract instance, that was wrapped by [@redstone-finance/evm-connector](https://www.npmjs.com/package/@redstone-finance/evm-connector). 85 | 86 | ### Tests 87 | 88 | We've used hardhat test framework to contract tests. All the tests are located in the [test](test/) folder. 89 | 90 | ## 🌎 Useful links 91 | 92 | - [Repo with examples](https://github.com/redstone-finance/redstone-evm-examples) 93 | - [RedStone Documentation](https://docs.redstone.finance/) 94 | - [RedStone Price Feeds](https://docs.redstone.finance/docs/smart-contract-devs/price-feeds) 95 | - [Data from any URL](https://docs.redstone.finance/docs/smart-contract-devs/custom-urls) 96 | - [NFT Data Feeds](https://docs.redstone.finance/docs/smart-contract-devs/nft-data-feeds) 97 | - [Randomness](https://docs.redstone.finance/docs/smart-contract-devs/randomness) 98 | 99 | ## 🙋‍♂️ Need help? 100 | 101 | Please feel free to contact the RedStone team [on Discord](https://redstone.finance/discord) if you have any questions. 102 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/core/blockchain.ts: -------------------------------------------------------------------------------- 1 | import { Web3Provider, Contract } from "zksync-web3"; 2 | // import { WrapperBuilder } from "@redstone-finance/evm-connector"; 3 | import { utils } from "ethers"; 4 | import localAddresses from "../config/zkSyncTestnet-addresses.json"; 5 | import nftAbi from "../config/nft-abi.json"; 6 | import marketplaceAbi from "../config/marketplace-abi.json"; 7 | import { zkSyncLocalTestnetChainId } from "../constants"; 8 | 9 | declare global { 10 | interface Window { 11 | ethereum: any; 12 | } 13 | } 14 | 15 | interface OrdersFromContract { 16 | tokenId: { toNumber: () => number }; 17 | price: number; 18 | creator: string; 19 | status: number; 20 | } 21 | 22 | const ABIs = { 23 | nft: nftAbi, 24 | marketplace: marketplaceAbi, 25 | }; 26 | 27 | ///////// NFT AND MARKETPLACE FUNCTIONS ///////// 28 | 29 | async function getOwnedNfts(address: string) { 30 | try { 31 | const nft = await getContractInstance("nft"); 32 | const nftCount = await nft.balanceOf(address); 33 | const tokenIds = []; 34 | for (let i = 0; i < nftCount; i++) { 35 | const tokenId = await nft.tokenOfOwnerByIndex(address, i); 36 | tokenIds.push(tokenId); 37 | } 38 | return tokenIds; 39 | } catch { 40 | const errText = "Error happened while fetching owned NFTs"; 41 | alert(errText); 42 | } 43 | } 44 | 45 | async function mintNft() { 46 | try { 47 | const nft = await getContractInstance("nft"); 48 | const tx = await nft.mint(); 49 | await tx.wait(); 50 | return tx; 51 | } catch { 52 | const errText = "Error happened while minting the NFT"; 53 | alert(errText); 54 | } 55 | } 56 | 57 | async function getAllOrders() { 58 | try { 59 | const marketplace = await getContractInstance("marketplace"); 60 | const orders = await marketplace.getAllOrders(); 61 | return (orders ?? []) 62 | .map((order: OrdersFromContract, index: number) => ({ 63 | orderId: index, 64 | tokenId: order.tokenId.toNumber(), 65 | usdPrice: utils.formatEther(order.price), 66 | creator: order.creator, 67 | status: order.status, 68 | })) 69 | .filter((order: OrdersFromContract) => order.status === 0); 70 | } catch { 71 | const errText = "Error happened while fetching all orders"; 72 | alert(errText); 73 | } 74 | } 75 | 76 | async function postOrder({ 77 | tokenId, 78 | usdPrice, 79 | }: { 80 | tokenId: string; 81 | usdPrice: number; 82 | }) { 83 | try { 84 | const marketplace = await getContractInstance("marketplace"); 85 | const nftContract = await getContractInstance("nft"); 86 | 87 | // Sending approve tx 88 | const approveTx = await nftContract.approve(marketplace.address, tokenId); 89 | await approveTx.wait(); 90 | 91 | // Posting order tx 92 | const postOrderTx = await marketplace.postSellOrder( 93 | nftContract.address, 94 | tokenId, 95 | utils.parseEther(String(usdPrice)) 96 | ); 97 | await postOrderTx.wait(); 98 | } catch { 99 | const errText = "Error happened while posting the order"; 100 | alert(errText); 101 | } 102 | } 103 | 104 | async function cancelOrder(orderId: string) { 105 | try { 106 | const marketplace = await getContractInstance("marketplace"); 107 | const cancelTx = await marketplace.cancelOrder(orderId); 108 | await cancelTx.wait(); 109 | return cancelTx; 110 | } catch { 111 | const errText = "Error happened while canceling the order"; 112 | alert(errText); 113 | } 114 | } 115 | 116 | /* 117 | Marketplace contract instance should be wrapped. 118 | It enables fetching data from redstone data pool 119 | for each contract function call 120 | */ 121 | async function buy(orderId: string) { 122 | const marketplace = await getContractInstance("marketplace"); 123 | // TO IMPLEMENT 124 | } 125 | 126 | ///////// STANDARD BLOCKCHAIN UTILS FUNCTIONS ///////// 127 | 128 | function shortenAddress(address: string) { 129 | return address.slice(0, 7) + ".." + address.slice(address.length - 7); 130 | } 131 | 132 | function onAddressChange(callback: () => void) { 133 | window.ethereum.on("accountsChanged", callback); 134 | } 135 | 136 | async function getUserAddress() { 137 | try { 138 | const signer = await getSigner(); 139 | return await signer.getAddress(); 140 | } catch (error: any) { 141 | alert(error?.message); 142 | } 143 | } 144 | 145 | async function connectWallet() { 146 | getChainId(); 147 | await window.ethereum.request({ method: "eth_requestAccounts" }); 148 | } 149 | 150 | async function getSigner() { 151 | await connectWallet(); 152 | const signer = new Web3Provider(window.ethereum).getSigner(); 153 | return signer; 154 | } 155 | 156 | async function getContractInstance(contractName: "nft" | "marketplace") { 157 | const abi = ABIs[contractName]; 158 | const address = await getContractAddress(contractName); 159 | const signer = await getSigner(); 160 | return new Contract(address, abi, signer); 161 | } 162 | 163 | async function getContractAddress(contractName: "nft" | "marketplace") { 164 | return localAddresses[contractName]; 165 | } 166 | 167 | async function getChainId() { 168 | const provider = new Web3Provider(window.ethereum); 169 | const network = await provider.getNetwork(); 170 | 171 | const chainId = network.chainId; 172 | 173 | // Check if network is supported 174 | if (chainId !== zkSyncLocalTestnetChainId) { 175 | const errText = "Please connect to zkSync local network and reload the page"; 176 | alert(errText); 177 | } 178 | 179 | return chainId; 180 | } 181 | 182 | export default { 183 | getOwnedNfts, 184 | mintNft, 185 | getAllOrders, 186 | postOrder, 187 | cancelOrder, 188 | buy, 189 | connectWallet, 190 | getUserAddress, 191 | shortenAddress, 192 | onAddressChange, 193 | }; 194 | -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/config/nft-abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "owner", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "approved", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": true, 24 | "internalType": "uint256", 25 | "name": "tokenId", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "Approval", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "owner", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": true, 43 | "internalType": "address", 44 | "name": "operator", 45 | "type": "address" 46 | }, 47 | { 48 | "indexed": false, 49 | "internalType": "bool", 50 | "name": "approved", 51 | "type": "bool" 52 | } 53 | ], 54 | "name": "ApprovalForAll", 55 | "type": "event" 56 | }, 57 | { 58 | "anonymous": false, 59 | "inputs": [ 60 | { 61 | "indexed": true, 62 | "internalType": "address", 63 | "name": "from", 64 | "type": "address" 65 | }, 66 | { 67 | "indexed": true, 68 | "internalType": "address", 69 | "name": "to", 70 | "type": "address" 71 | }, 72 | { 73 | "indexed": true, 74 | "internalType": "uint256", 75 | "name": "tokenId", 76 | "type": "uint256" 77 | } 78 | ], 79 | "name": "Transfer", 80 | "type": "event" 81 | }, 82 | { 83 | "inputs": [ 84 | { 85 | "internalType": "address", 86 | "name": "to", 87 | "type": "address" 88 | }, 89 | { 90 | "internalType": "uint256", 91 | "name": "tokenId", 92 | "type": "uint256" 93 | } 94 | ], 95 | "name": "approve", 96 | "outputs": [], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "owner", 105 | "type": "address" 106 | } 107 | ], 108 | "name": "balanceOf", 109 | "outputs": [ 110 | { 111 | "internalType": "uint256", 112 | "name": "", 113 | "type": "uint256" 114 | } 115 | ], 116 | "stateMutability": "view", 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [ 121 | { 122 | "internalType": "uint256", 123 | "name": "tokenId", 124 | "type": "uint256" 125 | } 126 | ], 127 | "name": "getApproved", 128 | "outputs": [ 129 | { 130 | "internalType": "address", 131 | "name": "", 132 | "type": "address" 133 | } 134 | ], 135 | "stateMutability": "view", 136 | "type": "function" 137 | }, 138 | { 139 | "inputs": [ 140 | { 141 | "internalType": "address", 142 | "name": "owner", 143 | "type": "address" 144 | }, 145 | { 146 | "internalType": "address", 147 | "name": "operator", 148 | "type": "address" 149 | } 150 | ], 151 | "name": "isApprovedForAll", 152 | "outputs": [ 153 | { 154 | "internalType": "bool", 155 | "name": "", 156 | "type": "bool" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [], 164 | "name": "mint", 165 | "outputs": [], 166 | "stateMutability": "nonpayable", 167 | "type": "function" 168 | }, 169 | { 170 | "inputs": [], 171 | "name": "name", 172 | "outputs": [ 173 | { 174 | "internalType": "string", 175 | "name": "", 176 | "type": "string" 177 | } 178 | ], 179 | "stateMutability": "view", 180 | "type": "function" 181 | }, 182 | { 183 | "inputs": [ 184 | { 185 | "internalType": "uint256", 186 | "name": "tokenId", 187 | "type": "uint256" 188 | } 189 | ], 190 | "name": "ownerOf", 191 | "outputs": [ 192 | { 193 | "internalType": "address", 194 | "name": "", 195 | "type": "address" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [ 203 | { 204 | "internalType": "address", 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "internalType": "address", 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "internalType": "uint256", 215 | "name": "tokenId", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "safeTransferFrom", 220 | "outputs": [], 221 | "stateMutability": "nonpayable", 222 | "type": "function" 223 | }, 224 | { 225 | "inputs": [ 226 | { 227 | "internalType": "address", 228 | "name": "from", 229 | "type": "address" 230 | }, 231 | { 232 | "internalType": "address", 233 | "name": "to", 234 | "type": "address" 235 | }, 236 | { 237 | "internalType": "uint256", 238 | "name": "tokenId", 239 | "type": "uint256" 240 | }, 241 | { 242 | "internalType": "bytes", 243 | "name": "_data", 244 | "type": "bytes" 245 | } 246 | ], 247 | "name": "safeTransferFrom", 248 | "outputs": [], 249 | "stateMutability": "nonpayable", 250 | "type": "function" 251 | }, 252 | { 253 | "inputs": [ 254 | { 255 | "internalType": "address", 256 | "name": "operator", 257 | "type": "address" 258 | }, 259 | { 260 | "internalType": "bool", 261 | "name": "approved", 262 | "type": "bool" 263 | } 264 | ], 265 | "name": "setApprovalForAll", 266 | "outputs": [], 267 | "stateMutability": "nonpayable", 268 | "type": "function" 269 | }, 270 | { 271 | "inputs": [ 272 | { 273 | "internalType": "bytes4", 274 | "name": "interfaceId", 275 | "type": "bytes4" 276 | } 277 | ], 278 | "name": "supportsInterface", 279 | "outputs": [ 280 | { 281 | "internalType": "bool", 282 | "name": "", 283 | "type": "bool" 284 | } 285 | ], 286 | "stateMutability": "view", 287 | "type": "function" 288 | }, 289 | { 290 | "inputs": [], 291 | "name": "symbol", 292 | "outputs": [ 293 | { 294 | "internalType": "string", 295 | "name": "", 296 | "type": "string" 297 | } 298 | ], 299 | "stateMutability": "view", 300 | "type": "function" 301 | }, 302 | { 303 | "inputs": [ 304 | { 305 | "internalType": "uint256", 306 | "name": "index", 307 | "type": "uint256" 308 | } 309 | ], 310 | "name": "tokenByIndex", 311 | "outputs": [ 312 | { 313 | "internalType": "uint256", 314 | "name": "", 315 | "type": "uint256" 316 | } 317 | ], 318 | "stateMutability": "view", 319 | "type": "function" 320 | }, 321 | { 322 | "inputs": [ 323 | { 324 | "internalType": "address", 325 | "name": "owner", 326 | "type": "address" 327 | }, 328 | { 329 | "internalType": "uint256", 330 | "name": "index", 331 | "type": "uint256" 332 | } 333 | ], 334 | "name": "tokenOfOwnerByIndex", 335 | "outputs": [ 336 | { 337 | "internalType": "uint256", 338 | "name": "", 339 | "type": "uint256" 340 | } 341 | ], 342 | "stateMutability": "view", 343 | "type": "function" 344 | }, 345 | { 346 | "inputs": [ 347 | { 348 | "internalType": "uint256", 349 | "name": "tokenId", 350 | "type": "uint256" 351 | } 352 | ], 353 | "name": "tokenURI", 354 | "outputs": [ 355 | { 356 | "internalType": "string", 357 | "name": "", 358 | "type": "string" 359 | } 360 | ], 361 | "stateMutability": "view", 362 | "type": "function" 363 | }, 364 | { 365 | "inputs": [], 366 | "name": "totalSupply", 367 | "outputs": [ 368 | { 369 | "internalType": "uint256", 370 | "name": "", 371 | "type": "uint256" 372 | } 373 | ], 374 | "stateMutability": "view", 375 | "type": "function" 376 | }, 377 | { 378 | "inputs": [ 379 | { 380 | "internalType": "address", 381 | "name": "from", 382 | "type": "address" 383 | }, 384 | { 385 | "internalType": "address", 386 | "name": "to", 387 | "type": "address" 388 | }, 389 | { 390 | "internalType": "uint256", 391 | "name": "tokenId", 392 | "type": "uint256" 393 | } 394 | ], 395 | "name": "transferFrom", 396 | "outputs": [], 397 | "stateMutability": "nonpayable", 398 | "type": "function" 399 | } 400 | ] 401 | -------------------------------------------------------------------------------- /tutorials/the-graph/code/pepe_abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "owner", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "spender", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": false, 24 | "internalType": "uint256", 25 | "name": "value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "Approval", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "_account", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": false, 43 | "internalType": "uint256", 44 | "name": "_amount", 45 | "type": "uint256" 46 | } 47 | ], 48 | "name": "BridgeBurn", 49 | "type": "event" 50 | }, 51 | { 52 | "anonymous": false, 53 | "inputs": [ 54 | { 55 | "indexed": true, 56 | "internalType": "address", 57 | "name": "l1Token", 58 | "type": "address" 59 | }, 60 | { 61 | "indexed": false, 62 | "internalType": "string", 63 | "name": "name", 64 | "type": "string" 65 | }, 66 | { 67 | "indexed": false, 68 | "internalType": "string", 69 | "name": "symbol", 70 | "type": "string" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "uint8", 75 | "name": "decimals", 76 | "type": "uint8" 77 | } 78 | ], 79 | "name": "BridgeInitialization", 80 | "type": "event" 81 | }, 82 | { 83 | "anonymous": false, 84 | "inputs": [ 85 | { 86 | "indexed": true, 87 | "internalType": "address", 88 | "name": "_account", 89 | "type": "address" 90 | }, 91 | { 92 | "indexed": false, 93 | "internalType": "uint256", 94 | "name": "_amount", 95 | "type": "uint256" 96 | } 97 | ], 98 | "name": "BridgeMint", 99 | "type": "event" 100 | }, 101 | { 102 | "anonymous": false, 103 | "inputs": [ 104 | { 105 | "indexed": false, 106 | "internalType": "uint8", 107 | "name": "version", 108 | "type": "uint8" 109 | } 110 | ], 111 | "name": "Initialized", 112 | "type": "event" 113 | }, 114 | { 115 | "anonymous": false, 116 | "inputs": [ 117 | { 118 | "indexed": true, 119 | "internalType": "address", 120 | "name": "from", 121 | "type": "address" 122 | }, 123 | { 124 | "indexed": true, 125 | "internalType": "address", 126 | "name": "to", 127 | "type": "address" 128 | }, 129 | { 130 | "indexed": false, 131 | "internalType": "uint256", 132 | "name": "value", 133 | "type": "uint256" 134 | } 135 | ], 136 | "name": "Transfer", 137 | "type": "event" 138 | }, 139 | { 140 | "inputs": [ 141 | { 142 | "internalType": "address", 143 | "name": "owner", 144 | "type": "address" 145 | }, 146 | { 147 | "internalType": "address", 148 | "name": "spender", 149 | "type": "address" 150 | } 151 | ], 152 | "name": "allowance", 153 | "outputs": [ 154 | { 155 | "internalType": "uint256", 156 | "name": "", 157 | "type": "uint256" 158 | } 159 | ], 160 | "stateMutability": "view", 161 | "type": "function" 162 | }, 163 | { 164 | "inputs": [ 165 | { 166 | "internalType": "address", 167 | "name": "spender", 168 | "type": "address" 169 | }, 170 | { 171 | "internalType": "uint256", 172 | "name": "amount", 173 | "type": "uint256" 174 | } 175 | ], 176 | "name": "approve", 177 | "outputs": [ 178 | { 179 | "internalType": "bool", 180 | "name": "", 181 | "type": "bool" 182 | } 183 | ], 184 | "stateMutability": "nonpayable", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [ 189 | { 190 | "internalType": "address", 191 | "name": "account", 192 | "type": "address" 193 | } 194 | ], 195 | "name": "balanceOf", 196 | "outputs": [ 197 | { 198 | "internalType": "uint256", 199 | "name": "", 200 | "type": "uint256" 201 | } 202 | ], 203 | "stateMutability": "view", 204 | "type": "function" 205 | }, 206 | { 207 | "inputs": [ 208 | { 209 | "internalType": "address", 210 | "name": "_from", 211 | "type": "address" 212 | }, 213 | { 214 | "internalType": "uint256", 215 | "name": "_amount", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "bridgeBurn", 220 | "outputs": [], 221 | "stateMutability": "nonpayable", 222 | "type": "function" 223 | }, 224 | { 225 | "inputs": [ 226 | { 227 | "internalType": "address", 228 | "name": "_l1Address", 229 | "type": "address" 230 | }, 231 | { 232 | "internalType": "bytes", 233 | "name": "_data", 234 | "type": "bytes" 235 | } 236 | ], 237 | "name": "bridgeInitialize", 238 | "outputs": [], 239 | "stateMutability": "nonpayable", 240 | "type": "function" 241 | }, 242 | { 243 | "inputs": [ 244 | { 245 | "internalType": "address", 246 | "name": "_to", 247 | "type": "address" 248 | }, 249 | { 250 | "internalType": "uint256", 251 | "name": "_amount", 252 | "type": "uint256" 253 | } 254 | ], 255 | "name": "bridgeMint", 256 | "outputs": [], 257 | "stateMutability": "nonpayable", 258 | "type": "function" 259 | }, 260 | { 261 | "inputs": [], 262 | "name": "decimals", 263 | "outputs": [ 264 | { 265 | "internalType": "uint8", 266 | "name": "", 267 | "type": "uint8" 268 | } 269 | ], 270 | "stateMutability": "view", 271 | "type": "function" 272 | }, 273 | { 274 | "inputs": [ 275 | { 276 | "internalType": "address", 277 | "name": "spender", 278 | "type": "address" 279 | }, 280 | { 281 | "internalType": "uint256", 282 | "name": "subtractedValue", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "decreaseAllowance", 287 | "outputs": [ 288 | { 289 | "internalType": "bool", 290 | "name": "", 291 | "type": "bool" 292 | } 293 | ], 294 | "stateMutability": "nonpayable", 295 | "type": "function" 296 | }, 297 | { 298 | "inputs": [ 299 | { 300 | "internalType": "address", 301 | "name": "spender", 302 | "type": "address" 303 | }, 304 | { 305 | "internalType": "uint256", 306 | "name": "addedValue", 307 | "type": "uint256" 308 | } 309 | ], 310 | "name": "increaseAllowance", 311 | "outputs": [ 312 | { 313 | "internalType": "bool", 314 | "name": "", 315 | "type": "bool" 316 | } 317 | ], 318 | "stateMutability": "nonpayable", 319 | "type": "function" 320 | }, 321 | { 322 | "inputs": [], 323 | "name": "l1Address", 324 | "outputs": [ 325 | { 326 | "internalType": "address", 327 | "name": "", 328 | "type": "address" 329 | } 330 | ], 331 | "stateMutability": "view", 332 | "type": "function" 333 | }, 334 | { 335 | "inputs": [], 336 | "name": "l2Bridge", 337 | "outputs": [ 338 | { 339 | "internalType": "address", 340 | "name": "", 341 | "type": "address" 342 | } 343 | ], 344 | "stateMutability": "view", 345 | "type": "function" 346 | }, 347 | { 348 | "inputs": [], 349 | "name": "name", 350 | "outputs": [ 351 | { 352 | "internalType": "string", 353 | "name": "", 354 | "type": "string" 355 | } 356 | ], 357 | "stateMutability": "view", 358 | "type": "function" 359 | }, 360 | { 361 | "inputs": [], 362 | "name": "symbol", 363 | "outputs": [ 364 | { 365 | "internalType": "string", 366 | "name": "", 367 | "type": "string" 368 | } 369 | ], 370 | "stateMutability": "view", 371 | "type": "function" 372 | }, 373 | { 374 | "inputs": [], 375 | "name": "totalSupply", 376 | "outputs": [ 377 | { 378 | "internalType": "uint256", 379 | "name": "", 380 | "type": "uint256" 381 | } 382 | ], 383 | "stateMutability": "view", 384 | "type": "function" 385 | }, 386 | { 387 | "inputs": [ 388 | { 389 | "internalType": "address", 390 | "name": "to", 391 | "type": "address" 392 | }, 393 | { 394 | "internalType": "uint256", 395 | "name": "amount", 396 | "type": "uint256" 397 | } 398 | ], 399 | "name": "transfer", 400 | "outputs": [ 401 | { 402 | "internalType": "bool", 403 | "name": "", 404 | "type": "bool" 405 | } 406 | ], 407 | "stateMutability": "nonpayable", 408 | "type": "function" 409 | }, 410 | { 411 | "inputs": [ 412 | { 413 | "internalType": "address", 414 | "name": "from", 415 | "type": "address" 416 | }, 417 | { 418 | "internalType": "address", 419 | "name": "to", 420 | "type": "address" 421 | }, 422 | { 423 | "internalType": "uint256", 424 | "name": "amount", 425 | "type": "uint256" 426 | } 427 | ], 428 | "name": "transferFrom", 429 | "outputs": [ 430 | { 431 | "internalType": "bool", 432 | "name": "", 433 | "type": "bool" 434 | } 435 | ], 436 | "stateMutability": "nonpayable", 437 | "type": "function" 438 | } 439 | ] -------------------------------------------------------------------------------- /tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # RedStone oracles on zkSync 2 | 3 | By the end of this tutorial you will understand how to integrate your dApp built on zkSync with RedStone oracles. 4 | 5 | ## Example dApp - Stable price NFT marketplace 6 | 7 | This repo is designed to show how to build a dApp that uses [RedStone oracles](https://redstone.finance/) on [zkSync](https://zksync.io/). 8 | 9 | The repo contains an implementation of an NFT marketplace dApp with so-called "stable" price. It means that sellers can create sell orders (offers), specifying the price amount in USD. But buyers are able to pay with native coins, the required amount of which is calculated dynamically at the moment of the order execution. Repo lacks few crucial parts which will demonstrate how to integrate RedStone oracles and deploy dApp on zkSync Era Testnet. 10 | 11 | ## 🧑‍💻 Implementation 12 | 13 | We use [hardhat](https://hardhat.org/), version prepared for working on [zkSync](https://github.com/matter-labs/hardhat-zksync), and [ethers.js](https://docs.ethers.io/v5/) for deployment scripts and contract tests. Frontend is implemented in [React](https://reactjs.org/). 14 | 15 | ### Code structure 16 | 17 | ```bash 18 | ├── contracts # Solidity contracts 19 | │ ├── ExampleNFT.sol # Example ERC721 contract 20 | │ ├── Marketplace.sol # Simple NFT marketplace contract 21 | │ ├── StableMarketplace.sol # NFT marketplace contract with stable price 22 | │ └── ... 23 | ├── public # Folder with public html files and images for React app 24 | ├── deploy # Contract deployment script 25 | ├── src # React app source code 26 | │ ├── components 27 | │ │ ├── App.tsx # Main React component 28 | │ ├── core 29 | │ │ ├── blockchain.ts # TS module responsible for interaction with blockchain and contracts 30 | │ ├── config/ # Folder with contract ABIs and deployed contract addresses 31 | │ └── ... 32 | ├── test # Contract tests 33 | └── ... 34 | ``` 35 | 36 | ### Contracts 37 | 38 | #### ExampleNFT.sol 39 | 40 | `ExampleNFT` is a simple ERC721 contract with automated sequential token id assignment 41 | 42 | ```js 43 | function mint() external { 44 | _mint(msg.sender, nextTokenId); 45 | nextTokenId++; 46 | } 47 | ``` 48 | 49 | This contract extends `ERC721Enumerable` implementation created by the `@openzeppelin` team, which adds view functions for listing all tokens and tokens owned by a user. 50 | 51 | #### Marketplace.sol 52 | 53 | `Marketplace` is an NFT marketplace contract, which allows to post sell orders for any NFT token that follows [EIP-721 non-fungible token standard](https://eips.ethereum.org/EIPS/eip-721). It has the following functions: 54 | 55 | ```js 56 | 57 | // Created a new sell order 58 | // This function requires approval for transfer on the specified NFT token 59 | function postSellOrder(address nftContractAddress, uint256 tokenId, uint256 price) external {} 60 | 61 | // Only order creator can call this function 62 | function cancelOrder(uint256 orderId) external {} 63 | 64 | // Allows to get info about all orders (including canceled, and executed ones) 65 | function getAllOrders() public view returns (SellOrder[] memory) {} 66 | 67 | // Returns expected price in ETH for the given order 68 | function getPrice(uint256 orderId) public view returns (uint256) {} 69 | 70 | // Requires sending at least the minimal amount of ETH 71 | function buy(uint256 orderId) external payable {} 72 | 73 | ``` 74 | 75 | The implementation is quite straightforward, so we won't describe it here. You can check the full contract code in the [contracts/Marketplace.sol.](contracts/Marketplace.sol) 76 | 77 | #### StableMarketplace.sol 78 | 79 | `StableMarketplace` is the marketplace contract with the stable price support. It extends the `Marketplace.sol` implementation and only overrides its `_getPriceFromOrder` function. 80 | This contract will integrate RedStone oracles functionalities and will be described later. 81 | 82 | ### Frontend 83 | 84 | You can check the code of the React app in the `src` folder. We tried to simplify it as much as possible and leave only the core marketplace functions. 85 | 86 | The main UI logic is located in the `App.tsx` file, and the contract interaction logic is in the `blockchain.ts` file. 87 | 88 | If you take a look into the `blockchain.ts` file code, you'll notice that each contract call that needs to process RedStone data is made on a contract instance, that was wrapped by [@redstone-finance/evm-connector](https://www.npmjs.com/package/@redstone-finance/evm-connector). 89 | 90 | ### Tests 91 | 92 | We've used hardhat test framework to contract tests. All the tests are located in the [test](test/) folder. 93 | 94 | ## 🔥 Tutorial how to integrate RedStone oracles on zkSync 95 | 96 | ### Prepare repo 97 | 98 | #### 1. Clone this repo 99 | 100 | ```sh 101 | git clone https://github.com/zkSync-Community-Hub/tutorials 102 | cd tutorials/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial 103 | ``` 104 | 105 | #### 2. Install dependencies 106 | 107 | ```sh 108 | yarn install 109 | ``` 110 | 111 | #### 3. Run local zkSync node 112 | 113 | You can run zkSync node in dockerized setup by following instructions presented [here](https://era.zksync.io/docs/tools/testing/dockerized-testing.html) 114 | 115 | ### Get familiar with the code 116 | 117 | If you are not familiar with the code yet, please read [implementation description](#🧑‍💻-implementation) 118 | 119 | ### Integrate with RedStone Oracles 120 | 121 | Now it is time to integrate RedStone Oracles into the marketplace. As you maybe noticed some parts of the code are missing the implementation. Let me give you instructions on how to integrate RedStone oracles. 122 | 123 | #### 1. Adjust smart contract 124 | 125 | First, we need to modify contracts as currently, they are not ready to receive transactions with RedStone data regarding price. If you are not familiar with our core model please read [how to adjust your smart contracts](#1-adjust-your-smart-contracts). Take a look at the StableMarketplace contract. It is the marketplace contract with stable price support. It extends the `Marketplace.sol` implementation and only overrides its `_getPriceFromOrder` function. The contract should be extended by MainDemoConsumerBase which is imported from [@redstone-finance/evm-connector](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector). The `_getPriceFromOrder` function should use the `getOracleNumericValueFromTxMsg` function to get price data and calculate the final price based on the order price and the price of ETH. Full implementation can be seen below: 126 | 127 | ```js 128 | // SPDX-License-Identifier: MIT 129 | pragma solidity ^0.8.4; 130 | 131 | import "@redstone-finance/evm-connector/contracts/data-services/MainDemoConsumerBase.sol"; 132 | import "./Marketplace.sol"; 133 | 134 | /* 135 | StableMarketplace contract should extend MainDemoConsumerBase contract 136 | For being able to use redstone oracles data, more inf: 137 | https://docs.redstone.finance/docs/smart-contract-devs/get-started/redstone-core#1-adjust-your-smart-contracts 138 | */ 139 | contract StableMarketplace is Marketplace, MainDemoConsumerBase { 140 | /* 141 | `_getPriceFromOrder` function should uses the `getOracleNumericValueFromTxMsg` function, 142 | which fetches signed data from tx calldata and verifies its signature 143 | */ 144 | function _getPriceFromOrder( 145 | SellOrder memory order 146 | ) internal view override returns (uint256) { 147 | uint256 ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH")); 148 | return (order.price / ethPrice) * (10 ** 8); 149 | } 150 | } 151 | ``` 152 | 153 | #### 2. Adjust dApp TypeScript code 154 | 155 | The second thing to do is adjust the Typescript code of the dApp. Please take a look at the `blockchain.ts` file. Here you can find all functions required to make the marketplace work. But the function `buy` is not implemented. Here we will call the function from the contracts which require price data. To make it possible we need to wrap the contract instance with the [RedStone framework](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector). If you are not familiar with our core model please read how to [adjust Typescript code](#2-adjust-javascript-code-of-your-dapp). After wrapping the contract we will be able to call the `getPrice` function from the `StableMarketplace` contract which eventually will call overridden `_getPriceFromOrder`. Now we are able to call the `buy` function from the `StableMarketplace` contract with the expected ETH amount to buy the NFT. Full implementation can be seen below: 156 | 157 | ```js 158 | import { WrapperBuilder } from "@redstone-finance/evm-connector"; 159 | 160 | async function buy(orderId: string) { 161 | const marketplace = await getContractInstance("marketplace"); 162 | 163 | // Wrapping marketplace contract instance. 164 | // It enables fetching data from redstone data pool 165 | // for each contract function call 166 | try { 167 | const wrappedMarketplaceContract = WrapperBuilder.wrap( 168 | marketplace 169 | ).usingDataService( 170 | { 171 | dataServiceId: "redstone-main-demo", 172 | uniqueSignersCount: 1, 173 | dataFeeds: ["ETH"], 174 | }, 175 | ); 176 | 177 | // Checking expected amount 178 | const expectedEthAmount = await wrappedMarketplaceContract.getPrice(orderId); 179 | 180 | // Sending buy tx 181 | const buyTx = await wrappedMarketplaceContract.buy(orderId, { 182 | value: expectedEthAmount.mul(101).div(100), // a buffer for price movements 183 | }); 184 | await buyTx.wait(); 185 | 186 | return buyTx; 187 | } catch { 188 | const errText = "Error happened while buying the NFT"; 189 | alert(errText); 190 | } 191 | } 192 | ``` 193 | 194 | ### Test dApp locally 195 | 196 | #### 1. Check if tests pass 197 | 198 | Tests work only when integration with RedStone oracles is ready 199 | 200 | ```sh 201 | yarn test 202 | ``` 203 | 204 | #### 2. Compile contracts 205 | 206 | ```sh 207 | yarn compile 208 | ``` 209 | 210 | #### 3. Deploy contracts on local blockchain 211 | 212 | You need to populate .env file with private key for deployment e.g. 213 | 214 | ``` 215 | WALLET_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 216 | ``` 217 | 218 | and then run 219 | 220 | ```sh 221 | yarn deploy:local 222 | ``` 223 | 224 | #### 4. Run react app 225 | 226 | ```sh 227 | yarn app:start 228 | ``` 229 | 230 | The app should be running on 231 | 232 | #### 3. Configure metamask 233 | 234 | ##### 3.1 Add local hardhat network to metamask 235 | 236 | Select `Networks dropdown` -> `Add network` and enter the following details: 237 | **Network Name**|**hardhat-local** 238 | :-----:|:-----: 239 | New RPC URL| 240 | Chain ID|270 241 | Currency Symbol|ETH 242 | 243 | Then hit the `Save` button. 244 | 245 | ##### 3.2 Add local wallets to metamask 246 | 247 | - `User 1`: `0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3` 248 | - `User 2`: `0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e` 249 | 250 | #### 4. Explore the app in browser 251 | 252 | stable-marketplace-app 253 | 254 | ##### Mint NFTs 255 | 256 | After visiting the app first time you will see an almost empty screen with the `+ Mint new NFT` link. Click this link to mint new NFTs. After the minting transaction confirmation you will see your NFT in the left column. 257 | 258 | my-nfts 259 | 260 | ##### Post sell orders 261 | 262 | Once you mint any NFTs, you can post sell order for each one of them. Click the SELL button and provide the USD value. You will be asked to confirm 2 transactions: for NFT transfer approval, and for the marketplace order creation. After their confirmation, you will see your order in the Orders column. 263 | 264 | orders 265 | 266 | ##### Buy NFTs 267 | 268 | You can also switch metamask account and buy the NFT. I would recommend to open the developer tools in browser at the network tab and explore network requests that are being sent before the buy transaction sending. 269 | 270 | You should see at least 2 requests with the ETH price data and crypto signatures. This data along with signatures is being attached for each contract call, that wants to process redstone oracles data. 271 | 272 | redstone-requests 273 | 274 | ## 🚀 What is RedStone? 275 | 276 | RedStone is a data ecosystem that delivers frequently updated, reliable and diverse data for your dApps and smart contracts. 277 | 278 | RedStone offers a radically different design of Oracles catering to the needs of modern DeFi protocols. 279 | 280 | - Data providers can avoid the requirement of continuous on-chain data delivery 281 | - Allow end users to self-deliver signed Oracle data on-chain 282 | - Use the decentralized Streamr network to deliver signed oracle data to the end users 283 | - Use token incentives to motivate data providers to maintain data integrity and uninterrupted service 284 | - Leverage the Arweave blockchain as cheap and permanent storage for archiving Oracle data and maintaining data providers' accountability 285 | 286 | To learn more about RedStone oracles design check out the [RedStone docs.](https://docs.redstone.finance/docs/introduction) 287 | 288 | ## 🗝️ Key facts 289 | 290 | - The [modular architecture](https://docs.redstone.finance/docs/smart-contract-devs/how-it-works#data-flow) maintains [data integrity](https://docs.redstone.finance/docs/smart-contract-devs/how-it-works#data-format) from source to smart contracts 291 | - There are [3 different ways](https://docs.redstone.finance/docs/smart-contract-devs/how-it-works#3-ways-to-integrate) to integrate our service tailored to your needs 292 | - We provide feeds for more than [1000 assets](https://app.redstone.finance/#/app/tokens) integrating [~50 data sources](https://app.redstone.finance/#/app/sources) 293 | - We are present on [20+ chains](https://showroom.redstone.finance/) 294 | - RedStone has been live on mainnets since March 2022 with no downtime. Code was audited by ABDK, Packshield and L2Beat Co-Founder. 295 | - RedStone was a launch partner for [DeltaPrime](https://deltaprime.io/) on Avalanche and delivered data feeds not available anywhere else. Thanks to that DeltaPrime became the top 3 fastest growing dApps according to DeFiLama. 296 | 297 | ## 📈 What data is available 298 | 299 | Thanks to our innovative architecture, we offer more than one thousand of pricing data feeds, including tokens, stocks, ETFs, commodities, and much more for a fraction of regular Oracles integration costs. 300 | 301 | You can check available assets and data providers using [app.redstone.finance.](https://app.redstone.finance/) 302 | 303 | ## 🔥 How to use RedStone? 304 | 305 | **IMPORTANT**: Please reach out to the RedStone team [on Discord](https://redstone.finance/discord) before using RedStone oracles in production dApps. We will be happy to help you with the integration and will set up a new pool of data provider nodes if there is a need. 306 | 307 | ### Installation 308 | 309 | Install [@redstone-finance/evm-connector](https://www.npmjs.com/package/@redstone-finance/evm-connector) from NPM registry 310 | 311 | ```bash 312 | # Using yarn 313 | yarn add @redstone-finance/evm-connector 314 | 315 | # Using NPM 316 | npm install @redstone-finance/evm-connector 317 | ``` 318 | 319 | ### Usage 320 | 321 | TLDR; You need to do 2 things: 322 | 323 | 1. [Adjust your smart contracts](#1-adjust-your-smart-contracts) 324 | 2. [Adjust Javascript code of your dApp](#2-adjust-javascript-code-of-your-dapp) (**it is required**, otherwise you will get smart contract errors) 325 | 326 | 💡 Note: Please don't use Remix to test RedStone oracles, as Remix does not support modifying transactions in the way that the evm-connector does. 327 | 328 | ### 1. Adjust your smart contracts 329 | 330 | You need to apply a minimum change to the source code to enable smart contract to access data. Your contract needs to extend one of our custom base contracts, which can be found [here.](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector/contracts/data-services) 331 | 332 | We strongly recommend having some upgradeability mechanism for your contracts (it can be based on multisig, DAO, or anything else). This way, you can quickly switch to the latest trusted data providers in case of changes or problems with the current providers. 333 | 334 | ```js 335 | import "@redstone-finance/evm-connector/contracts/data-services/MainDemoConsumerBase.sol"; 336 | 337 | contract YourContractName is MainDemoConsumerBase { 338 | ... 339 | } 340 | ``` 341 | 342 | After applying the mentioned change you will be able to access the data calling the local `getOracleNumericValueFromTxMsg` function. You should pass the data feed id converted to `bytes32`. 343 | 344 | ```js 345 | // Getting a single value 346 | uint256 ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH")); 347 | 348 | // Getting several values 349 | bytes32[] memory dataFeedIds = new bytes32[](2); 350 | dataFeedIds[0] = bytes32("ETH"); 351 | dataFeedIds[1] = bytes32("BTC"); 352 | uint256[] memory values = getOracleNumericValuesFromTxMsg(dataFeedIds); 353 | uint256 ethPrice = values[0]; 354 | uint256 btcPrice = values[1]; 355 | ``` 356 | 357 | You can see all available data feeds [in our web app.](https://app.redstone.finance) 358 | 359 | ### 2. Adjust Javascript code of your dApp 360 | 361 | You should also update the code responsible for submitting transactions. If you're using [ethers.js](https://github.com/ethers-io/ethers.js/), we've prepared a dedicated library to make the transition seamless. 362 | 363 | #### Contract object wrapping 364 | 365 | First, you need to import the wrapper code to your project 366 | 367 | ```ts 368 | // Typescript 369 | import { WrapperBuilder } from "@redstone-finance/evm-connector"; 370 | 371 | // Javascript 372 | const { WrapperBuilder } = require("@redstone-finance/evm-connector"); 373 | ``` 374 | 375 | Then you can wrap your ethers contract pointing to the selected [Redstone data service id.](https://api.redstone.finance/providers) You should also specify a number of unique signers, data feed identifiers, and (optionally) URLs for the redstone cache nodes. 376 | 377 | ```js 378 | const yourEthersContract = new ethers.Contract(address, abi, provider); 379 | 380 | // Connecting all provider's prices (consumes more GAS) 381 | const wrappedContract = WrapperBuilder.wrap(contract).usingDataService({ 382 | dataServiceId: "redstone-main-demo", 383 | uniqueSignersCount: 1, 384 | dataFeeds: ["ETH", "BTC"], 385 | }); 386 | ``` 387 | 388 | Now you can access any of the contract's methods in exactly the same way as interacting with the ethers-js code: 389 | 390 | ```js 391 | wrappedContract.executeYourMethod(); 392 | ``` 393 | 394 | #### Mock provider 395 | 396 | If you'd like to use the wrapper in a test context, we recommend using a mock wrapper so that you can easily override the oracles values to test different scenarios. To use the mock wrapper just use the `usingMockData(signedDataPackages)` function instead of the `usingDataService` function. You can see examples of the mock wrapper usage [here.](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector/test/mock-wrapper) 397 | 398 | You can find more information in the [RedStone documentation](https://docs.redstone.finance/docs/smart-contract-devs/getting-started) to learn how to integrate your zkSync dApp with RedStone oracles. 399 | 400 | ## 🌎 Useful links 401 | 402 | - [Repo with examples](https://github.com/redstone-finance/redstone-evm-examples) 403 | - [RedStone Documentation](https://docs.redstone.finance/) 404 | - [RedStone Price Feeds](https://docs.redstone.finance/docs/smart-contract-devs/price-feeds) 405 | - [Data from any URL](https://docs.redstone.finance/docs/smart-contract-devs/custom-urls) 406 | - [NFT Data Feeds](https://docs.redstone.finance/docs/smart-contract-devs/nft-data-feeds) 407 | - [Randomness](https://docs.redstone.finance/docs/smart-contract-devs/randomness) 408 | 409 | ## 🙋‍♂️ Need help? 410 | 411 | Please feel free to contact the RedStone team [on Discord](https://redstone.finance/discord) if you have any questions. 412 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.22.5" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" 8 | integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== 9 | dependencies: 10 | "@babel/highlight" "^7.22.5" 11 | 12 | "@babel/helper-validator-identifier@^7.22.5": 13 | version "7.22.5" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" 15 | integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== 16 | 17 | "@babel/highlight@^7.22.5": 18 | version "7.22.5" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" 20 | integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.22.5" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@cspell/cspell-bundled-dicts@6.31.2": 27 | version "6.31.2" 28 | resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.31.2.tgz#42865a6c025b0ce5550efa24c9a78d7094b206dc" 29 | integrity sha512-rQ5y/U1Ah5AaduIh3NU2z371hRrOr1cmNdhhP8oiuz2E4VqmcoVHflXIct9DgY8uIJpwsSCdR6ypOQWZYXYnwA== 30 | dependencies: 31 | "@cspell/dict-ada" "^4.0.1" 32 | "@cspell/dict-aws" "^3.0.0" 33 | "@cspell/dict-bash" "^4.1.1" 34 | "@cspell/dict-companies" "^3.0.9" 35 | "@cspell/dict-cpp" "^5.0.2" 36 | "@cspell/dict-cryptocurrencies" "^3.0.1" 37 | "@cspell/dict-csharp" "^4.0.2" 38 | "@cspell/dict-css" "^4.0.5" 39 | "@cspell/dict-dart" "^2.0.2" 40 | "@cspell/dict-django" "^4.0.2" 41 | "@cspell/dict-docker" "^1.1.6" 42 | "@cspell/dict-dotnet" "^5.0.0" 43 | "@cspell/dict-elixir" "^4.0.2" 44 | "@cspell/dict-en-common-misspellings" "^1.0.2" 45 | "@cspell/dict-en-gb" "1.1.33" 46 | "@cspell/dict-en_us" "^4.3.2" 47 | "@cspell/dict-filetypes" "^3.0.0" 48 | "@cspell/dict-fonts" "^3.0.2" 49 | "@cspell/dict-fullstack" "^3.1.5" 50 | "@cspell/dict-gaming-terms" "^1.0.4" 51 | "@cspell/dict-git" "^2.0.0" 52 | "@cspell/dict-golang" "^6.0.1" 53 | "@cspell/dict-haskell" "^4.0.1" 54 | "@cspell/dict-html" "^4.0.3" 55 | "@cspell/dict-html-symbol-entities" "^4.0.0" 56 | "@cspell/dict-java" "^5.0.5" 57 | "@cspell/dict-k8s" "^1.0.1" 58 | "@cspell/dict-latex" "^4.0.0" 59 | "@cspell/dict-lorem-ipsum" "^3.0.0" 60 | "@cspell/dict-lua" "^4.0.1" 61 | "@cspell/dict-node" "^4.0.2" 62 | "@cspell/dict-npm" "^5.0.5" 63 | "@cspell/dict-php" "^4.0.1" 64 | "@cspell/dict-powershell" "^5.0.1" 65 | "@cspell/dict-public-licenses" "^2.0.2" 66 | "@cspell/dict-python" "^4.0.2" 67 | "@cspell/dict-r" "^2.0.1" 68 | "@cspell/dict-ruby" "^5.0.0" 69 | "@cspell/dict-rust" "^4.0.1" 70 | "@cspell/dict-scala" "^5.0.0" 71 | "@cspell/dict-software-terms" "^3.1.6" 72 | "@cspell/dict-sql" "^2.1.0" 73 | "@cspell/dict-svelte" "^1.0.2" 74 | "@cspell/dict-swift" "^2.0.1" 75 | "@cspell/dict-typescript" "^3.1.1" 76 | "@cspell/dict-vue" "^3.0.0" 77 | 78 | "@cspell/cspell-pipe@6.31.1": 79 | version "6.31.1" 80 | resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-6.31.1.tgz#6c8edc92039125695a894186a899290d56d0f2c7" 81 | integrity sha512-zk1olZi4dr6GLm5PAjvsiZ01HURNSruUYFl1qSicGnTwYN8GaN4RhAwannAytcJ7zJPIcyXlid0YsB58nJf3wQ== 82 | 83 | "@cspell/cspell-service-bus@6.31.1": 84 | version "6.31.1" 85 | resolved "https://registry.yarnpkg.com/@cspell/cspell-service-bus/-/cspell-service-bus-6.31.1.tgz#ede5859e180f8d9be760df500e02164dae0084fe" 86 | integrity sha512-YyBicmJyZ1uwKVxujXw7sgs9x+Eps43OkWmCtDZmZlnq489HdTSuhF1kTbVi2yeFSeaXIS87+uHo12z97KkQpg== 87 | 88 | "@cspell/cspell-types@6.31.1": 89 | version "6.31.1" 90 | resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-6.31.1.tgz#b3737ef7743c0e5803d57e667f816418ac8da1cf" 91 | integrity sha512-1KeTQFiHMssW1eRoF2NZIEg4gPVIfXLsL2+VSD/AV6YN7lBcuf6gRRgV5KWYarhxtEfjxhDdDTmu26l/iJEUtw== 92 | 93 | "@cspell/dict-ada@^4.0.1": 94 | version "4.0.2" 95 | resolved "https://registry.yarnpkg.com/@cspell/dict-ada/-/dict-ada-4.0.2.tgz#8da2216660aeb831a0d9055399a364a01db5805a" 96 | integrity sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA== 97 | 98 | "@cspell/dict-aws@^3.0.0": 99 | version "3.0.0" 100 | resolved "https://registry.yarnpkg.com/@cspell/dict-aws/-/dict-aws-3.0.0.tgz#7b2db82bb632c664c3d72b83267b93b9b0cafe60" 101 | integrity sha512-O1W6nd5y3Z00AMXQMzfiYrIJ1sTd9fB1oLr+xf/UD7b3xeHeMeYE2OtcWbt9uyeHim4tk+vkSTcmYEBKJgS5bQ== 102 | 103 | "@cspell/dict-bash@^4.1.1": 104 | version "4.1.1" 105 | resolved "https://registry.yarnpkg.com/@cspell/dict-bash/-/dict-bash-4.1.1.tgz#fe28016096f44d4a09fe4c5bcaf6fa40f33d98c6" 106 | integrity sha512-8czAa/Mh96wu2xr0RXQEGMTBUGkTvYn/Pb0o+gqOO1YW+poXGQc3gx0YPqILDryP/KCERrNvkWUJz3iGbvwC2A== 107 | 108 | "@cspell/dict-companies@^3.0.9": 109 | version "3.0.17" 110 | resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-3.0.17.tgz#98c8bed74892a415f9471f77d11d2aa8f727b103" 111 | integrity sha512-vo1jbozgZWSzz2evIL26kLd35tVb+5kW/UTvTzAwaWutSWRloRyKx38nj2CaLJ2IFxBdiATteCFGTzKCvJJl6A== 112 | 113 | "@cspell/dict-cpp@^5.0.2": 114 | version "5.0.4" 115 | resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-5.0.4.tgz#2c237dd5d690ee7464c612fd0ef8f2244359d97f" 116 | integrity sha512-Vmz/CCb2d91ES5juaO8+CFWeTa2AFsbpR8bkCPJq+P8cRP16+37tY0zNXEBSK/1ur4MakaRf76jeQBijpZxw0Q== 117 | 118 | "@cspell/dict-cryptocurrencies@^3.0.1": 119 | version "3.0.1" 120 | resolved "https://registry.yarnpkg.com/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz#de1c235d6427946b679d23aacff12fea94e6385b" 121 | integrity sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w== 122 | 123 | "@cspell/dict-csharp@^4.0.2": 124 | version "4.0.2" 125 | resolved "https://registry.yarnpkg.com/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz#e55659dbe594e744d86b1baf0f3397fe57b1e283" 126 | integrity sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g== 127 | 128 | "@cspell/dict-css@^4.0.5": 129 | version "4.0.6" 130 | resolved "https://registry.yarnpkg.com/@cspell/dict-css/-/dict-css-4.0.6.tgz#39cf199e68d6e17b9518938fa64368cec2f7f9ca" 131 | integrity sha512-2Lo8W2ezHmGgY8cWFr4RUwnjbndna5mokpCK/DuxGILQnuajR0J31ANQOXj/8iZM2phFB93ZzMNk/0c04TDfSQ== 132 | 133 | "@cspell/dict-dart@^2.0.2": 134 | version "2.0.3" 135 | resolved "https://registry.yarnpkg.com/@cspell/dict-dart/-/dict-dart-2.0.3.tgz#75e7ffe47d5889c2c831af35acdd92ebdbd4cf12" 136 | integrity sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw== 137 | 138 | "@cspell/dict-data-science@^1.0.0": 139 | version "1.0.8" 140 | resolved "https://registry.yarnpkg.com/@cspell/dict-data-science/-/dict-data-science-1.0.8.tgz#ceba98fb70ed872739d2c6e5cbc94020818450e8" 141 | integrity sha512-uGx0rd3BftfZ5mvXtPxvLNkQ33y0ylNw4GpBAAfF3hgGtifKdvLSmphOGuNgDYUPpJ0+e025bsvtN0/ZZCzWTg== 142 | 143 | "@cspell/dict-django@^4.0.2": 144 | version "4.1.0" 145 | resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-4.1.0.tgz#2d4b765daf3c83e733ef3e06887ea34403a4de7a" 146 | integrity sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w== 147 | 148 | "@cspell/dict-docker@^1.1.6": 149 | version "1.1.7" 150 | resolved "https://registry.yarnpkg.com/@cspell/dict-docker/-/dict-docker-1.1.7.tgz#bcf933283fbdfef19c71a642e7e8c38baf9014f2" 151 | integrity sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A== 152 | 153 | "@cspell/dict-dotnet@^5.0.0": 154 | version "5.0.0" 155 | resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-5.0.0.tgz#13690aafe14b240ad17a30225ac1ec29a5a6a510" 156 | integrity sha512-EOwGd533v47aP5QYV8GlSSKkmM9Eq8P3G/eBzSpH3Nl2+IneDOYOBLEUraHuiCtnOkNsz0xtZHArYhAB2bHWAw== 157 | 158 | "@cspell/dict-elixir@^4.0.2": 159 | version "4.0.3" 160 | resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-4.0.3.tgz#57c25843e46cf3463f97da72d9ef8e37c818296f" 161 | integrity sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q== 162 | 163 | "@cspell/dict-en-common-misspellings@^1.0.2": 164 | version "1.0.2" 165 | resolved "https://registry.yarnpkg.com/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-1.0.2.tgz#3c4ebab8e9e906d66d60f53c8f8c2e77b7f108e7" 166 | integrity sha512-jg7ZQZpZH7+aAxNBlcAG4tGhYF6Ksy+QS5Df73Oo+XyckBjC9QS+PrRwLTeYoFIgXy5j3ICParK5r3MSSoL4gw== 167 | 168 | "@cspell/dict-en-gb@1.1.33": 169 | version "1.1.33" 170 | resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" 171 | integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== 172 | 173 | "@cspell/dict-en_us@^4.3.2": 174 | version "4.3.6" 175 | resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-4.3.6.tgz#1f554cf4e235af4e8d115c5924c87537b16a08d0" 176 | integrity sha512-odhgsjNZI9BtEOJdvqfAuv/3yz5aB1ngfBNaph7WSnYVt//9e3fhrElZ6/pIIkoyuGgeQPwz1fXt+tMgcnLSEQ== 177 | 178 | "@cspell/dict-filetypes@^3.0.0": 179 | version "3.0.1" 180 | resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-3.0.1.tgz#61642b14af90894e6acf4c00f20ab2d097c1ed12" 181 | integrity sha512-8z8mY1IbrTyTRumx2vvD9yzRhNMk9SajM/GtI5hdMM2pPpNSp25bnuauzjRf300eqlqPY2MNb5MmhBFO014DJw== 182 | 183 | "@cspell/dict-fonts@^3.0.2": 184 | version "3.0.2" 185 | resolved "https://registry.yarnpkg.com/@cspell/dict-fonts/-/dict-fonts-3.0.2.tgz#657d871cf627466765166cf18c448743c19317e2" 186 | integrity sha512-Z5QdbgEI7DV+KPXrAeDA6dDm/vTzyaW53SGlKqz6PI5VhkOjgkBXv3YtZjnxMZ4dY2ZIqq+RUK6qa9Pi8rQdGQ== 187 | 188 | "@cspell/dict-fullstack@^3.1.5": 189 | version "3.1.5" 190 | resolved "https://registry.yarnpkg.com/@cspell/dict-fullstack/-/dict-fullstack-3.1.5.tgz#35d18678161f214575cc613dd95564e05422a19c" 191 | integrity sha512-6ppvo1dkXUZ3fbYn/wwzERxCa76RtDDl5Afzv2lijLoijGGUw5yYdLBKJnx8PJBGNLh829X352ftE7BElG4leA== 192 | 193 | "@cspell/dict-gaming-terms@^1.0.4": 194 | version "1.0.4" 195 | resolved "https://registry.yarnpkg.com/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.4.tgz#b67d89d014d865da6cb40de4269d4c162a00658e" 196 | integrity sha512-hbDduNXlk4AOY0wFxcDMWBPpm34rpqJBeqaySeoUH70eKxpxm+dvjpoRLJgyu0TmymEICCQSl6lAHTHSDiWKZg== 197 | 198 | "@cspell/dict-git@^2.0.0": 199 | version "2.0.0" 200 | resolved "https://registry.yarnpkg.com/@cspell/dict-git/-/dict-git-2.0.0.tgz#fa5cb298845da9c69efc01c6af07a99097718dc9" 201 | integrity sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w== 202 | 203 | "@cspell/dict-golang@^6.0.1": 204 | version "6.0.2" 205 | resolved "https://registry.yarnpkg.com/@cspell/dict-golang/-/dict-golang-6.0.2.tgz#dcba58b9e658c1cc713c19965a358185d15d1987" 206 | integrity sha512-5pyZn4AAiYukAW+gVMIMVmUSkIERFrDX2vtPDjg8PLQUhAHWiVeQSDjuOhq9/C5GCCEZU/zWSONkGiwLBBvV9A== 207 | 208 | "@cspell/dict-haskell@^4.0.1": 209 | version "4.0.1" 210 | resolved "https://registry.yarnpkg.com/@cspell/dict-haskell/-/dict-haskell-4.0.1.tgz#e9fca7c452411ff11926e23ffed2b50bb9b95e47" 211 | integrity sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ== 212 | 213 | "@cspell/dict-html-symbol-entities@^4.0.0": 214 | version "4.0.0" 215 | resolved "https://registry.yarnpkg.com/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz#4d86ac18a4a11fdb61dfb6f5929acd768a52564f" 216 | integrity sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw== 217 | 218 | "@cspell/dict-html@^4.0.3": 219 | version "4.0.3" 220 | resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-4.0.3.tgz#155450cb57750774583fce463d01d6323ab41701" 221 | integrity sha512-Gae8i8rrArT0UyG1I6DHDK62b7Be6QEcBSIeWOm4VIIW1CASkN9B0qFgSVnkmfvnu1Y3H7SSaaEynKjdj3cs8w== 222 | 223 | "@cspell/dict-java@^5.0.5": 224 | version "5.0.5" 225 | resolved "https://registry.yarnpkg.com/@cspell/dict-java/-/dict-java-5.0.5.tgz#c673f27ce7a5d96e205f42e8be540aeda0beef11" 226 | integrity sha512-X19AoJgWIBwJBSWGFqSgHaBR/FEykBHTMjL6EqOnhIGEyE9nvuo32tsSHjXNJ230fQxQptEvRZoaldNLtKxsRg== 227 | 228 | "@cspell/dict-k8s@^1.0.1": 229 | version "1.0.1" 230 | resolved "https://registry.yarnpkg.com/@cspell/dict-k8s/-/dict-k8s-1.0.1.tgz#6c0cc521dd42fee2c807368ebfef77137686f3a1" 231 | integrity sha512-gc5y4Nm3hVdMZNBZfU2M1AsAmObZsRWjCUk01NFPfGhFBXyVne41T7E62rpnzu5330FV/6b/TnFcPgRmak9lLw== 232 | 233 | "@cspell/dict-latex@^4.0.0": 234 | version "4.0.0" 235 | resolved "https://registry.yarnpkg.com/@cspell/dict-latex/-/dict-latex-4.0.0.tgz#85054903db834ea867174795d162e2a8f0e9c51e" 236 | integrity sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ== 237 | 238 | "@cspell/dict-lorem-ipsum@^3.0.0": 239 | version "3.0.0" 240 | resolved "https://registry.yarnpkg.com/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-3.0.0.tgz#c6347660fcab480b47bdcaec3b57e8c3abc4af68" 241 | integrity sha512-msEV24qEpzWZs2kcEicqYlhyBpR0amfDkJOs+iffC07si9ftqtQ+yP3lf1VFLpgqw3SQh1M1vtU7RD4sPrNlcQ== 242 | 243 | "@cspell/dict-lua@^4.0.1": 244 | version "4.0.1" 245 | resolved "https://registry.yarnpkg.com/@cspell/dict-lua/-/dict-lua-4.0.1.tgz#4c31975646cb2d71f1216c7aeaa0c5ab6994ea25" 246 | integrity sha512-j0MFmeCouSoC6EdZTbvGe1sJ9V+ruwKSeF+zRkNNNload7R72Co5kX1haW2xLHGdlq0kqSy1ODRZKdVl0e+7hg== 247 | 248 | "@cspell/dict-node@^4.0.2": 249 | version "4.0.2" 250 | resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-4.0.2.tgz#9e5f64d882568fdd2a2243542d1263dbbb87c53a" 251 | integrity sha512-FEQJ4TnMcXEFslqBQkXa5HposMoCGsiBv2ux4IZuIXgadXeHKHUHk60iarWpjhzNzQLyN2GD7NoRMd12bK3Llw== 252 | 253 | "@cspell/dict-npm@^5.0.5": 254 | version "5.0.7" 255 | resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-5.0.7.tgz#f2977579413a09d53fb385ed48f93184aad55aea" 256 | integrity sha512-6SegF0HsVaBTl6PlHjeErG8Av+tRYkUG1yaXUQIGWXU0A8oxhI0o4PuL65UWH5lkCKhJyGai69Cd0iytL0oVFg== 257 | 258 | "@cspell/dict-php@^4.0.1": 259 | version "4.0.1" 260 | resolved "https://registry.yarnpkg.com/@cspell/dict-php/-/dict-php-4.0.1.tgz#f3c5cd241f43a32b09355370fc6ce7bd50e6402c" 261 | integrity sha512-XaQ/JkSyq2c07MfRG54DjLi2CV+HHwS99DDCAao9Fq2JfkWroTQsUeek7wYZXJATrJVOULoV3HKih12x905AtQ== 262 | 263 | "@cspell/dict-powershell@^5.0.1": 264 | version "5.0.2" 265 | resolved "https://registry.yarnpkg.com/@cspell/dict-powershell/-/dict-powershell-5.0.2.tgz#2b1d7d514354b6d7de405d5faaef30f8eca0ef09" 266 | integrity sha512-IHfWLme3FXE7vnOmMncSBxOsMTdNWd1Vcyhag03WS8oANSgX8IZ+4lMI00mF0ptlgchf16/OU8WsV4pZfikEFw== 267 | 268 | "@cspell/dict-public-licenses@^2.0.2": 269 | version "2.0.3" 270 | resolved "https://registry.yarnpkg.com/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.3.tgz#fa03649a5d6b8284e0c1da17eb449707df1a2a1c" 271 | integrity sha512-JSLEdpEYufQ1H+93UHi+axlqQm1fhgK6kpdLHp6uPHu//CsvETcqNVawjB+qOdI/g38JTMw5fBqSd0aGNxa6Dw== 272 | 273 | "@cspell/dict-python@^4.0.2": 274 | version "4.1.4" 275 | resolved "https://registry.yarnpkg.com/@cspell/dict-python/-/dict-python-4.1.4.tgz#c8e3bd7acbb1f88a8777ca7f67682568f317b5f0" 276 | integrity sha512-4JJ6MjIyuZN4h2VkSxZxiQ55lVh6NccW/0H6rdu0aDz+E3uyFVFtlBp5kTY5jIA11PZqSZZpyowzGnwrJX6w0g== 277 | dependencies: 278 | "@cspell/dict-data-science" "^1.0.0" 279 | 280 | "@cspell/dict-r@^2.0.1": 281 | version "2.0.1" 282 | resolved "https://registry.yarnpkg.com/@cspell/dict-r/-/dict-r-2.0.1.tgz#73474fb7cce45deb9094ebf61083fbf5913f440a" 283 | integrity sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA== 284 | 285 | "@cspell/dict-ruby@^5.0.0": 286 | version "5.0.0" 287 | resolved "https://registry.yarnpkg.com/@cspell/dict-ruby/-/dict-ruby-5.0.0.tgz#ca22ddf0842f29b485e3ef585c666c6be5227e6d" 288 | integrity sha512-ssb96QxLZ76yPqFrikWxItnCbUKhYXJ2owkoIYzUGNFl2CHSoHCb5a6Zetum9mQ/oUA3gNeUhd28ZUlXs0la2A== 289 | 290 | "@cspell/dict-rust@^4.0.1": 291 | version "4.0.1" 292 | resolved "https://registry.yarnpkg.com/@cspell/dict-rust/-/dict-rust-4.0.1.tgz#ef0b88cb3a45265824e2c9ce31b0baa4e1050351" 293 | integrity sha512-xJSSzHDK2z6lSVaOmMxl3PTOtfoffaxMo7fTcbZUF+SCJzfKbO6vnN9TCGX2sx1RHFDz66Js6goz6SAZQdOwaw== 294 | 295 | "@cspell/dict-scala@^5.0.0": 296 | version "5.0.0" 297 | resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-5.0.0.tgz#b64365ad559110a36d44ccd90edf7151ea648022" 298 | integrity sha512-ph0twaRoV+ylui022clEO1dZ35QbeEQaKTaV2sPOsdwIokABPIiK09oWwGK9qg7jRGQwVaRPEq0Vp+IG1GpqSQ== 299 | 300 | "@cspell/dict-software-terms@^3.1.6": 301 | version "3.2.0" 302 | resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-3.2.0.tgz#41f5a7ff187298f04c9d564d45423afaddf637e0" 303 | integrity sha512-RI6sv4Bc4i42YH/ofVelv8lXpJRhCyS9IhI2BtejUoMXKhKA9gC01ATXOylx+oaQmj3t5ark4R50xKFRvC7ENA== 304 | 305 | "@cspell/dict-sql@^2.1.0": 306 | version "2.1.1" 307 | resolved "https://registry.yarnpkg.com/@cspell/dict-sql/-/dict-sql-2.1.1.tgz#eb16c8bece4ff3154a193fe854a600ed0f75c64c" 308 | integrity sha512-v1mswi9NF40+UDUMuI148YQPEQvWjac72P6ZsjlRdLjEiQEEMEsTQ+zlkIdnzC9QCNyJaqD5Liq9Mn78/8Zxtw== 309 | 310 | "@cspell/dict-svelte@^1.0.2": 311 | version "1.0.2" 312 | resolved "https://registry.yarnpkg.com/@cspell/dict-svelte/-/dict-svelte-1.0.2.tgz#0c866b08a7a6b33bbc1a3bdbe6a1b484ca15cdaa" 313 | integrity sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q== 314 | 315 | "@cspell/dict-swift@^2.0.1": 316 | version "2.0.1" 317 | resolved "https://registry.yarnpkg.com/@cspell/dict-swift/-/dict-swift-2.0.1.tgz#06ec86e52e9630c441d3c19605657457e33d7bb6" 318 | integrity sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw== 319 | 320 | "@cspell/dict-typescript@^3.1.1": 321 | version "3.1.1" 322 | resolved "https://registry.yarnpkg.com/@cspell/dict-typescript/-/dict-typescript-3.1.1.tgz#25a9c241fa79c032f907db21b0aaf7c7baee6cc3" 323 | integrity sha512-N9vNJZoOXmmrFPR4ir3rGvnqqwmQGgOYoL1+y6D4oIhyr7FhaYiyF/d7QT61RmjZQcATMa6PSL+ZisCeRLx9+A== 324 | 325 | "@cspell/dict-vue@^3.0.0": 326 | version "3.0.0" 327 | resolved "https://registry.yarnpkg.com/@cspell/dict-vue/-/dict-vue-3.0.0.tgz#68ccb432ad93fcb0fd665352d075ae9a64ea9250" 328 | integrity sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A== 329 | 330 | "@cspell/dynamic-import@6.31.1": 331 | version "6.31.1" 332 | resolved "https://registry.yarnpkg.com/@cspell/dynamic-import/-/dynamic-import-6.31.1.tgz#26e218362e98158be5c88f970ce774458e53dd60" 333 | integrity sha512-uliIUv9uZlnyYmjUlcw/Dm3p0xJOEnWJNczHAfqAl4Ytg6QZktw0GtUA9b1umbRXLv0KRTPtSC6nMq3cR7rRmQ== 334 | dependencies: 335 | import-meta-resolve "^2.2.2" 336 | 337 | "@cspell/strong-weak-map@6.31.1": 338 | version "6.31.1" 339 | resolved "https://registry.yarnpkg.com/@cspell/strong-weak-map/-/strong-weak-map-6.31.1.tgz#370faeae5ecb0c9a55344a34cd70f1690c62de01" 340 | integrity sha512-z8AuWvUuSnugFKJOA9Ke0aiFuehcqLFqia9bk8XaQNEWr44ahPVn3sEWnAncTxPbpWuUw5UajoJa0egRAE1CCg== 341 | 342 | "@isaacs/cliui@^8.0.2": 343 | version "8.0.2" 344 | resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" 345 | integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== 346 | dependencies: 347 | string-width "^5.1.2" 348 | string-width-cjs "npm:string-width@^4.2.0" 349 | strip-ansi "^7.0.1" 350 | strip-ansi-cjs "npm:strip-ansi@^6.0.1" 351 | wrap-ansi "^8.1.0" 352 | wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" 353 | 354 | "@nodelib/fs.scandir@2.1.5": 355 | version "2.1.5" 356 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 357 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 358 | dependencies: 359 | "@nodelib/fs.stat" "2.0.5" 360 | run-parallel "^1.1.9" 361 | 362 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 363 | version "2.0.5" 364 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 365 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 366 | 367 | "@nodelib/fs.walk@^1.2.3": 368 | version "1.2.8" 369 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 370 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 371 | dependencies: 372 | "@nodelib/fs.scandir" "2.1.5" 373 | fastq "^1.6.0" 374 | 375 | "@pkgjs/parseargs@^0.11.0": 376 | version "0.11.0" 377 | resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" 378 | integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== 379 | 380 | ansi-regex@^5.0.1: 381 | version "5.0.1" 382 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 383 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 384 | 385 | ansi-regex@^6.0.1: 386 | version "6.0.1" 387 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" 388 | integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== 389 | 390 | ansi-styles@^3.2.1: 391 | version "3.2.1" 392 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 393 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 394 | dependencies: 395 | color-convert "^1.9.0" 396 | 397 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 398 | version "4.3.0" 399 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 400 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 401 | dependencies: 402 | color-convert "^2.0.1" 403 | 404 | ansi-styles@^6.1.0: 405 | version "6.2.1" 406 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" 407 | integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== 408 | 409 | argparse@^2.0.1: 410 | version "2.0.1" 411 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 412 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 413 | 414 | array-timsort@^1.0.3: 415 | version "1.0.3" 416 | resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" 417 | integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== 418 | 419 | balanced-match@^1.0.0: 420 | version "1.0.2" 421 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 422 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 423 | 424 | brace-expansion@^1.1.7: 425 | version "1.1.11" 426 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 427 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 428 | dependencies: 429 | balanced-match "^1.0.0" 430 | concat-map "0.0.1" 431 | 432 | brace-expansion@^2.0.1: 433 | version "2.0.1" 434 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 435 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 436 | dependencies: 437 | balanced-match "^1.0.0" 438 | 439 | braces@^3.0.2: 440 | version "3.0.2" 441 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 442 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 443 | dependencies: 444 | fill-range "^7.0.1" 445 | 446 | callsites@^3.0.0, callsites@^3.1.0: 447 | version "3.1.0" 448 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 449 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 450 | 451 | chalk@^2.0.0: 452 | version "2.4.2" 453 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 454 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 455 | dependencies: 456 | ansi-styles "^3.2.1" 457 | escape-string-regexp "^1.0.5" 458 | supports-color "^5.3.0" 459 | 460 | chalk@^4.1.2: 461 | version "4.1.2" 462 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 463 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 464 | dependencies: 465 | ansi-styles "^4.1.0" 466 | supports-color "^7.1.0" 467 | 468 | clear-module@^4.1.2: 469 | version "4.1.2" 470 | resolved "https://registry.yarnpkg.com/clear-module/-/clear-module-4.1.2.tgz#5a58a5c9f8dccf363545ad7284cad3c887352a80" 471 | integrity sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw== 472 | dependencies: 473 | parent-module "^2.0.0" 474 | resolve-from "^5.0.0" 475 | 476 | color-convert@^1.9.0: 477 | version "1.9.3" 478 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 479 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 480 | dependencies: 481 | color-name "1.1.3" 482 | 483 | color-convert@^2.0.1: 484 | version "2.0.1" 485 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 486 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 487 | dependencies: 488 | color-name "~1.1.4" 489 | 490 | color-name@1.1.3: 491 | version "1.1.3" 492 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 493 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 494 | 495 | color-name@~1.1.4: 496 | version "1.1.4" 497 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 498 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 499 | 500 | commander@^10.0.0: 501 | version "10.0.1" 502 | resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" 503 | integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== 504 | 505 | commander@~11.0.0: 506 | version "11.0.0" 507 | resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" 508 | integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== 509 | 510 | comment-json@^4.2.3: 511 | version "4.2.3" 512 | resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" 513 | integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw== 514 | dependencies: 515 | array-timsort "^1.0.3" 516 | core-util-is "^1.0.3" 517 | esprima "^4.0.1" 518 | has-own-prop "^2.0.0" 519 | repeat-string "^1.6.1" 520 | 521 | concat-map@0.0.1: 522 | version "0.0.1" 523 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 524 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 525 | 526 | configstore@^5.0.1: 527 | version "5.0.1" 528 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" 529 | integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== 530 | dependencies: 531 | dot-prop "^5.2.0" 532 | graceful-fs "^4.1.2" 533 | make-dir "^3.0.0" 534 | unique-string "^2.0.0" 535 | write-file-atomic "^3.0.0" 536 | xdg-basedir "^4.0.0" 537 | 538 | core-util-is@^1.0.3: 539 | version "1.0.3" 540 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 541 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 542 | 543 | cosmiconfig@8.0.0: 544 | version "8.0.0" 545 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.0.0.tgz#e9feae014eab580f858f8a0288f38997a7bebe97" 546 | integrity sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ== 547 | dependencies: 548 | import-fresh "^3.2.1" 549 | js-yaml "^4.1.0" 550 | parse-json "^5.0.0" 551 | path-type "^4.0.0" 552 | 553 | cross-spawn@^7.0.0: 554 | version "7.0.3" 555 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 556 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 557 | dependencies: 558 | path-key "^3.1.0" 559 | shebang-command "^2.0.0" 560 | which "^2.0.1" 561 | 562 | crypto-random-string@^2.0.0: 563 | version "2.0.0" 564 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" 565 | integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== 566 | 567 | cspell-dictionary@6.31.1: 568 | version "6.31.1" 569 | resolved "https://registry.yarnpkg.com/cspell-dictionary/-/cspell-dictionary-6.31.1.tgz#a5c52da365aa03d7b6454f017d97b0d4b3da8859" 570 | integrity sha512-7+K7aQGarqbpucky26wled7QSCJeg6VkLUWS+hLjyf0Cqc9Zew5xsLa4QjReExWUJx+a97jbiflITZNuWxgMrg== 571 | dependencies: 572 | "@cspell/cspell-pipe" "6.31.1" 573 | "@cspell/cspell-types" "6.31.1" 574 | cspell-trie-lib "6.31.1" 575 | fast-equals "^4.0.3" 576 | gensequence "^5.0.2" 577 | 578 | cspell-gitignore@6.31.2: 579 | version "6.31.2" 580 | resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-6.31.2.tgz#c297f0c094a96ea1ba8849fd17fb1a7feb274318" 581 | integrity sha512-B1i8aiXCIbb/08u0K3xnDyXtg0qD+lb5B2itOOXi7KXlPkKvIuN4hWyXxhVDweWyYWEzyXD5wBpPrqICVrStHQ== 582 | dependencies: 583 | cspell-glob "6.31.2" 584 | find-up "^5.0.0" 585 | 586 | cspell-glob@6.31.2: 587 | version "6.31.2" 588 | resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-6.31.2.tgz#877d914420e38aa3b375066f425e5a33514cc5e2" 589 | integrity sha512-ceTjHM4HaBgvG5S3oiB+PTPYq58EQYG6MmYpycDHzpR5I2H1NurK9lxWHfANmLbi0DsHn58tIZNDMUnnQj19Jw== 590 | dependencies: 591 | micromatch "^4.0.5" 592 | 593 | cspell-grammar@6.31.1: 594 | version "6.31.1" 595 | resolved "https://registry.yarnpkg.com/cspell-grammar/-/cspell-grammar-6.31.1.tgz#f766df3d5f1ec95a1e472fc339716757d2acfa56" 596 | integrity sha512-AsRVP0idcNFVSb9+p9XjMumFj3BUV67WIPWApaAzJl/dYyiIygQObRE+si0/QtFWGNw873b7hNhWZiKjqIdoaQ== 597 | dependencies: 598 | "@cspell/cspell-pipe" "6.31.1" 599 | "@cspell/cspell-types" "6.31.1" 600 | 601 | cspell-io@6.31.2: 602 | version "6.31.2" 603 | resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-6.31.2.tgz#5b1059779b8417510df077781a82cbe2b5c7463b" 604 | integrity sha512-Lp7LsF/f35LaOneROb/9mWiprShz2ONxjYFAt3bYP7gIxq41lWi8QhO+SN6spoqPp/wQXjSqJ7MuTZsemxPRnA== 605 | dependencies: 606 | "@cspell/cspell-service-bus" "6.31.1" 607 | node-fetch "^2.6.9" 608 | 609 | cspell-lib@6.31.2: 610 | version "6.31.2" 611 | resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-6.31.2.tgz#46e1f89876e5a5c055bc2493562c2c6d7ebff8fb" 612 | integrity sha512-LqaB2ZfVfQHKL5aZzYoKU6/UxxAtWeXAYwpC9l+satXmajYyXtAh4kWmuW+y7kKRH2jA79rJQS3QE6ToeSqgQQ== 613 | dependencies: 614 | "@cspell/cspell-bundled-dicts" "6.31.2" 615 | "@cspell/cspell-pipe" "6.31.1" 616 | "@cspell/cspell-types" "6.31.1" 617 | "@cspell/strong-weak-map" "6.31.1" 618 | clear-module "^4.1.2" 619 | comment-json "^4.2.3" 620 | configstore "^5.0.1" 621 | cosmiconfig "8.0.0" 622 | cspell-dictionary "6.31.1" 623 | cspell-glob "6.31.2" 624 | cspell-grammar "6.31.1" 625 | cspell-io "6.31.2" 626 | cspell-trie-lib "6.31.1" 627 | fast-equals "^4.0.3" 628 | find-up "^5.0.0" 629 | gensequence "^5.0.2" 630 | import-fresh "^3.3.0" 631 | resolve-from "^5.0.0" 632 | resolve-global "^1.0.0" 633 | vscode-languageserver-textdocument "^1.0.8" 634 | vscode-uri "^3.0.7" 635 | 636 | cspell-trie-lib@6.31.1: 637 | version "6.31.1" 638 | resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-6.31.1.tgz#72b272e16d53c15de5a1ef3178dd2519670daca7" 639 | integrity sha512-MtYh7s4Sbr1rKT31P2BK6KY+YfOy3dWsuusq9HnqCXmq6aZ1HyFgjH/9p9uvqGi/TboMqn1KOV8nifhXK3l3jg== 640 | dependencies: 641 | "@cspell/cspell-pipe" "6.31.1" 642 | "@cspell/cspell-types" "6.31.1" 643 | gensequence "^5.0.2" 644 | 645 | cspell@^6.31.2: 646 | version "6.31.2" 647 | resolved "https://registry.yarnpkg.com/cspell/-/cspell-6.31.2.tgz#c334ac34353fe446d82c27fe348bb17b4b3e9f7f" 648 | integrity sha512-HJcQ8jqL/1N3Mj5dufFnIZCX3ACuRoFTSVY6h3Bo5wBqd2iiJTyeQ1SY9Zymlxtb2KyJ6jQRiFmkWeFx2HVs7w== 649 | dependencies: 650 | "@cspell/cspell-pipe" "6.31.1" 651 | "@cspell/cspell-types" "6.31.1" 652 | "@cspell/dynamic-import" "6.31.1" 653 | chalk "^4.1.2" 654 | commander "^10.0.0" 655 | cspell-gitignore "6.31.2" 656 | cspell-glob "6.31.2" 657 | cspell-io "6.31.2" 658 | cspell-lib "6.31.2" 659 | fast-glob "^3.2.12" 660 | fast-json-stable-stringify "^2.1.0" 661 | file-entry-cache "^6.0.1" 662 | get-stdin "^8.0.0" 663 | imurmurhash "^0.1.4" 664 | semver "^7.3.8" 665 | strip-ansi "^6.0.1" 666 | vscode-uri "^3.0.7" 667 | 668 | deep-extend@^0.6.0: 669 | version "0.6.0" 670 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 671 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 672 | 673 | dot-prop@^5.2.0: 674 | version "5.3.0" 675 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" 676 | integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== 677 | dependencies: 678 | is-obj "^2.0.0" 679 | 680 | eastasianwidth@^0.2.0: 681 | version "0.2.0" 682 | resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 683 | integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== 684 | 685 | emoji-regex@^8.0.0: 686 | version "8.0.0" 687 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 688 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 689 | 690 | emoji-regex@^9.2.2: 691 | version "9.2.2" 692 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" 693 | integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== 694 | 695 | entities@~3.0.1: 696 | version "3.0.1" 697 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" 698 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== 699 | 700 | error-ex@^1.3.1: 701 | version "1.3.2" 702 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 703 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 704 | dependencies: 705 | is-arrayish "^0.2.1" 706 | 707 | escape-string-regexp@^1.0.5: 708 | version "1.0.5" 709 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 710 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 711 | 712 | esprima@^4.0.1: 713 | version "4.0.1" 714 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 715 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 716 | 717 | fast-equals@^4.0.3: 718 | version "4.0.3" 719 | resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-4.0.3.tgz#72884cc805ec3c6679b99875f6b7654f39f0e8c7" 720 | integrity sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg== 721 | 722 | fast-glob@^3.2.12: 723 | version "3.3.1" 724 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" 725 | integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== 726 | dependencies: 727 | "@nodelib/fs.stat" "^2.0.2" 728 | "@nodelib/fs.walk" "^1.2.3" 729 | glob-parent "^5.1.2" 730 | merge2 "^1.3.0" 731 | micromatch "^4.0.4" 732 | 733 | fast-json-stable-stringify@^2.1.0: 734 | version "2.1.0" 735 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 736 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 737 | 738 | fastq@^1.6.0: 739 | version "1.15.0" 740 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" 741 | integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== 742 | dependencies: 743 | reusify "^1.0.4" 744 | 745 | file-entry-cache@^6.0.1: 746 | version "6.0.1" 747 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 748 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 749 | dependencies: 750 | flat-cache "^3.0.4" 751 | 752 | fill-range@^7.0.1: 753 | version "7.0.1" 754 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 755 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 756 | dependencies: 757 | to-regex-range "^5.0.1" 758 | 759 | find-up@^5.0.0: 760 | version "5.0.0" 761 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 762 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 763 | dependencies: 764 | locate-path "^6.0.0" 765 | path-exists "^4.0.0" 766 | 767 | flat-cache@^3.0.4: 768 | version "3.0.4" 769 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" 770 | integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== 771 | dependencies: 772 | flatted "^3.1.0" 773 | rimraf "^3.0.2" 774 | 775 | flatted@^3.1.0: 776 | version "3.2.7" 777 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" 778 | integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== 779 | 780 | foreground-child@^3.1.0: 781 | version "3.1.1" 782 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" 783 | integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== 784 | dependencies: 785 | cross-spawn "^7.0.0" 786 | signal-exit "^4.0.1" 787 | 788 | fs.realpath@^1.0.0: 789 | version "1.0.0" 790 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 791 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 792 | 793 | gensequence@^5.0.2: 794 | version "5.0.2" 795 | resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-5.0.2.tgz#f065be2f9a5b2967b9cad7f33b2d79ce1f22dc82" 796 | integrity sha512-JlKEZnFc6neaeSVlkzBGGgkIoIaSxMgvdamRoPN8r3ozm2r9dusqxeKqYQ7lhzmj2UhFQP8nkyfCaiLQxiLrDA== 797 | 798 | get-stdin@^8.0.0: 799 | version "8.0.0" 800 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" 801 | integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== 802 | 803 | get-stdin@~9.0.0: 804 | version "9.0.0" 805 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" 806 | integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== 807 | 808 | glob-parent@^5.1.2: 809 | version "5.1.2" 810 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 811 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 812 | dependencies: 813 | is-glob "^4.0.1" 814 | 815 | glob@^7.1.3: 816 | version "7.2.3" 817 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 818 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 819 | dependencies: 820 | fs.realpath "^1.0.0" 821 | inflight "^1.0.4" 822 | inherits "2" 823 | minimatch "^3.1.1" 824 | once "^1.3.0" 825 | path-is-absolute "^1.0.0" 826 | 827 | glob@~10.2.7: 828 | version "10.2.7" 829 | resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.7.tgz#9dd2828cd5bc7bd861e7738d91e7113dda41d7d8" 830 | integrity sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA== 831 | dependencies: 832 | foreground-child "^3.1.0" 833 | jackspeak "^2.0.3" 834 | minimatch "^9.0.1" 835 | minipass "^5.0.0 || ^6.0.2" 836 | path-scurry "^1.7.0" 837 | 838 | global-dirs@^0.1.1: 839 | version "0.1.1" 840 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" 841 | integrity sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg== 842 | dependencies: 843 | ini "^1.3.4" 844 | 845 | graceful-fs@^4.1.2: 846 | version "4.2.11" 847 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 848 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 849 | 850 | has-flag@^3.0.0: 851 | version "3.0.0" 852 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 853 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 854 | 855 | has-flag@^4.0.0: 856 | version "4.0.0" 857 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 858 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 859 | 860 | has-own-prop@^2.0.0: 861 | version "2.0.0" 862 | resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" 863 | integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== 864 | 865 | ignore@~5.2.4: 866 | version "5.2.4" 867 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" 868 | integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== 869 | 870 | import-fresh@^3.2.1, import-fresh@^3.3.0: 871 | version "3.3.0" 872 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 873 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 874 | dependencies: 875 | parent-module "^1.0.0" 876 | resolve-from "^4.0.0" 877 | 878 | import-meta-resolve@^2.2.2: 879 | version "2.2.2" 880 | resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9" 881 | integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA== 882 | 883 | imurmurhash@^0.1.4: 884 | version "0.1.4" 885 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 886 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 887 | 888 | inflight@^1.0.4: 889 | version "1.0.6" 890 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 891 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 892 | dependencies: 893 | once "^1.3.0" 894 | wrappy "1" 895 | 896 | inherits@2: 897 | version "2.0.4" 898 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 899 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 900 | 901 | ini@^1.3.4: 902 | version "1.3.8" 903 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 904 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== 905 | 906 | ini@~3.0.0: 907 | version "3.0.1" 908 | resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" 909 | integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== 910 | 911 | is-arrayish@^0.2.1: 912 | version "0.2.1" 913 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 914 | integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== 915 | 916 | is-extglob@^2.1.1: 917 | version "2.1.1" 918 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 919 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 920 | 921 | is-fullwidth-code-point@^3.0.0: 922 | version "3.0.0" 923 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 924 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 925 | 926 | is-glob@^4.0.1: 927 | version "4.0.3" 928 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 929 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 930 | dependencies: 931 | is-extglob "^2.1.1" 932 | 933 | is-number@^7.0.0: 934 | version "7.0.0" 935 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 936 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 937 | 938 | is-obj@^2.0.0: 939 | version "2.0.0" 940 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" 941 | integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== 942 | 943 | is-typedarray@^1.0.0: 944 | version "1.0.0" 945 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 946 | integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== 947 | 948 | isexe@^2.0.0: 949 | version "2.0.0" 950 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 951 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 952 | 953 | jackspeak@^2.0.3: 954 | version "2.2.2" 955 | resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.2.tgz#707c62733924b8dc2a0a629dc6248577788b5385" 956 | integrity sha512-mgNtVv4vUuaKA97yxUHoA3+FkuhtxkjdXEWOyB/N76fjy0FjezEt34oy3epBtvCvS+7DyKwqCFWx/oJLV5+kCg== 957 | dependencies: 958 | "@isaacs/cliui" "^8.0.2" 959 | optionalDependencies: 960 | "@pkgjs/parseargs" "^0.11.0" 961 | 962 | js-tokens@^4.0.0: 963 | version "4.0.0" 964 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 965 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 966 | 967 | js-yaml@^4.1.0: 968 | version "4.1.0" 969 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 970 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 971 | dependencies: 972 | argparse "^2.0.1" 973 | 974 | json-parse-even-better-errors@^2.3.0: 975 | version "2.3.1" 976 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 977 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 978 | 979 | jsonc-parser@~3.2.0: 980 | version "3.2.0" 981 | resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" 982 | integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== 983 | 984 | lines-and-columns@^1.1.6: 985 | version "1.2.4" 986 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 987 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 988 | 989 | linkify-it@^4.0.1: 990 | version "4.0.1" 991 | resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" 992 | integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw== 993 | dependencies: 994 | uc.micro "^1.0.1" 995 | 996 | locate-path@^6.0.0: 997 | version "6.0.0" 998 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 999 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 1000 | dependencies: 1001 | p-locate "^5.0.0" 1002 | 1003 | lru-cache@^6.0.0: 1004 | version "6.0.0" 1005 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 1006 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 1007 | dependencies: 1008 | yallist "^4.0.0" 1009 | 1010 | "lru-cache@^9.1.1 || ^10.0.0": 1011 | version "10.0.0" 1012 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61" 1013 | integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw== 1014 | 1015 | make-dir@^3.0.0: 1016 | version "3.1.0" 1017 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1018 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 1019 | dependencies: 1020 | semver "^6.0.0" 1021 | 1022 | markdown-it@13.0.1: 1023 | version "13.0.1" 1024 | resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430" 1025 | integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q== 1026 | dependencies: 1027 | argparse "^2.0.1" 1028 | entities "~3.0.1" 1029 | linkify-it "^4.0.1" 1030 | mdurl "^1.0.1" 1031 | uc.micro "^1.0.5" 1032 | 1033 | markdownlint-cli@^0.35.0: 1034 | version "0.35.0" 1035 | resolved "https://registry.yarnpkg.com/markdownlint-cli/-/markdownlint-cli-0.35.0.tgz#1a6386777c6f20681e1425c0b7a056cf130bc46f" 1036 | integrity sha512-lVIIIV1MrUtjoocgDqXLxUCxlRbn7Ve8rsWppfwciUNwLlNS28AhNiyQ3PU7jjj4Qvj+rWTTvwkqg7AcdG988g== 1037 | dependencies: 1038 | commander "~11.0.0" 1039 | get-stdin "~9.0.0" 1040 | glob "~10.2.7" 1041 | ignore "~5.2.4" 1042 | js-yaml "^4.1.0" 1043 | jsonc-parser "~3.2.0" 1044 | markdownlint "~0.29.0" 1045 | minimatch "~9.0.1" 1046 | run-con "~1.2.11" 1047 | 1048 | markdownlint-micromark@0.1.5: 1049 | version "0.1.5" 1050 | resolved "https://registry.yarnpkg.com/markdownlint-micromark/-/markdownlint-micromark-0.1.5.tgz#a23400b101be32cd4336f2b6b4c47da31825524c" 1051 | integrity sha512-HvofNU4QCvfUCWnocQP1IAWaqop5wpWrB0mKB6SSh0fcpV0PdmQNS6tdUuFew1utpYlUvYYzz84oDkrD76GB9A== 1052 | 1053 | markdownlint@^0.29.0, markdownlint@~0.29.0: 1054 | version "0.29.0" 1055 | resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.29.0.tgz#9647478b7d5485965c557502fe54ee5a550033f2" 1056 | integrity sha512-ASAzqpODstu/Qsk0xW5BPgWnK/qjpBQ4e7IpsSvvFXcfYIjanLTdwFRJK1SIEEh0fGSMKXcJf/qhaZYHyME0wA== 1057 | dependencies: 1058 | markdown-it "13.0.1" 1059 | markdownlint-micromark "0.1.5" 1060 | 1061 | mdurl@^1.0.1: 1062 | version "1.0.1" 1063 | resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" 1064 | integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== 1065 | 1066 | merge2@^1.3.0: 1067 | version "1.4.1" 1068 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 1069 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 1070 | 1071 | micromatch@^4.0.4, micromatch@^4.0.5: 1072 | version "4.0.5" 1073 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" 1074 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== 1075 | dependencies: 1076 | braces "^3.0.2" 1077 | picomatch "^2.3.1" 1078 | 1079 | minimatch@^3.1.1: 1080 | version "3.1.2" 1081 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 1082 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1083 | dependencies: 1084 | brace-expansion "^1.1.7" 1085 | 1086 | minimatch@^9.0.1, minimatch@~9.0.1: 1087 | version "9.0.3" 1088 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" 1089 | integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== 1090 | dependencies: 1091 | brace-expansion "^2.0.1" 1092 | 1093 | minimist@^1.2.8: 1094 | version "1.2.8" 1095 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" 1096 | integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== 1097 | 1098 | "minipass@^5.0.0 || ^6.0.2": 1099 | version "6.0.2" 1100 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" 1101 | integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== 1102 | 1103 | "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": 1104 | version "7.0.2" 1105 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.2.tgz#58a82b7d81c7010da5bd4b2c0c85ac4b4ec5131e" 1106 | integrity sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA== 1107 | 1108 | node-fetch@^2.6.9: 1109 | version "2.6.12" 1110 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" 1111 | integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== 1112 | dependencies: 1113 | whatwg-url "^5.0.0" 1114 | 1115 | once@^1.3.0: 1116 | version "1.4.0" 1117 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1118 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 1119 | dependencies: 1120 | wrappy "1" 1121 | 1122 | p-limit@^3.0.2: 1123 | version "3.1.0" 1124 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 1125 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 1126 | dependencies: 1127 | yocto-queue "^0.1.0" 1128 | 1129 | p-locate@^5.0.0: 1130 | version "5.0.0" 1131 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 1132 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 1133 | dependencies: 1134 | p-limit "^3.0.2" 1135 | 1136 | parent-module@^1.0.0: 1137 | version "1.0.1" 1138 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 1139 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1140 | dependencies: 1141 | callsites "^3.0.0" 1142 | 1143 | parent-module@^2.0.0: 1144 | version "2.0.0" 1145 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-2.0.0.tgz#fa71f88ff1a50c27e15d8ff74e0e3a9523bf8708" 1146 | integrity sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg== 1147 | dependencies: 1148 | callsites "^3.1.0" 1149 | 1150 | parse-json@^5.0.0: 1151 | version "5.2.0" 1152 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" 1153 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== 1154 | dependencies: 1155 | "@babel/code-frame" "^7.0.0" 1156 | error-ex "^1.3.1" 1157 | json-parse-even-better-errors "^2.3.0" 1158 | lines-and-columns "^1.1.6" 1159 | 1160 | path-exists@^4.0.0: 1161 | version "4.0.0" 1162 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 1163 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 1164 | 1165 | path-is-absolute@^1.0.0: 1166 | version "1.0.1" 1167 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1168 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 1169 | 1170 | path-key@^3.1.0: 1171 | version "3.1.1" 1172 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 1173 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 1174 | 1175 | path-scurry@^1.7.0: 1176 | version "1.10.1" 1177 | resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" 1178 | integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== 1179 | dependencies: 1180 | lru-cache "^9.1.1 || ^10.0.0" 1181 | minipass "^5.0.0 || ^6.0.2 || ^7.0.0" 1182 | 1183 | path-type@^4.0.0: 1184 | version "4.0.0" 1185 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 1186 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 1187 | 1188 | picomatch@^2.3.1: 1189 | version "2.3.1" 1190 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1191 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1192 | 1193 | prettier@^3.0.0: 1194 | version "3.0.0" 1195 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.0.tgz#e7b19f691245a21d618c68bc54dc06122f6105ae" 1196 | integrity sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g== 1197 | 1198 | queue-microtask@^1.2.2: 1199 | version "1.2.3" 1200 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 1201 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 1202 | 1203 | repeat-string@^1.6.1: 1204 | version "1.6.1" 1205 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1206 | integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== 1207 | 1208 | resolve-from@^4.0.0: 1209 | version "4.0.0" 1210 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1211 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1212 | 1213 | resolve-from@^5.0.0: 1214 | version "5.0.0" 1215 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" 1216 | integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== 1217 | 1218 | resolve-global@^1.0.0: 1219 | version "1.0.0" 1220 | resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" 1221 | integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== 1222 | dependencies: 1223 | global-dirs "^0.1.1" 1224 | 1225 | reusify@^1.0.4: 1226 | version "1.0.4" 1227 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 1228 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1229 | 1230 | rimraf@^3.0.2: 1231 | version "3.0.2" 1232 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1233 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1234 | dependencies: 1235 | glob "^7.1.3" 1236 | 1237 | run-con@~1.2.11: 1238 | version "1.2.12" 1239 | resolved "https://registry.yarnpkg.com/run-con/-/run-con-1.2.12.tgz#51c319910e45a3bd71ee773564a89d96635c8c64" 1240 | integrity sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg== 1241 | dependencies: 1242 | deep-extend "^0.6.0" 1243 | ini "~3.0.0" 1244 | minimist "^1.2.8" 1245 | strip-json-comments "~3.1.1" 1246 | 1247 | run-parallel@^1.1.9: 1248 | version "1.2.0" 1249 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 1250 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1251 | dependencies: 1252 | queue-microtask "^1.2.2" 1253 | 1254 | semver@^6.0.0: 1255 | version "6.3.1" 1256 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 1257 | integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 1258 | 1259 | semver@^7.3.8: 1260 | version "7.5.4" 1261 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" 1262 | integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== 1263 | dependencies: 1264 | lru-cache "^6.0.0" 1265 | 1266 | shebang-command@^2.0.0: 1267 | version "2.0.0" 1268 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 1269 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 1270 | dependencies: 1271 | shebang-regex "^3.0.0" 1272 | 1273 | shebang-regex@^3.0.0: 1274 | version "3.0.0" 1275 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 1276 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 1277 | 1278 | signal-exit@^3.0.2: 1279 | version "3.0.7" 1280 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" 1281 | integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 1282 | 1283 | signal-exit@^4.0.1: 1284 | version "4.1.0" 1285 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 1286 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== 1287 | 1288 | "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: 1289 | version "4.2.3" 1290 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1291 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1292 | dependencies: 1293 | emoji-regex "^8.0.0" 1294 | is-fullwidth-code-point "^3.0.0" 1295 | strip-ansi "^6.0.1" 1296 | 1297 | string-width@^5.0.1, string-width@^5.1.2: 1298 | version "5.1.2" 1299 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" 1300 | integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== 1301 | dependencies: 1302 | eastasianwidth "^0.2.0" 1303 | emoji-regex "^9.2.2" 1304 | strip-ansi "^7.0.1" 1305 | 1306 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: 1307 | version "6.0.1" 1308 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1309 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1310 | dependencies: 1311 | ansi-regex "^5.0.1" 1312 | 1313 | strip-ansi@^7.0.1: 1314 | version "7.1.0" 1315 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" 1316 | integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== 1317 | dependencies: 1318 | ansi-regex "^6.0.1" 1319 | 1320 | strip-json-comments@~3.1.1: 1321 | version "3.1.1" 1322 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 1323 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 1324 | 1325 | supports-color@^5.3.0: 1326 | version "5.5.0" 1327 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1328 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1329 | dependencies: 1330 | has-flag "^3.0.0" 1331 | 1332 | supports-color@^7.1.0: 1333 | version "7.2.0" 1334 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1335 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1336 | dependencies: 1337 | has-flag "^4.0.0" 1338 | 1339 | to-regex-range@^5.0.1: 1340 | version "5.0.1" 1341 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1342 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1343 | dependencies: 1344 | is-number "^7.0.0" 1345 | 1346 | tr46@~0.0.3: 1347 | version "0.0.3" 1348 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 1349 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 1350 | 1351 | typedarray-to-buffer@^3.1.5: 1352 | version "3.1.5" 1353 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1354 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1355 | dependencies: 1356 | is-typedarray "^1.0.0" 1357 | 1358 | uc.micro@^1.0.1, uc.micro@^1.0.5: 1359 | version "1.0.6" 1360 | resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" 1361 | integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== 1362 | 1363 | unique-string@^2.0.0: 1364 | version "2.0.0" 1365 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" 1366 | integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== 1367 | dependencies: 1368 | crypto-random-string "^2.0.0" 1369 | 1370 | vscode-languageserver-textdocument@^1.0.8: 1371 | version "1.0.8" 1372 | resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz#9eae94509cbd945ea44bca8dcfe4bb0c15bb3ac0" 1373 | integrity sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q== 1374 | 1375 | vscode-uri@^3.0.7: 1376 | version "3.0.7" 1377 | resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8" 1378 | integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA== 1379 | 1380 | webidl-conversions@^3.0.0: 1381 | version "3.0.1" 1382 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 1383 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 1384 | 1385 | whatwg-url@^5.0.0: 1386 | version "5.0.0" 1387 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 1388 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 1389 | dependencies: 1390 | tr46 "~0.0.3" 1391 | webidl-conversions "^3.0.0" 1392 | 1393 | which@^2.0.1: 1394 | version "2.0.2" 1395 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1396 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1397 | dependencies: 1398 | isexe "^2.0.0" 1399 | 1400 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 1401 | version "7.0.0" 1402 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 1403 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 1404 | dependencies: 1405 | ansi-styles "^4.0.0" 1406 | string-width "^4.1.0" 1407 | strip-ansi "^6.0.0" 1408 | 1409 | wrap-ansi@^8.1.0: 1410 | version "8.1.0" 1411 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" 1412 | integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== 1413 | dependencies: 1414 | ansi-styles "^6.1.0" 1415 | string-width "^5.0.1" 1416 | strip-ansi "^7.0.1" 1417 | 1418 | wrappy@1: 1419 | version "1.0.2" 1420 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1421 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 1422 | 1423 | write-file-atomic@^3.0.0: 1424 | version "3.0.3" 1425 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" 1426 | integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== 1427 | dependencies: 1428 | imurmurhash "^0.1.4" 1429 | is-typedarray "^1.0.0" 1430 | signal-exit "^3.0.2" 1431 | typedarray-to-buffer "^3.1.5" 1432 | 1433 | xdg-basedir@^4.0.0: 1434 | version "4.0.0" 1435 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" 1436 | integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== 1437 | 1438 | yallist@^4.0.0: 1439 | version "4.0.0" 1440 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1441 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1442 | 1443 | yocto-queue@^0.1.0: 1444 | version "0.1.0" 1445 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 1446 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 1447 | --------------------------------------------------------------------------------