diff --git a/.eslintrc.js b/.eslintrc.js index adb3cb7b7a..8fce224bc3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,7 +36,7 @@ module.exports = { // We utilize class properties 'react/state-in-constructor': 'off', - // Dont use prop types since were using TypeScript + // Dont use prop types since we are using TypeScript 'react/default-props-match-prop-types': 'off', 'react/forbid-foreign-prop-types': 'off', 'react/forbid-prop-types': 'off', @@ -135,7 +135,7 @@ module.exports = { '@typescript-eslint/prefer-string-starts-ends-with': 'error', // Hard to migrate - // Errors for all try/catch blocks and any types from third-parties + // Errors for all try/catch blocks and any types from third parties '@typescript-eslint/no-unsafe-member-access': 'off', }, }; diff --git a/.gitignore b/.gitignore index 70cb9d45a3..725e239af2 100644 --- a/.gitignore +++ b/.gitignore @@ -57,7 +57,7 @@ out/ !.yarn/sdks !.yarn/versions .pnp.* -# prevent people from accidentally commiting a package-lock +# prevent people from accidentally committing a package-lock package-lock.json # Env files diff --git a/.vscode/settings.json b/.vscode/settings.json index aaca799c8d..7ce34dee13 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { // Prettier "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, // use ⌘-K S to format without saving + "editor.formatOnSave": true, // use ⌘-K S (or Ctrl-K S) to format without saving // Disable built-in formatters "html.format.enable": false, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba9b1fb69a..ce5503d240 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ The following is a set of guidelines for contributing to Base Web. These are jus ## Code of Conduct -This project and everyone participating in it are governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. +This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. ## How Can I Contribute? diff --git a/apps/base-docs/base-learn/docs/etherscan/etherscan-sbs.md b/apps/base-docs/base-learn/docs/etherscan/etherscan-sbs.md index b366c5bce2..ab476d0adb 100644 --- a/apps/base-docs/base-learn/docs/etherscan/etherscan-sbs.md +++ b/apps/base-docs/base-learn/docs/etherscan/etherscan-sbs.md @@ -13,7 +13,7 @@ In this article, you'll learn about Etherscan, a blockchain explorer to inspect By the end of this lesson, you should be able to: - List some of the features of Etherscan -- Read data from the Bored Apes Yacht Club contract on Etherscan +- Read data from the Bored Ape Yacht Club contract on Etherscan - Write data to a contract using Etherscan. --- diff --git a/apps/base-docs/base-learn/docs/introduction-to-ethereum/gas-use-in-eth-transactions.md b/apps/base-docs/base-learn/docs/introduction-to-ethereum/gas-use-in-eth-transactions.md index 935e47a39b..f1030a7596 100644 --- a/apps/base-docs/base-learn/docs/introduction-to-ethereum/gas-use-in-eth-transactions.md +++ b/apps/base-docs/base-learn/docs/introduction-to-ethereum/gas-use-in-eth-transactions.md @@ -119,4 +119,4 @@ Gas is a vital component of Ethereum. It's what regulates the execution of all t [Ethereum Docs]: https://ethereum.org/en/developers/docs/ [Mastering Ethereum]: https://github.com/ethereumbook/ethereumbook -[Ethereum demonimations]: https://www.gemini.com/en-US/cryptopedia/satoshi-value-gwei-to-ether-to-wei-converter-eth-gwei +[Ethereum denominations]: https://www.gemini.com/en-US/cryptopedia/satoshi-value-gwei-to-ether-to-wei-converter-eth-gwei diff --git a/apps/base-docs/base-learn/docs/learning-objectives.md b/apps/base-docs/base-learn/docs/learning-objectives.md index 65c2c2a8eb..3e60d19674 100644 --- a/apps/base-docs/base-learn/docs/learning-objectives.md +++ b/apps/base-docs/base-learn/docs/learning-objectives.md @@ -228,7 +228,7 @@ Use the script to regenerate this file. ### [The `useAccount` Hook](./reading-and-displaying-data/useAccount.md) -- Implement the `useAccount`` hook to show the user's address, connection state, network, and balance +- Implement the `useAccount` hook to show the user's address, connection state, network, and balance - Implement an `isMounted` hook to prevent hydration errors ### [The `useReadContract` Hook](./reading-and-displaying-data/useReadContract.md) diff --git a/apps/base-docs/base-learn/docs/minimal-tokens/minimal-token-sbs.md b/apps/base-docs/base-learn/docs/minimal-tokens/minimal-token-sbs.md index b1145639cd..6d0208d065 100644 --- a/apps/base-docs/base-learn/docs/minimal-tokens/minimal-token-sbs.md +++ b/apps/base-docs/base-learn/docs/minimal-tokens/minimal-token-sbs.md @@ -165,7 +165,7 @@ transact to MinimalToken.transfer errored: Error encoding arguments: Error: bad A more guaranteed way to destroy, or _burn_ a token, is to transfer it to the default address `0x0000000000000000000000000000000000000000`. This address is unowned and unownable, making it mathematically impossible to retrieve any tokens that are sent to it. Redeploy and try it out by sending 1000 tokens to the zero address. -The `totalSupply` remains unchanged, and the balance of the zero address are visible, but those tokens are stuck there forever. +The `totalSupply` remains unchanged, and the balance of the zero address is visible, but those tokens are stuck there forever. :::info diff --git a/apps/base-docs/base-learn/docs/reading-and-displaying-data/configuring-useReadContract.md b/apps/base-docs/base-learn/docs/reading-and-displaying-data/configuring-useReadContract.md index 2947f6d463..9f83ae171e 100644 --- a/apps/base-docs/base-learn/docs/reading-and-displaying-data/configuring-useReadContract.md +++ b/apps/base-docs/base-learn/docs/reading-and-displaying-data/configuring-useReadContract.md @@ -252,7 +252,7 @@ In this guide, you've learned how to use the `watch` feature of `useBlockNumber` [wagmi]: https://wagmi.sh/ [`useReadContract`]: https://wagmi.sh/react/hooks/useReadContract [`useReadContract` hook]: ./useReadContract -[`useBlocNumber`]: https://wagmi.sh/react/api/hooks/useBlockNumber +[`useBlockNumber`]: https://wagmi.sh/react/api/hooks/useBlockNumber [removed]: https://wagmi.sh/react/guides/migrate-from-v1-to-v2#removed-watch-property [`useReadContracts`]: https://wagmi.sh/react/hooks/useReadContracts [`pollingInterval`]: https://wagmi.sh/react/api/createConfig#pollinginterval diff --git a/apps/base-docs/base-learn/docs/reading-and-displaying-data/useAccount.md b/apps/base-docs/base-learn/docs/reading-and-displaying-data/useAccount.md index 4a82b76d8c..89b1567ba0 100644 --- a/apps/base-docs/base-learn/docs/reading-and-displaying-data/useAccount.md +++ b/apps/base-docs/base-learn/docs/reading-and-displaying-data/useAccount.md @@ -14,7 +14,7 @@ You can use this for connection-status-based rendering, to enable or disable con By the end of this guide you should be able to: -- Implement the `useAccount`` hook to show the user's address, connection state, network, and balance +- Implement the `useAccount` hook to show the user's address, connection state, network, and balance - Implement an `isMounted` hook to prevent hydration errors --- diff --git a/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md b/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md index b99a0c2542..82605b02cd 100644 --- a/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md +++ b/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md @@ -149,7 +149,7 @@ Review the **Warning** in the [layout] section of the docs for more details! ### Add a Function to Update `age` -It would also be good to be able update the `age` value. This problem has slightly different considerations. Sadly, `age` will never go down. It should also probably only go up by one year for each update. The `++` operator works in Solidity, so we can use that to create a function that simple increments age when called. +It would also be good to be able to update the `age` value. This problem has slightly different considerations. Sadly, `age` will never go down. It should also probably only go up by one year for each update. The `++` operator works in Solidity, so we can use that to create a function that simple increments age when called.
diff --git a/apps/base-docs/docs/building-with-base/base-contracts.md b/apps/base-docs/docs/building-with-base/base-contracts.md index 0267e59379..8e2803380a 100644 --- a/apps/base-docs/docs/building-with-base/base-contracts.md +++ b/apps/base-docs/docs/building-with-base/base-contracts.md @@ -108,15 +108,15 @@ Certain contracts are mandatory according to the [OP Stack SDK](https://stack.op | DelayedWETHProxy (FDG) | [0x489c2E5ebe0037bDb2DC039C5770757b8E54eA1F](https://sepolia.etherscan.io/address/0x489c2E5ebe0037bDb2DC039C5770757b8E54eA1F) | | DelayedWETHProxy (PDG) | [0x27A6128F707de3d99F89Bf09c35a4e0753E1B808](https://sepolia.etherscan.io/address/0x27A6128F707de3d99F89Bf09c35a4e0753E1B808) | | DisputeGameFactoryProxy | [0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1](https://sepolia.etherscan.io/address/0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1) | -| FaultDisputeGame | [0x5062792ED6A85cF72a1424a1b7f39eD0f7972a4B](https://sepolia.etherscan.io/address/0x5062792ED6A85cF72a1424a1b7f39eD0f7972a4B) | +| FaultDisputeGame | [0xB7fB44a61fdE2b9DB28a84366e168b14D1a1b103](https://sepolia.etherscan.io/address/0xB7fB44a61fdE2b9DB28a84366e168b14D1a1b103) | | L1CrossDomainMessenger | [0xC34855F4De64F1840e5686e64278da901e261f20](https://sepolia.etherscan.io/address/0xC34855F4De64F1840e5686e64278da901e261f20) | | L1ERC721Bridge | [0x21eFD066e581FA55Ef105170Cc04d74386a09190](https://sepolia.etherscan.io/address/0x21eFD066e581FA55Ef105170Cc04d74386a09190) | | L1StandardBridge | [0xfd0Bf71F60660E2f608ed56e1659C450eB113120](https://sepolia.etherscan.io/address/0xfd0Bf71F60660E2f608ed56e1659C450eB113120) | | L2OutputOracle | [0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254](https://sepolia.etherscan.io/address/0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254) | -| MIPS | [0x47B0E34C1054009e696BaBAAd56165e1e994144d](https://sepolia.etherscan.io/address/0x47B0E34C1054009e696BaBAAd56165e1e994144d) | +| MIPS | [0x69470D6970Cd2A006b84B1d4d70179c892cFCE01](https://sepolia.etherscan.io/address/0x69470D6970Cd2A006b84B1d4d70179c892cFCE01) | | OptimismMintableERC20Factory | [0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37](https://sepolia.etherscan.io/address/0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37) | | OptimismPortal | [0x49f53e41452C74589E85cA1677426Ba426459e85](https://sepolia.etherscan.io/address/0x49f53e41452C74589E85cA1677426Ba426459e85) | -| PermissionedDisputeGame | [0x593D20C4c69485B95D11507239BE2C725ea2A6fD](https://sepolia.etherscan.io/address/0x593D20C4c69485B95D11507239BE2C725ea2A6fD) | +| PermissionedDisputeGame | [0x68f600e592799c16D1b096616eDbf1681FB9c0De](https://sepolia.etherscan.io/address/0x68f600e592799c16D1b096616eDbf1681FB9c0De) | | PreimageOracle | [0x92240135b46fc1142dA181f550aE8f595B858854](https://sepolia.etherscan.io/address/0x92240135b46fc1142dA181f550aE8f595B858854) | | ProxyAdmin | [0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3](https://sepolia.etherscan.io/address/0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3) | | SystemConfig | [0xf272670eb55e895584501d564AfEB048bEd26194](https://sepolia.etherscan.io/address/0xf272670eb55e895584501d564AfEB048bEd26194) | diff --git a/apps/base-docs/docs/contracts.md b/apps/base-docs/docs/contracts.md index ba479583ee..69383189bb 100644 --- a/apps/base-docs/docs/contracts.md +++ b/apps/base-docs/docs/contracts.md @@ -87,7 +87,7 @@ This page lists contract addresses for onchain apps that we have deployed. :::info -Two community projects, [BaseX](https://basex-test.vercel.app/swap?currencyA=ETH¤cyB=0x036CbD53842c5426634e7929541eC2318f3dCF7e&focus=source) and [DapDap](https://testnet.base.dapdap.net/uniswap/swap), provide testnet interfaces for Uniswap contracts if you prefer to interact in the browser instead of with the contracts directly. +If you prefer interacting through a browser instead of directly with the contracts, you can try this community project: [DapDap](https://testnet.base.dapdap.net/uniswap/swap), which provides testnet interfaces for Uniswap contracts. ::: diff --git a/apps/base-docs/docs/notices/decomissioning-public-geth-archive-snapshots.md b/apps/base-docs/docs/notices/decomissioning-public-geth-archive-snapshots.md index c61c60059e..5875a52db4 100644 --- a/apps/base-docs/docs/notices/decomissioning-public-geth-archive-snapshots.md +++ b/apps/base-docs/docs/notices/decomissioning-public-geth-archive-snapshots.md @@ -1,7 +1,7 @@ --- title: Decommissioning Public Geth Archive Snapshots -slug: /decomissioning-public-geth-archive-snapshots -description: Public Geth archive snapshots will be decommissioned on December 15th, 2024. +slug: /decommissioning-public-geth-archive-snapshots +description: Public Geth archive snapshots were decommissioned on December 15th, 2024. keywords: [ Geth, @@ -20,7 +20,7 @@ hide_table_of_contents: true # Decommissioning Public Geth Archive Snapshots -As part of our ongoing efforts to optimize our services, we will be deprecating the Public Geth Archive Snapshots on _December 15th, 2024_. We understand that this change may affect your operations if you rely on these snapshots for maintaining your Ethereum infrastructure. This notice aims to provide you with a potential path forward and offer solutions to ensure a smooth transition. +As part of our ongoing efforts to optimize our services, Public Geth Archive Snapshots were deprecated on _December 15th, 2024_. We understand that this change may affect your operations if you rely on these snapshots for maintaining your Ethereum infrastructure. This notice aims to provide you with a potential path forward and offer solutions to ensure a smooth transition. ## Recommended Path Forward @@ -28,10 +28,4 @@ We recommend switching to Reth going forward. We will continue to maintain the R If you need continued Geth support, we would advise that you maintain your own snapshot that is specific to your infrastructure e.g. EBS on AWS. -To sync a Geth Archive node to tip: - -- Download the latest Geth Archive snapshot ~30 days old -- Use a beacon endpoint with historical blob data - - Alternatively you can run your own [blob archiver](https://github.com/base-org/blob-archiver) if you don't want to rely on a third party - -If you have any questions or would like assistance, please reach out to us on [Discord](https://base.org/discord) or [GitHub](https://github.com/base-org/base-node). +If you have any questions or would like assistance, please reach out to us on [Discord](https://base.org/discord) or [GitHub](https://github.com/base-org/node). diff --git a/apps/base-docs/docs/tokens/token-list.md b/apps/base-docs/docs/tokens/token-list.md index e713dc1b21..77cf52c4d6 100644 --- a/apps/base-docs/docs/tokens/token-list.md +++ b/apps/base-docs/docs/tokens/token-list.md @@ -23,7 +23,7 @@ hide_table_of_contents: true This page is intended for token issuers who already have an ERC-20 contract deployed on Ethereum and would like to submit their token for bridging between Ethereum and Base. Base uses the [Superchain token list](https://github.com/ethereum-optimism/ethereum-optimism.github.io) as a reference for tokens that have been deployed on Base. -**_Disclaimer: Base does not endorse any of the tokens that are listed in the Github repository and has conducted only preliminary checks, which include automated checks listed_** [**_here_**](https://github.com/ethereum-optimism/ethereum-optimism.github.io)**_._** +**_Disclaimer: Base does not endorse any of the tokens that are listed in the GitHub repository and has conducted only preliminary checks, which include automated checks listed_** [**_here_**](https://github.com/ethereum-optimism/ethereum-optimism.github.io)**_._** --- @@ -41,4 +41,4 @@ Follow the instructions in the [GitHub repository](https://github.com/ethereum-o ### Step 3: Await final approval -Reviews are regularly conducted by the Base team and you should receive a reply within 24-72 hours (depending on if the PR is opened on a week day, weekend or holiday). +Reviews are regularly conducted by the Base team and you should receive a reply within 24-72 hours (depending on if the PR is opened on a weekday, weekend or holiday). diff --git a/apps/base-docs/docs/tools/account-abstraction.md b/apps/base-docs/docs/tools/account-abstraction.md index 410897dfa7..139401a065 100644 --- a/apps/base-docs/docs/tools/account-abstraction.md +++ b/apps/base-docs/docs/tools/account-abstraction.md @@ -15,6 +15,9 @@ keywords: smart contract wallets, Alchemy, Biconomy, + Reown, + AppKit, + WalletConnect, Stackup, WalletKit, Zerodev, @@ -57,6 +60,14 @@ The Coinbase Developer Platform [Account Abstraction Kit](https://www.coinbase.c --- +## Reown (prev. known as WalletConnect) + +**[Reown](https://reown.com/?utm_source=base&utm_medium=docs&utm_campaign=backlinks)** gives developers the tools to build user experiences that make digital ownership effortless, intuitive, and secure. One of Reown's offerings is the AppKit SDK. + +**AppKit** is a powerful, free, and fully open-source SDK for developers looking to integrate wallet connections and other Web3 functionalities into their apps on any EVM and non-EVM chain. In just a few simple steps, you can provide your users with seamless wallet access, one-click authentication, social logins, and notifications—streamlining their experience while enabling advanced features like on-ramp functionality, in-app token swaps and smart accounts. Check out the [docs](https://docs.reown.com/appkit/overview?utm_source=base&utm_medium=docs&utm_campaign=backlinks) to get started. + +--- + ## Safe [Safe](https://docs.safe.global/getting-started/readme) provides modular smart account infrastructure and account abstraction stack via their Safe{Core} [Account Abstraction SDK](https://docs.safe.global/safe-core-aa-sdk/safe-core-sdk), [API](https://docs.safe.global/safe-core-api/supported-networks), and [Protocol](https://docs.safe.global/safe-core-protocol/safe-core-protocol). diff --git a/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md b/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md index 87e4e70b5d..675e7eb67d 100644 --- a/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md +++ b/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md @@ -1,7 +1,7 @@ --- title: Basenames + OnchainKit Tutorial slug: /basenames-tutorial-with-onchainkit -description: 'A tutorial that teaches how to intergrate Basenames to your wagmi/viem App using OnchainKit' +description: 'A tutorial that teaches how to integrate Basenames to your wagmi/viem App using OnchainKit' author: hughescoin keywords: ['build on base', 'viem', 'wagmi', 'frontend', 'onchain app development'] tags: ['account abstraction'] @@ -102,8 +102,6 @@ Ensure Chain is Set to Base Be sure to set the `chain={base}` parameter; otherwi ```typescript title="src/components/basename.tsx" 'use client'; import React from 'react'; -'use client'; -import React from 'react'; import { Avatar, Identity, Name, Address } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; diff --git a/apps/base-docs/docs/tools/basenames-tutorial.md b/apps/base-docs/docs/tools/basenames-tutorial.md index 83ac061960..f2cead5e8a 100644 --- a/apps/base-docs/docs/tools/basenames-tutorial.md +++ b/apps/base-docs/docs/tools/basenames-tutorial.md @@ -58,7 +58,7 @@ To interact with the Base blockchain, you will need to update the wagmi configur Update your wagmi.ts file as follows: -```typescript tile="wagmi.ts" +```typescript title="wagmi.ts" 'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; diff --git a/apps/base-docs/docs/tools/bridges-mainnet.md b/apps/base-docs/docs/tools/bridges-mainnet.md index 84eddae652..e86e91e268 100644 --- a/apps/base-docs/docs/tools/bridges-mainnet.md +++ b/apps/base-docs/docs/tools/bridges-mainnet.md @@ -61,7 +61,7 @@ See the [sample code repository](https://github.com/base-org/guides/tree/main/br :::caution -**Double check the token address for ERC-20s** You can use any ERC-20 that is +**Double-check the token address for ERC-20s** You can use any ERC-20 that is supported on the network. You can check what assets are on Base and the corresponding contract address via [this hub](https://github.com/ethereum-optimism/ethereum-optimism.github.io/tree/master/data). Ensure there is an address for `base`, [example](https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/data/WETH/data.json#L16-L18). diff --git a/apps/base-docs/docs/tools/data-indexers.md b/apps/base-docs/docs/tools/data-indexers.md index 6f72ec5f36..1ebbd3a908 100644 --- a/apps/base-docs/docs/tools/data-indexers.md +++ b/apps/base-docs/docs/tools/data-indexers.md @@ -201,15 +201,22 @@ To get started, visit the [developer documentation](https://academy.subquery.net ## The Graph -[The Graph](https://thegraph.com/) is an indexing protocol for organizing blockchain data and making it easily accessible with GraphQL. +[The Graph](https://thegraph.com/) is an indexing protocol that provides an easy way to query blockchain data through APIs known as subgraphs. -Base applications can use GraphQL to query open APIs called subgraphs, to retrieve data that is indexed on the network. With The Graph, you can build serverless applications that run entirely on public infrastructure. +With The Graph, you can benefit from: + - **Decentralized Indexing**: Enables indexing blockchain data through multiple indexers, thus eliminating any single point of failure + - **GraphQL Queries**: Provides a powerful GraphQL interface for querying indexed data, making data retrieval super simple. + - **Customization**: Define your own logic for transforming & storing blockchain data. Reuse subgraphs published by other developers on The Graph Network. -To get started, visit the [documentation](https://thegraph.com/docs/en/) or see [this quickstart](https://thegraph.com/docs/en/cookbook/quick-start/) on how to create, deploy, and query a subgraph. +Follow this [quick-start](https://thegraph.com/docs/en/quick-start/) guide to create, deploy, and query a subgraph within 5 minutes. #### Supported Networks -- [Base Mainnet](https://thegraph.com/docs/en/#supported-networks) +- Base Mainnet +- Base Sepolia (Testnet) + +See [all supported networks](https://thegraph.com/docs/en/#supported-networks) + --- diff --git a/apps/base-docs/docs/tools/ethers.md b/apps/base-docs/docs/tools/ethers.md index d59392c2b7..746d4fc3da 100644 --- a/apps/base-docs/docs/tools/ethers.md +++ b/apps/base-docs/docs/tools/ethers.md @@ -48,7 +48,7 @@ const ethers = require('ethers'); ## Connecting to Base -You can connect to Base by instantiating a new ethers.js `JsonRpcProvider` object with a RPC URL of the Base network: +You can connect to Base by instantiating a new ethers.js `JsonRpcProvider` object with an RPC URL of the Base network: ```javascript const ethers = require('ethers'); diff --git a/apps/base-docs/docs/tools/hardhat.md b/apps/base-docs/docs/tools/hardhat.md index 1065a66506..2b8b445b6a 100644 --- a/apps/base-docs/docs/tools/hardhat.md +++ b/apps/base-docs/docs/tools/hardhat.md @@ -41,7 +41,7 @@ networks: { accounts: [process.env.PRIVATE_KEY as string], gasPrice: 1000000000, }, - // for Sepolia testnet + // for Base Sepolia testnet "base-sepolia": { url: "https://sepolia.base.org", accounts: [process.env.PRIVATE_KEY as string], diff --git a/apps/base-docs/docs/tools/onboarding.md b/apps/base-docs/docs/tools/onboarding.md index 9d5679a986..1e04a5c4c6 100644 --- a/apps/base-docs/docs/tools/onboarding.md +++ b/apps/base-docs/docs/tools/onboarding.md @@ -13,6 +13,10 @@ keywords: onboard, onboarding, Privy, + Reown, + AppKit, + WalletConnect, + WalletKit, Crossmint, Dynamic, Particle Network, @@ -64,6 +68,30 @@ You can [get started with Privy here](https://docs.privy.io/guide/quickstart), a --- +## Reown (prev. known as WalletConnect) + +**[Reown](https://reown.com/?utm_source=base&utm_medium=docs&utm_campaign=backlinks)** gives developers the tools to build user experiences that make digital ownership effortless, intuitive, and secure. + +Reown has two major product offerings, they are, **AppKit** and **WalletKit**. + +### AppKit + +AppKit is a powerful, free, and fully open-source SDK for developers looking to integrate wallet connections and other Web3 functionalities into their apps on any EVM and non-EVM chain. In just a few simple steps, you can provide your users with seamless wallet access, one-click authentication, social logins, and notifications—streamlining their experience while enabling advanced features like on-ramp functionality, in-app token swaps and smart accounts. + +### WalletKit +WalletKit is a robust, open-source SDK designed to empower seamless wallet connections and interactions across any blockchain. With WalletKit, you can offer your users a simple and secure way to connect with thousands of apps, enabling features like one-click authentication, secure transaction signing, and streamlined wallet address verification. Its chain-agnostic design ensures effortless multi-chain support, eliminating the need for complex integrations while delivering unmatched connectivity and security. + +To summarize, **AppKit** is for **Web3 applications** and **WalletKit** is for **Web3 wallets**. + +You will be able to use Reown AppKit to power end-to-end wallet interactions on your Web3 app deployed on Base. + +Some links to learn more about Reown: +- [Website](https://reown.com/?utm_source=base&utm_medium=docs&utm_campaign=backlinks) +- [Blog](https://reown.com/blog?utm_source=base&utm_medium=docs&utm_campaign=backlinks) +- [Docs](https://docs.reown.com/?utm_source=base&utm_medium=docs&utm_campaign=backlinks) + +--- + ## Sequence [Sequence](https://sequence.xyz/base) is an all-in-one development platform for integrating web3 into games. Onboard, monetize, grow, and retain players with Sequence’s award-winning technology including: non-custodial Embedded Wallets, white labeled marketplaces and marketplace API, indexer, relayer, node gateway, Unity/Unreal/React Native/Mobile SDKs, transaction API, contract deployment, analytics, and more. [Learn more here](https://sequence.xyz/base) and start creating on [Sequence Builder](https://sequence.build/) now. diff --git a/apps/base-docs/docs/tools/oracles.md b/apps/base-docs/docs/tools/oracles.md index affb144a7d..03a3a07b39 100644 --- a/apps/base-docs/docs/tools/oracles.md +++ b/apps/base-docs/docs/tools/oracles.md @@ -173,7 +173,7 @@ See [this guide](https://docs.redstone.finance/) to learn how to use the RedSton [Supra](https://supraoracles.com) provides VRF and decentralized oracle price feeds that can be used for onchain and offchain use-cases such as spot and perpetual DEXes, lending protocols, and payments protocols. Supra’s oracle chain and consensus algorithm makes it one of the fastest-to-finality oracle providers, with layer-1 security guarantees. The pull oracle has a sub-second response time. Aside from speed and security, Supra’s rotating node architecture gathers data from 40+ data sources and applies a robust calculation methodology to get the most accurate value. The node provenance on the data dashboard also provides a fully transparent historical audit trail. Supra’s Distributed Oracle Agreement (DORA) paper was accepted into ICDCS 2023, the oldest distributed systems conference. -Visit the Supra [documentation](https://supraoracles.com/docs/) to learn more about integrating Supra's oracle and VRF into your Base project. +Visit the Supra [documentation](https://docs.supra.com) to learn more about integrating Supra's oracle and VRF into your Base project. #### Supported Networks diff --git a/apps/base-docs/docs/tools/web3.md b/apps/base-docs/docs/tools/web3.md index ba131a3729..2f1512204e 100644 --- a/apps/base-docs/docs/tools/web3.md +++ b/apps/base-docs/docs/tools/web3.md @@ -52,7 +52,7 @@ const { Web3 } = require('web3'); ## Connecting to Base -You can connect to Base by instantiating a new web3.js `Web3` object with a RPC URL of the Base network: +You can connect to Base by instantiating a new web3.js `Web3` object with an RPC URL of the Base network: ```javascript const { Web3 } = require('web3'); diff --git a/apps/base-docs/src/components/Banner/styles.module.css b/apps/base-docs/src/components/Banner/styles.module.css index 297c76c70d..26f6c4a9ea 100644 --- a/apps/base-docs/src/components/Banner/styles.module.css +++ b/apps/base-docs/src/components/Banner/styles.module.css @@ -47,7 +47,7 @@ } .bannerSpacer { - display: hidden; + display: none; font-size: 0.75rem; } diff --git a/apps/base-docs/src/css/root.css b/apps/base-docs/src/css/root.css index bcfcff7a46..19cac91451 100644 --- a/apps/base-docs/src/css/root.css +++ b/apps/base-docs/src/css/root.css @@ -223,7 +223,7 @@ html { --ifm-color-primary-lightest: rgb(146, 224, 208); --ifm-code-font-size: 95%; --search-font-size: 16px; - --search-font-weight: 16px; + --search-font-weight: 400; /* Base Docs Palette */ --base-docs-color-fg: #000000; diff --git a/apps/base-docs/tutorials/docs/0_run-a-base-node.md b/apps/base-docs/tutorials/docs/0_run-a-base-node.md index fb1e46433c..ab2941ee74 100644 --- a/apps/base-docs/tutorials/docs/0_run-a-base-node.md +++ b/apps/base-docs/tutorials/docs/0_run-a-base-node.md @@ -107,20 +107,20 @@ In the home directory of your Base Node, create a folder named `geth-data` or `r :::info -We will be deprecating the Public Geth Archive Snapshots on _December 15th, 2024_ and recommend switching to Reth going forward. We will continue to maintain the Reth archive snapshot. +Public Geth Archive Snapshots were deprecated on _December 15th, 2024_ and recommend switching to Reth going forward. We will continue to maintain the Reth archive snapshot. ::: | Network | Client | Snapshot Type | Command | | ------- | ------ | ------------- | --------------------------------------------------------------------------------------------------------------------- | | Testnet | Geth | Full | `wget https://sepolia-full-snapshots.base.org/$(curl https://sepolia-full-snapshots.base.org/latest)` | -| Testnet | Geth | Archive | `wget https://sepolia-archive-snapshots.base.org/$(curl https://sepolia-archive-snapshots.base.org/latest)` | +| Testnet | Geth | Archive | No longer supported | | Testnet | Reth | Archive | `wget https://sepolia-reth-archive-snapshots.base.org/$(curl https://sepolia-reth-archive-snapshots.base.org/latest)` | | Mainnet | Geth | Full | `wget https://mainnet-full-snapshots.base.org/$(curl https://mainnet-full-snapshots.base.org/latest)` | -| Mainnet | Geth | Archive | `wget https://mainnet-archive-snapshots.base.org/$(curl https://mainnet-archive-snapshots.base.org/latest)` | +| Mainnet | Geth | Archive | No longer supported | | Mainnet | Reth | Archive | `wget https://mainnet-reth-archive-snapshots.base.org/$(curl https://mainnet-reth-archive-snapshots.base.org/latest)` | -You'll then need to untar the downloaded snapshot and place the `geth` subfolder inside of it in the `geth-data` folder you created (unless you changed the location of your data directory). +You'll then need to untar the downloaded snapshot and place the `geth` or `reth` subfolder inside of it in the `geth-data` or `reth-data` folder you created (unless you changed the location of your data directory). Return to the root of your Base node folder and start your node. diff --git a/apps/base-docs/tutorials/docs/1_smart-wallet-spend-permissions.md b/apps/base-docs/tutorials/docs/1_smart-wallet-spend-permissions.md new file mode 100644 index 0000000000..4556ecc5a0 --- /dev/null +++ b/apps/base-docs/tutorials/docs/1_smart-wallet-spend-permissions.md @@ -0,0 +1,284 @@ +--- +title: 'Create Onchain Subscription Payments with Spend Permissions' +slug: /create-subscription-payments-with-spend-permissions +description: Implement a smart wallet signer for a subscription payment application. +author: hughescoin +keywords: [smart wallet, onchain, spend permissions, smart wallet, account abstraction] +tags: ['frontend', 'account abstraction'] +difficulty: medium +hide_table_of_contents: false +displayed_sidebar: null +--- + +# Create Onchain Subscription Payments with Spend Permissions + +## Overview + +Spend Permissions are a new onchain primitive that allows any user to grant an application permission to spend a specified amount of funds from their wallet. Spend Permissions are similar to **Session Keys**, where temporary permissions enable seamless user interaction without repeatedly prompting signatures. However, Spend Permissions are more secure because they are scoped and controlled by parameters such as **token**, **start time**, **end time**, **period**, and **allowance**, which a user signs off on when approving a Spend Permission. + +Existing Smart Wallets without Spend Permissions enabled will be asked to enable Spend Permissions the first time they interact with an application that requests a Spend Permission approval. Enabling Spend Permissions is easily done via a one-click, one-time approval flow. + +A typical flow is as follows: + +1. The user logs into an app with their Smart Wallet. +2. The app requests approval by presenting the user with the spend permissions. +3. The user reviews the scopes and either confirms or denies the request. +4. Upon approval, the app calls the **SpendPermission singleton contract** to initiate transactions, spending funds from the user's Smart Wallet under the granted scope. + +At any point, the user can revoke their Spend Permission. + +### Use Cases for Spend Permissions + +Spend Permissions allow for the following onchain functionalities: + +- **Subscription Payments**: Apps can collect recurring payments (e.g., monthly subscriptions) without requiring the user to re-sign each time. +- **Seamless In-App Purchases**: E-commerce stores and apps can spend funds directly for purchases without popup interruptions. +- **Gas Sponsorship**: Spend Permissions can be used alongside paymasters to sponsor gas fees for user transactions. +- **One-Click Mints**: Users can allocate an amount of funds for an app to spend on their behalf, enabling a series of onchain actions without requiring repeated approvals. + +--- + +## Objectives + +In this tutorial, we’ll walk through a demo application that uses Spend Permissions to enable onchain subscription payments. Specifically, you will: + +- Create a smart wallet from a public/private keypair. +- Enable an EOA to receive subscription payments. +- Implement a **Subscribe** button that: + - Calls the **spend** function to initiate transactions. + - Adds the **SpendPermission singleton contract** as an owner to the user’s Smart Wallet. + +By the end of this tutorial, your application will seamlessly request and utilize Spend Permissions to facilitate recurring onchain payments. + +## Prerequisites: + +### Coinbase CDP account[](https://docs.base.org/tutorials/gasless-transaction-on-base-using-a-paymaster/#coinbase-cdp-account 'Direct link to Coinbase CDP account') + +This is your access point to the Coinbase Cloud Developer Platform, where you can manage projects and utilize tools like the Paymaster. + +### Familiarity with Smart Wallets and ERC 4337[​](https://docs.base.org/tutorials/gasless-transaction-on-base-using-a-paymaster/#familiarity-with-smart-accounts-and-erc-4337 'Direct link to Familiarity with Smart Accounts and ERC 4337') + +Understand the basics of Smart Wallets and the ERC-4337 standard for advanced transaction patterns and account abstraction. + +### Familiarity with wagmi/viem + +Wagmi/viem are two libraries that enable smart contract interaction using typescript. It makes onchain development smoother and what you will use to create smart wallets, functions, etc. It easily allows onchain developers to use the same skillsets from Javascript/typescript and frontend development and bring it onchain. + +## Template Project + +Let's first start at a common place. Clone the template e-commerce store: + +```bash +git clone https://github.com/hughescoin/learn-spend-permissions.git + +cd learn-spend-permissions + +bun install +``` + +Create a .env file from the example provided: + +```bash +cp env.local.example .env +``` + +If you don’t have an existing keypair, follow these steps to generate one using Foundry: + +Install foundry if you don't have it. + +```sh +curl -L https://foundry.paradigm.xyz | bash +``` + +Then, create a private key pair: + +```bash +cast wallet new +``` + +Your terminal should output something similar to this: + +```bash +Successfully created new keypair. + +Address: 0x48155Eca1EC9e6986Eef6129A0024f84B8483B59 + +Private key: 0xcd57753bb4e308ba0c6f574e8af04a7bae0ca0aff5750ddd6275460f49635527 +``` + +Now that you have your keypair, it's time to create a "`Spender` client". The **Spender** is the account that will receive funds from users granting Spend Permissions. We'll use the keypair generated earlier to set this up. + +Start by opening the `.env` file in the Healing Honey project and adding your private key: + +```bash +SPENDER_PRIVATE_KEY=0xcd57753bb4e308ba0c6f574e8af04a7bae0ca0aff5750ddd6275460f49635527 +``` + +Next, navigate to the `src/app/lib/spender.ts` file. Here, you'll see the `privateKeyToAccount` function from Viem in use. This function creates a wallet from the private key, enabling it to sign transactions and messages. The generated `account` is then used to create a [Wallet Client], which allows signing and executing onchain transactions to interact with the Spend Permission contract. + +With your Spender Client set up, ensure all other required environment variables are configured for the app to work when running the dev server. + +Head over to [Coinbase Developer Platform](https://portal.cdp.coinbase.com/) to retrieve your Paymaster URL and API Key. These can be found under **Onchain Tools > Paymaster > Configuration**. +![cdp-config](../../assets/images/paymaster-tutorials/cdp-copy-endpoint.png) + +Copy the **Base Sepolia** (Base testnet) Paymaster URL and API Key, then update your `.env` file as follows: + +```bash +BASE_SEPOLIA_PAYMASTER_URL=https://api.developer.coinbase.com/rpc/v1/base-sepolia/YOUR_API_KEY +CDP_API_KEY=YOUR_API_KEY +NEXT_PUBLIC_ONCHAINKIT_API_KEY=YOUR_API_KEY +``` + +:::tip CDP API KEYS +For the `CDP_API_KEY` and `NEXT_PUBLIC_ONCHAINKIT_API_KEY`, extract the alphanumeric string from the Paymaster URL after the `base-sepolia` path. + +For example, if your Paymaster URL is: https://api.developer.coinbase.com/rpc/v1/base-sepolia/JJ8uIiSMZWgCOyL0EpJgNAf0qPegLMC0 + +The API Key would be: `JJ8uIiSMZWgCOyL0EpJgNAf0qPegLMC0` +::: + +:::warning +Please do not use these API Keys +::: + +Your .env file should now look like this: + +``` +COINBASE_COMMERCE_API_KEY="f3cbce52-6f03-49b1-ab34-4fe9e1311d9a" + +CDP_API_KEY="JJ8uIiSMZWgCOyL0EpJgNAf0qPegLMC0" + +NEXT_PUBLIC_ENVIRONMENT=localhost + +SPENDER_PRIVATE_KEY=0xa72d316dd59a9e9a876b80fa2bbe825a9836e66fd45d87a2ea3c9924a5b131a1 + +NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME=Healing Honey Shop + +NEXT_PUBLIC_ONCHAINKIT_API_KEY="JJ8uIiSMZWgCOyL0EpJgNAf0qPegLMC0" + +BASE_SEPOLIA_PAYMASTER_URL=https://api.developer.coinbase.com/rpc/v1/base-sepolia/JJ8uIiSMZWgCOyL0EpJgNAf0qPegLMC0 + +``` + +To ensure your app communicates with the correct server when a user interacts with their wallet, open the src/components/OnchainProviders.tsx file. + +Replace the // TODO comment with the following value for the keysUrl property: + +```json +keysUrl: "https://keys.coinbase.com/connect" +``` + +With these steps complete, your environment and Spender Client are ready to support onchain interactions. Now, let's move on to building the **Subscribe** button. + +Navigate to `src/components/Subscribe.tsx`. You'll notice that the component is incomplete and currently shows multiple errors. We'll address these issues to enable Spend Permission functionality. + +Spend Permissions rely on [EIP-712] signatures and include several parameters, or [scopes]. One key scope is the `allowance`, which defines the amount an app can spend on behalf of the user. For our application, this will be set to **85% of the user's cart total**, reflecting a **15% subscription discount**. To achieve this, add the following code to line 95 to calculate the `subscriptionAmountInWei` variable: + +```ts +const subscriptionAmountInEther = price ? subscriptionAmount / price : 0; +const subscriptionAmountInWei = parseEther(subscriptionAmountInEther.toString()); +``` + +By adding these lines of code, we enable the discounted price to be passed as the `allowance` in the Spend Permission. + +Next, we need to define the `period` and `end` parameters. The `period` specifies the time interval for resetting the used allowance (recurring basis), and the `end` specifies the Unix timestamp until which the Spend Permission remains valid. + +For this demo, we'll set: + +- `period`: 2629743 seconds (equivalent to one month) +- `end`: 1767291546 (Unix timestamp for January 1, 2026) + +Now, update the message constant to include these parameters. It should look like this: + +```ts +const message = { + account: accountAddress, + spender: process.env.NEXT_PUBLIC_SPENDER_ADDRESS! as Address, + token: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' as Address, + allowance: subscriptionAmountInWei, + period: 2629743, + start: Math.floor(Date.now() / 1000), + end: 1767291546, + salt: BigInt(0), + extraData: '0x' as Hex, +} as const; +``` + +By setting these values, we have defined the essential parameters for the Spend Permission, allowing our **Subscribe** button to handle recurring payments with ease. Let's continue enhancing the functionality in the next steps. + +You may have noticed that when the user clicks the **Subscribe** button, it sends data to the `/collect` route. However, this route is currently broken. Let's address this issue to complete the functionality of our application. + +In its current state, the `/collect` route contains incomplete logic for interacting with the `Spend Permission Manager` singleton contract. Specifically, we need to update the `approvalTxnHash` and `spendTxnHash` functions to properly handle user approvals and spending operations. + +The `approvalTxnHash` function is responsible for calling the `approveWithSignature` method on the `Spend Permission Manager` contract. Update it with the following properties and values: + +```ts +const approvalTxnHash = await spenderBundlerClient.writeContract({ + address: spendPermissionManagerAddress, + abi: spendPermissionManagerAbi, + functionName: 'approveWithSignature', + args: [spendPermission, signature], +}); +``` + +Once the approval transaction completes, the app will have the user's permission to spend their funds. + +Next, we need to call the `spend` function to utilize the user's approved funds. Update the `spendTxnHash` function with the following code: + +```ts +const spendTxnHash = await spenderBundlerClient.writeContract({ + address: spendPermissionManagerAddress, + abi: spendPermissionManagerAbi, + functionName: 'spend', + args: [spendPermission, BigInt(1)], +}); +``` + +These updates ensure that the `/collect` route correctly processes both the approval and spending steps, enabling seamless interaction with the `Spend Permission Manager`. With these fixes in place, the backend can fully support the Spend Permission flow. + +Excellent! You just added a Spender Client as a backend app wallet. Now, when users click the `Subscribe` button, the component will call the `handleCollectSubscription` function, and the request will be handled by the `route` function. + +Go ahead and run your app locally to see your hard work come to life: + +```bash +bun run dev +``` + +### Obtaining Wallet Spend Permissions (Optional) + +I know what you're thinking: how can I see the valid (non-revoked) spend permissions for each user (wallet)? That's an easy one. Base provides an endpoint that allows you to retrieve valid spend permissions for an account by polling the utility API at: https://rpc.wallet.coinbase.com. + +An optional step you can take is to create a "My Subscriptions" tab on your site to present users with their valid spend permissions. Below is an example of the curl request to the RPC endpoint. A sample response can be found [here](https://gist.github.com/hughescoin/d1566557f85cb2fafd281833affbe022). + +```bash +curl --location 'https://rpc.wallet.coinbase.com' \ +--header 'Content-Type: application/json' \ +--data '{ + "jsonrpc": "2.0", + "method": "coinbase_fetchPermissions", + "params": [ + { + "account": "0xfB2adc8629FC9F54e243377ffcECEb437a42934C", + "chainId": "0x14A34", + "spender": "0x2a83b0e4462449660b6e7567b2c81ac6d04d877d" + } + ], + "id": 1 +}' +``` + +## Conclusion + +And there you have it - an onchain subscription application enabled by Spend Permissions. By combining Smart Wallets with scoped permissions, you’ve seen how we can streamline recurring payments, enable one-click purchases, and revolutionize how users interact with decentralized applications. + +Now, it’s your turn! The code and concepts we’ve explored today are just the beginning. Start experimenting, integrate Spend Permissions into your app, and redefine what’s possible with blockchain technology. + +We can’t wait to see what you’ll build. When you implement Spend Permissions, tag us on X/Farcaster [@Base](https://x.com/base) to share your creations. Let’s make 2025 the year of onchain apps—together! 🚀 + +--- + +[Paymaster]: https://portal.cdp.coinbase.com/products/bundler-and-paymaster +[Spender]: https://www.smartwallet.dev/guides/spend-permissions/api-reference/spendpermissionmanager#:~:text=spender,%27s%20tokens. +[Wallet Client]: https://viem.sh/docs/clients/wallet.html +[scopes]: https://www.smartwallet.dev/guides/spend-permissions/overview#the-spendpermission-details +[EIP-712]: https://eips.ethereum.org/EIPS/eip-712 diff --git a/apps/base-docs/tutorials/docs/1_verify-contract-with-basescan.md b/apps/base-docs/tutorials/docs/1_verify-contract-with-basescan.md index feb8a0d401..20fa09448f 100644 --- a/apps/base-docs/tutorials/docs/1_verify-contract-with-basescan.md +++ b/apps/base-docs/tutorials/docs/1_verify-contract-with-basescan.md @@ -88,13 +88,13 @@ Once you have the private key to the wallet of your choice, open your terminal a export PRIVATE_KEY="" ``` -To deploy our contract you will need a RPC URL to a Base node in order to broadcast our transactions to the network. [CDP] provides us with a free node for interacting with Base mainnet and testnet. +To deploy our contract you will need an RPC URL to a Base node in order to broadcast our transactions to the network. [CDP] provides us with a free node for interacting with Base mainnet and testnet. -Obtain a rpc url from the [Node product] and store the url as an environment variable similar to the private key in the previous step. +Obtain an rpc url from the [Node product] and store the url as an environment variable similar to the private key in the previous step. ![cdp-node](../../assets/images/verify-with-basescan-api/cdp-node-full.png) -Then store it as a environment variable in your terminal: +Then store it as an environment variable in your terminal: ```bash export BASE_RPC_URL="your_base_rpc_url" diff --git a/apps/base-docs/tutorials/docs/2_ock-fund-tutorial.md b/apps/base-docs/tutorials/docs/2_ock-fund-tutorial.md index 95b7814116..a098294ee5 100644 --- a/apps/base-docs/tutorials/docs/2_ock-fund-tutorial.md +++ b/apps/base-docs/tutorials/docs/2_ock-fund-tutorial.md @@ -1,7 +1,7 @@ --- title: 'Build a Smart Wallet Funding app with OnchainKit' slug: /build-smart-wallet-funding-app -description: Learn how to create a app that detects if a smart wallet has ETH and prompts users to add funds if needed. +description: Learn how to create an app that detects if a smart wallet has ETH and prompts users to add funds if needed. author: hughescoin keywords: [ Account Abstraction, @@ -29,9 +29,9 @@ In this tutorial, you'll learn how to build an onchain app that checks a user's By the end of this tutorial you should be able to: - Set up a project using the [OnchainKit App Template] -- Configure the app for to onboard users easily using [Smart Wallets] +- Configure the app to onboard users easily using [Smart Wallets] - Implement balance checking and conditional rendering -- Use the Fund component to allow users to add buy tokens from their wallet without leaving your app +- Use the Fund component to allow users to buy tokens from their wallet without leaving your app ## Prerequisites @@ -45,7 +45,7 @@ This tutorial uses Coinbase's OnchainKit. Familiarity with its basic concepts wi ### Access to the Coinbase Developer Platform -You'll need to set up an account on with [Coinbase Developer Platform (CDP) Account](https://www.coinbase.com/cloud). The CDP provides various tools and services for blockchain development, including access to API endpoints and other resources that will be instrumental in your project. Once you've created your account, you'll be ready to move forward with integrating these services into your application. +You'll need to set up an account with [Coinbase Developer Platform (CDP) Account](https://www.coinbase.com/cloud). The CDP provides various tools and services for blockchain development, including access to API endpoints and other resources that will be instrumental in your project. Once you've created your account, you'll be ready to move forward with integrating these services into your application. :::tip CDP Configurations @@ -85,7 +85,7 @@ coinbaseWallet.preference = 'smartWalletOnly'; ## Implementing Balance Checking -Now well implement a check on the user's wallet to see if they have enough funds. Before we implement this check, let's create a helper function that grabs the user's Ethereum balance using [viem]. To do so, create a `utils.ts` file in the `src` directory that creates a client connected to Base and fetches the user's ETH balance: +Now we'll implement a check on the user's wallet to see if they have enough funds. Before we implement this check, let's create a helper function that grabs the user's Ethereum balance using [viem]. To do so, create a `utils.ts` file in the `src` directory that creates a client connected to Base and fetches the user's ETH balance: ```typescript import { createPublicClient, http } from 'viem'; @@ -167,7 +167,7 @@ Sweet! Now our conditional rendering is in full force. If a user clicks on the ` ## Conclusion -Congratulations! You've built a app that checks a user's smart wallet balance and provides appropriate options based on their funds. +Congratulations! You've built an app that checks a user's smart wallet balance and provides appropriate options based on their funds. This app can serve as a foundation for more complex onchain applications that require users to have funded smart wallets. --- diff --git a/apps/base-docs/tutorials/docs/4_hardhat-test-coverage.md b/apps/base-docs/tutorials/docs/4_hardhat-test-coverage.md index 6740ba2e0a..f0fee67edd 100644 --- a/apps/base-docs/tutorials/docs/4_hardhat-test-coverage.md +++ b/apps/base-docs/tutorials/docs/4_hardhat-test-coverage.md @@ -154,7 +154,7 @@ describe("Lock Tests", function () { await expect(newInstanceUsingAnotherSigner.withdraw()).to.be.revertedWith("You aren't the owner") }) - it('should allow to withdraw a owner', async()=> { + it('should allow to withdraw an owner', async()=> { const balanceBefore = await ethers.provider.getBalance(await lockInstance.getAddress()); expect(balanceBefore).to.equal(VALUE_LOCKED) @@ -180,7 +180,7 @@ If you run `npx hardhat coverage`, you should get: ✔ should have the right owner ✔ shouldn't allow to withdraw before unlock time ✔ shouldn't allow to withdraw a non owner - ✔ should allow to withdraw a owner + ✔ should allow to withdraw an owner 6 passing (195ms) @@ -232,7 +232,7 @@ Then, run `npx hardhat coverage` and you should get: ✔ should have the right owner ✔ shouldn't allow to withdraw before unlock time ✔ shouldn't allow to withdraw a non owner - ✔ should allow to withdraw a owner + ✔ should allow to withdraw an owner 7 passing (198ms) diff --git a/apps/base-docs/tutorials/docs/5_basename-frames.md b/apps/base-docs/tutorials/docs/5_basename-frames.md index 122573225e..3add817334 100644 --- a/apps/base-docs/tutorials/docs/5_basename-frames.md +++ b/apps/base-docs/tutorials/docs/5_basename-frames.md @@ -50,7 +50,7 @@ To get started, head over to a Basename that you own. For example: Once you're on your profile, you’ll be greeted with a new banner inviting you to pin a frame to your profile. Look for the call-to-action button and click `Try it now`. -![try-now-buton](../../assets/images/basenames-tutorial/try-now.png) +![try-now-button](../../assets/images/basenames-tutorial/try-now.png) ## Explore the Frame Selection Panels diff --git a/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md b/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md index 2db0967210..1833d78cf6 100644 --- a/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md +++ b/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md @@ -215,12 +215,12 @@ The code snippet above defines a new smart contract named `ExampleContract` that The contract's constructor expects two arguments: -- `_endpoint`: The [LayerZero Endpoint](https://docs.layerzero.network/explore/layerzero-endpoint) `address` for the chain the smart contract is deployed to. +- `_endpoint`: The [LayerZero Endpoint](https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint) `address` for the chain the smart contract is deployed to. - `_owner`: The `address` of the owner of the smart contract. :::info -[LayerZero Endpoints](https://docs.layerzero.network/explore/layerzero-endpoint) are smart contracts that expose an interface for OApp contracts to manage security configurations and send and receive messages via the LayerZero protocol. +[LayerZero Endpoints](https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint) are smart contracts that expose an interface for OApp contracts to manage security configurations and send and receive messages via the LayerZero protocol. ::: @@ -251,9 +251,9 @@ The `sendMessage` function above calls the inherited `_lzSend` function, while p | Name | Type | Description | | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `_dstEid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/contracts/endpoint-addresses) of the destination chain to send the message to. | +| `_dstEid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) of the destination chain to send the message to. | | `_payload` | `bytes` | The message (encoded) to send. | -| `_options` | `bytes` | [Additional options](https://docs.layerzero.network/contracts/options) when sending the message, such as how much gas should be used when receiving the message. | +| `_options` | `bytes` | [Additional options](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options) when sending the message, such as how much gas should be used when receiving the message. | | `_fee` | [`MessagingFee`](https://github.com/LayerZero-Labs/LayerZero-v2/blob/c3213200dfe8fabbf7d92c685590d34e6e70da43/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol#L24) | The calculated fee for sending the message. | | `_refundAddress` | `address` | The `address` that will receive any excess fee values sent to the endpoint in case the `_lzSend` execution reverts. | @@ -289,9 +289,9 @@ The `estimateFee` function above calls the inherited `_quote` function, while pa | Name | Type | Description | | :-------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `_dstEid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/contracts/endpoint-addresses) of the destination chain the message will be sent to. | +| `_dstEid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) of the destination chain the message will be sent to. | | `_payload` | `bytes` | The message (encoded) that will be sent. | -| `_options` | `bytes` | [Additional options](https://docs.layerzero.network/contracts/options) when sending the message, such as how much gas should be used when receiving the message. | +| `_options` | `bytes` | [Additional options](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options) when sending the message, such as how much gas should be used when receiving the message. | | `_payInLzToken` | `bool` | Boolean flag for which token to use when returning the fee (native or ZRO token). | :::info @@ -468,7 +468,7 @@ cast wallet list ### Setting up environment variables -To setup your environment, create an `.env` file in the home directory of your project, and add the RPC URLs and [LayerZero Endpoint](https://docs.layerzero.network/contracts/endpoint-addresses) information for both Base Goerli and Optimism Goerli testnets: +To setup your environment, create an `.env` file in the home directory of your project, and add the RPC URLs and [LayerZero Endpoint](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) information for both Base Goerli and Optimism Goerli testnets: ```bash BASE_GOERLI_RPC="https://goerli.base.org" @@ -530,14 +530,14 @@ The `setPeer` function expects the following arguments: | Name | Type | Description | | :------ | :-------- | :------------------------------------------------------------------------------------------------------- | -| `_eid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/contracts/endpoint-addresses) of the destination chain. | +| `_eid` | `uint32` | The [endpoint ID](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) of the destination chain. | | `_peer` | `bytes32` | The contract address of the OApp contract on the destination chain. | ### Setting the peers Foundry provides the `cast` command-line tool that can be used to interact with deployed smart contracts and call their functions. -To set the peer of your `ExampleContract` contracts, you can use `cast` to call the `setPeer` function while providing the [endpoint ID](https://docs.layerzero.network/contracts/endpoint-addresses) and address (in bytes) of the deployed contract on the respective destination chain. +To set the peer of your `ExampleContract` contracts, you can use `cast` to call the `setPeer` function while providing the [endpoint ID](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) and address (in bytes) of the deployed contract on the respective destination chain. To set the peer of the Base Goerli contract to the Optimism Goerli contract, run the following command: @@ -571,17 +571,17 @@ Once peers have been set on each contract, they are now able to send and receive Sending a message using the newly created `ExampleContract` contract can be done in three steps: -1. Build [message options](https://docs.layerzero.network/contracts/options) to specify logic associated with the message transaction +1. Build [message options](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options) to specify logic associated with the message transaction 2. Call the `estimateFee` function to estimate the gas fee for sending a message 3. Call the `sendMessage` function to send a message ### Building message options -The `estimateFee` and `sendMessage` custom functions of the `ExampleContract` contract both require a [message options](https://docs.layerzero.network/contracts/options) (`_options`) argument to be provided. +The `estimateFee` and `sendMessage` custom functions of the `ExampleContract` contract both require a [message options](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options) (`_options`) argument to be provided. Message options allow you to specify arbitrary logic as part of the message transaction, such as the gas amount the [Executor](https://docs.layerzero.network/v2/home/permissionless-execution/executors) pays for message delivery, the order of message execution, or dropping an amount of gas to a destination address. -LayerZero provides a [Solidity](https://github.com/LayerZero-Labs/LayerZero-v2/blob/ccfd0d38f83ca8103b14ab9ca77f32e0419510ff/oapp/contracts/oapp/libs/OptionsBuilder.sol#L12) library and [TypeScript SDK](https://docs.layerzero.network/contracts/options) for building these message options. +LayerZero provides a [Solidity](https://github.com/LayerZero-Labs/LayerZero-v2/blob/ccfd0d38f83ca8103b14ab9ca77f32e0419510ff/oapp/contracts/oapp/libs/OptionsBuilder.sol#L12) library and [TypeScript SDK](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options) for building these message options. As an example, below is a Foundry script that uses OptionsBuilder from the Solidity library to generate message options (as `bytes`) that set the gas amount that the Executor will pay upon message delivery to `200000` wei: @@ -613,7 +613,7 @@ For this tutorial, rather than building and generating your own message options, :::info -Covering all of the different message options in detail is out of scope for this tutorial. If you are interested in learning more about the different message options and how to build them, visit the [LayerZero developer documentation](https://docs.layerzero.network/contracts/options). +Covering all of the different message options in detail is out of scope for this tutorial. If you are interested in learning more about the different message options and how to build them, visit the [LayerZero developer documentation](https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options). ::: diff --git a/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md b/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md index 7c09c0191b..acca97dea1 100644 --- a/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md +++ b/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md @@ -128,7 +128,7 @@ This will create a Foundry project, which has the following basic layout: Once your Foundry project has been created, you can now start writing a smart contract. -The Solidity code below defines a basic contract named `RNGContract`. The smart contract's constructor takes in a single `address` and assigns it to a member variable named `supraAddr`. This address corresponds to the [contract address](https://supraoracles.com/docs/vrf/networks/) of the Supra Router Contract that will be used to generate random numbers. The contract address of the Supra Router Contract on Base Sepolia testnet is `0x99a021029EBC90020B193e111Ae2726264a111A2`. +The Solidity code below defines a basic contract named `RNGContract`. The smart contract's constructor takes in a single `address` and assigns it to a member variable named `supraAddr`. This address corresponds to the [contract address](https://docs.supra.com/oracles/data-feeds/pull-oracle/networks) of the Supra Router Contract that will be used to generate random numbers. The contract address of the Supra Router Contract on Base Sepolia testnet is `0x99a021029EBC90020B193e111Ae2726264a111A2`. The contract also assigns the contract deployer (`msg.sender`) to a member variable named `supraClientAddress`. This should be the client wallet address that is registered and whitelisted to use Supra VRF (see: [Prerequisites](#prerequisites)). diff --git a/apps/bridge/next.config.js b/apps/bridge/next.config.js index 34e6986883..2b320c9270 100644 --- a/apps/bridge/next.config.js +++ b/apps/bridge/next.config.js @@ -36,7 +36,7 @@ const baseConfig = { // Enable strict mode in development reactStrictMode: !isProdEnv, - // Minifiy for production builds + // Minify for production builds swcMinify: true, }; diff --git a/apps/bridge/src/data/useWithdrawals.ts b/apps/bridge/src/data/useWithdrawals.ts index 6c4a36458b..74e6fce2ea 100644 --- a/apps/bridge/src/data/useWithdrawals.ts +++ b/apps/bridge/src/data/useWithdrawals.ts @@ -48,7 +48,7 @@ async function fetchOPWithdrawals(address: string) { async function fetchExplorerWithdrawals(address: string, isMainnet: boolean) { const response = await getJSON>( - // TODO: filter to transactions to the withdraw contract + // TODO: filter transactions to the withdraw contract publicRuntimeConfig.l2ExplorerApiURL, { address, diff --git a/apps/bridge/src/utils/transactions/isETHOrERC20Deposit.ts b/apps/bridge/src/utils/transactions/isETHOrERC20Deposit.ts index 4e915aad35..ce26878d8f 100644 --- a/apps/bridge/src/utils/transactions/isETHOrERC20Deposit.ts +++ b/apps/bridge/src/utils/transactions/isETHOrERC20Deposit.ts @@ -70,7 +70,7 @@ export function isETHOrERC20OrCCTPDeposit(tx: BlockExplorerTransaction) { return true; } - // ERC-20 desposit + // ERC-20 deposit if (tx.to === ERC20_DEPOSIT_ADDRESS) { const { functionName, args } = decodeFunctionData({ abi: l1StandardBridgeABI, diff --git a/apps/web/app/(basenames)/api/basenames/avatar/ipfsUpload/route.ts b/apps/web/app/(basenames)/api/basenames/avatar/ipfsUpload/route.ts index 68b4955057..d59ffe3564 100644 --- a/apps/web/app/(basenames)/api/basenames/avatar/ipfsUpload/route.ts +++ b/apps/web/app/(basenames)/api/basenames/avatar/ipfsUpload/route.ts @@ -14,7 +14,7 @@ export const MAX_IMAGE_SIZE_IN_MB = 1; // max 1mb export async function POST(request: NextRequest) { try { - // Rerrer validation + // Referer validation const requestUrl = new URL(request.url); // Username must be provided diff --git a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx index 073788206c..47b7500a2b 100644 --- a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx +++ b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx @@ -71,7 +71,7 @@ export default async function OpenGraphImage(props: ImageRouteProps) { const chain = getChainForBasename(username as Basename); let imageSource = domainName + profilePicture.src; - // NOTE: Do we want to fail if the name doesn't exists? + // NOTE: Do we want to fail if the name doesn't exist? try { const client = getBasenamePublicClient(chain.id); const avatar = await client.getEnsText({ @@ -80,20 +80,20 @@ export default async function OpenGraphImage(props: ImageRouteProps) { universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id], }); - if (!avatar) return; - - // IPFS Resolution - if (IsValidIpfsUrl(avatar)) { - const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl); - if (ipfsUrl) { - imageSource = ipfsUrl; + if (avatar) { + // IPFS Resolution + if (IsValidIpfsUrl(avatar)) { + const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl); + if (ipfsUrl) { + imageSource = ipfsUrl; + } + } else { + imageSource = avatar; } - } else { - imageSource = avatar; - } - // Cloudinary resize / fetch - imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 80 }); + // Cloudinary resize / fetch + imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 80 }); + } } catch (error) { logger.error('Error fetching basename Avatar:', error); } diff --git a/apps/web/app/AppProviders.tsx b/apps/web/app/AppProviders.tsx index b720ff7c13..5acb266694 100644 --- a/apps/web/app/AppProviders.tsx +++ b/apps/web/app/AppProviders.tsx @@ -29,7 +29,7 @@ type AppProvidersProps = { children: React.ReactNode; }; -// TODO: Not all pages needs all these components, ideally should be split and put +// TODO: Not all pages need all these components, ideally should be split and put // on the sub-layouts export default function AppProviders({ children }: AppProvidersProps) { const trackingPreference = useRef(); diff --git a/apps/web/app/api/cloudinaryUrl/route.ts b/apps/web/app/api/cloudinaryUrl/route.ts index cb0ea4f52a..24cdc46f14 100644 --- a/apps/web/app/api/cloudinaryUrl/route.ts +++ b/apps/web/app/api/cloudinaryUrl/route.ts @@ -66,7 +66,7 @@ async function getCloudinaryMediaUrl({ media, width, }: CloudinaryMediaUrlRequest): Promise { - // Asset idea based on URL + // Asset ID based on URL const assetId = generateAssetId(media); // Return the asset if already uploaded diff --git a/apps/web/contexts/Analytics.tsx b/apps/web/contexts/Analytics.tsx index d3e2bec679..be7df543f6 100644 --- a/apps/web/contexts/Analytics.tsx +++ b/apps/web/contexts/Analytics.tsx @@ -22,7 +22,7 @@ export const AnalyticsContext = createContext({ export function useAnalytics() { const context = useContext(AnalyticsContext); if (context === undefined) { - throw new Error('useAnalytics must be used within a AnalyticsProvider'); + throw new Error('useAnalytics must be used within an AnalyticsProvider'); } return context; } diff --git a/apps/web/global.d.ts b/apps/web/global.d.ts index 563fb102ad..d658225f7d 100644 --- a/apps/web/global.d.ts +++ b/apps/web/global.d.ts @@ -38,3 +38,8 @@ declare module '*.gltf' { const src: string; export default src; } + +declare module '*.mp4' { + const src: string; + export default src; +} diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 7dc6b6564b..0d55e99f8f 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -37,7 +37,7 @@ const baseConfig = { // Enable strict mode in development reactStrictMode: !isProdEnv, - // Minifiy for production builds + // Minify for production builds swcMinify: false, }; @@ -196,6 +196,19 @@ module.exports = extendBaseConfig( }, ], }); + config.module.rules.push({ + test: /\.mp4$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name][hash].[ext]', + outputPath: 'static/assets/mp4/', + publicPath: '/_next/static/assets/mp4/', + }, + }, + ], + }); config.module.rules.push({ test: /\.gltf/, use: [ diff --git a/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx b/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx index deabe8d199..d8ec858f71 100644 --- a/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx +++ b/apps/web/pages/api/basenames/[name]/assets/cardImage.svg.tsx @@ -55,25 +55,25 @@ export default async function handler(request: NextRequest) { universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id], }); - if (!avatar) return; - - // IPFS Resolution - if (IsValidIpfsUrl(avatar)) { - const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl); - if (ipfsUrl) { - imageSource = ipfsUrl; + if (avatar) { + // IPFS Resolution + if (avatar && IsValidIpfsUrl(avatar)) { + const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl); + if (ipfsUrl) { + imageSource = ipfsUrl; + } + } else if (avatar) { + imageSource = avatar; } - } else { - imageSource = avatar; - } - // Cloudinary resize / fetch - imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 120 }); + // Cloudinary resize / fetch + imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 120 }); + } } catch (error) { logger.error('Error fetching basename Avatar:', error); } - // Using Satori for a SVG response + // Using Satori for an SVG response const svg = await satori(
; /** the url of the homeframe, if null / undefined won't load a frame */ homeframeUrl: string | null | undefined; diff --git a/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.mp4 b/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.mp4 new file mode 100644 index 0000000000..615a4dc46b Binary files /dev/null and b/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.mp4 differ diff --git a/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.webm b/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.webm deleted file mode 100644 index 0939512f8d..0000000000 Binary files a/apps/web/src/components/base-org/root/BuildAndRewardSection/assets/cubes.webm and /dev/null differ diff --git a/apps/web/src/components/base-org/root/BuildAndRewardSection/index.tsx b/apps/web/src/components/base-org/root/BuildAndRewardSection/index.tsx index a5337fb65d..306fdc66f2 100644 --- a/apps/web/src/components/base-org/root/BuildAndRewardSection/index.tsx +++ b/apps/web/src/components/base-org/root/BuildAndRewardSection/index.tsx @@ -2,12 +2,11 @@ import { useErrors } from 'apps/web/contexts/Errors'; import Title from 'apps/web/src/components/base-org/typography/Title'; import { TitleLevel } from 'apps/web/src/components/base-org/typography/Title/types'; - import Text from 'apps/web/src/components/base-org/typography/Text'; import Button from 'apps/web/src/components/base-org/Button'; import { ButtonVariants } from 'apps/web/src/components/base-org/Button/types'; import { useCallback, useRef } from 'react'; -import cubes from './assets/cubes.webm'; +import cubes from './assets/cubes.mp4'; import Link from 'apps/web/src/components/Link'; export default function BuildAndRewardSection() { @@ -26,7 +25,7 @@ export default function BuildAndRewardSection() {