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/.github/ISSUE_TEMPLATE/docs_request.yml b/.github/ISSUE_TEMPLATE/docs_request.yml index c2fc35229c..2f36b47d88 100644 --- a/.github/ISSUE_TEMPLATE/docs_request.yml +++ b/.github/ISSUE_TEMPLATE/docs_request.yml @@ -30,4 +30,4 @@ body: id: other attributes: label: Additional context - description: Add any other context or screenshots about the concern can be added here. + description: Add any additional context or screenshots about the concern here. diff --git a/.github/workflows/file-size-checker.yml b/.github/workflows/file-size-checker.yml new file mode 100644 index 0000000000..71a0968c1c --- /dev/null +++ b/.github/workflows/file-size-checker.yml @@ -0,0 +1,107 @@ +name: File Size Checker + +# Add required permissions +permissions: + contents: read + pull-requests: write + statuses: write + +on: + pull_request: + types: [opened, synchronize] + +jobs: + check-file-sizes: + name: File Size Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check file sizes + id: check-sizes + run: | + # Initialize variables for tracking findings + large_files="" + huge_files="" + + # Get all files in the PR + echo "Files changed in PR:" + git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} + + for file in $(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}); do + if [ -f "$file" ]; then + size=$(stat -c%s "$file") + size_mb=$(echo "scale=2; $size/1048576" | bc) + + echo "Checking $file: ${size_mb}MB" + + # Check for files over 40MB + if (( $(echo "$size_mb > 40" | bc -l) )); then + huge_files="${huge_files}* ${file} (${size_mb}MB)\n" + # Check for files over 10MB + elif (( $(echo "$size_mb > 10" | bc -l) )); then + large_files="${large_files}* ${file} (${size_mb}MB)\n" + fi + fi + done + + # Print findings for debugging + echo "Large files found:" + echo -e "$large_files" + echo "Huge files found:" + echo -e "$huge_files" + + # Set outputs for use in next steps + echo "large_files<> $GITHUB_OUTPUT + echo -e "$large_files" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + echo "huge_files<> $GITHUB_OUTPUT + echo -e "$huge_files" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Fail if huge files are found + if [ ! -z "$huge_files" ]; then + echo "❌ Files over 40MB found!" + exit 1 + fi + + - name: Update Status and Comment + if: always() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const hugeFiles = `${{ steps.check-sizes.outputs.huge_files }}`; + const largeFiles = `${{ steps.check-sizes.outputs.large_files }}`; + + try { + // Only comment if issues were found + if (hugeFiles || largeFiles) { + let comment = '## ⚠️ File Size Check Results\n\n'; + + if (hugeFiles) { + comment += '### 🚫 Files over 40MB (Not Allowed):\n' + hugeFiles + '\n'; + comment += '**These files must be removed from git history before the PR can be merged.**\n\n'; + } + + if (largeFiles) { + comment += '### ⚠️ Large Files (Over 10MB):\n' + largeFiles + '\n'; + comment += 'Consider reducing the size of these files if possible.\n'; + } + + await github.rest.issues.createComment({ + issue_number: context.payload.pull_request.number, + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + body: comment + }); + } + } catch (error) { + console.error('Error:', error); + core.setFailed(error.message); + } 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 ea70eb1c9d..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, @@ -15,8 +15,15 @@ "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - - // ESLint + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "editor.codeActionsOnSave": ["source.fixAll.eslint"], "eslint.packageManager": "yarn", "eslint.useESLintClass": true, 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/README.md b/README.md index b82b6dd746..aa06b1f34c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Base is a secure, low-cost, developer-friendly Ethereum L2 built to bring the ne ## Setup -1. Ensure `nvm` is [installed](https://github.com/nvm-sh/nvm#install--update-script). +1. Ensure that `nvm` is [installed](https://github.com/nvm-sh/nvm#install--update-script). 2. Clone the repository. 3. If `nvm` doesn't auto-load the Node.js environment when changing to the repo directory, run `nvm use`. 4. Enable Yarn by running `corepack enable`. @@ -71,7 +71,7 @@ yarn workspace @app/bridge dev ## Contributing -We welcome contributions to Base! To contribute, please see [CONTRIBUTING.md](CONTRIBUTING.md). +We welcome contributions to Base! For guidelines on how to contribute please refer to [CONTRIBUTING.md](CONTRIBUTING.md). ### Updating the Base Ecosystem Page @@ -81,38 +81,47 @@ If you're a builder who wants to add or update your project on the [Base Ecosyst 2. Create a new branch for your changes. -3. Update the `web/apps/web/src/data/ecosystem.json` with your project information. All fields are required. Each entry should follow this format: +3. Update the `web/apps/web/src/data/ecosystem.json` with your project information. All fields are required. Each entry should follow the format below: ```json { "name": "Your Project Name", - "tags": ["category"], "description": "A brief description of your project (less than 200 characters)", "url": "https://your-project-url.com", - "imageUrl": "/images/partners/your-project-logo.png" + "imageUrl": "/images/partners/your-project-logo.png", + "category": "Your Project Category", + "subcategory": "Your Project Subcategory" } ``` - name: Your project's name - - tags: An array with _one_ of the following categories: `bridge`, `dao`, `defi`, `gaming`, `infra`, `nft`, `onramp`, `social`, `wallet`, `security` - description: A brief description of your project, must be less than 200 characters - url: Your project's website URL - imageUrl: Path to your project's logo image + - category: Your project's category, _one_ of: `consumer`, `defi`, `infra`, `onramp`, `wallet` + - subcategory: Your project's subcategory, with the following options associated with each category + - `consumer`: _One_ of `creator`, `crypto taxes`, `dao`, `gaming`, `messaging`, `music`, `nft`, `payments`, `real world`, `social` + - `defi`: _One_ of `dex`, `dex aggregator`, `insurance`, `lending/borrowing`, `liquidity management`, `portfolio`, `stablecoin`, `yield vault` + - `infra`: _One_ of `ai`, `bridge`, `data`, `depin`, `developer tool`, `identity`, `node provider`, `raas`, `security` + - `onramp`: _One_ of `centralized exchange`, `fiat on-ramp` + - `wallet`: _One_ of `account abstraction`, `multisig`, `self-custody` 4. When adding and/or updating a logo, place a 192x192 pixel PNG file in the `web/apps/web/public/images/partners/`. The file should be named appropriately (e.g., your-project-name.png). The logo should be an App Store or Play Store iconographic version, not a full wordmark. 5. Create a pull request with your changes. -By opening a PR to add your project, you authorize and license to Coinbase on a non-exclusive, worldwide, irrevocable, sublicensable, and royalty free basis to reproduce, distribute, transmit, make available, perform, display, or otherwise use the submitted Multimedia Assets for any purpose, including any marketing or promotional activities related to Base or Coinbase. Any goodwill associated with use of trademarks submitted in your Multimedia Assets will inure to your benefit. You further acknowledge and represent that you have all IP rights in the Multimedia Assets, that the Multimedia Assets do not infringe the rights of any third party, and that you have the right to grant this license to Coinbase. +By opening a PR to add your project, you authorize and license Coinbase on a non-exclusive, worldwide, irrevocable, sublicensable, and royalty-free basis to reproduce, distribute, transmit, make available, perform, display, or otherwise use the submitted Multimedia Assets for any purpose, including any marketing or promotional activities related to Base or Coinbase. Any goodwill associated with use of trademarks submitted in your Multimedia Assets will inure to your benefit. You further acknowledge and represent that you have all IP rights in the Multimedia Assets, that the Multimedia Assets do not infringe the rights of any third party, and that you have the right to grant this license to Coinbase. **Note:** Submissions do not guarantee inclusion and all submissions are subject to review. Your project must be live on Base to potentially be included. Ensure all information is accurate and up-to-date. -#### Tips for a successful submission +#### Submission requirements +- App content adheres to the [Base Editorial Style Guide](https://github.com/base-org/brand-kit/blob/main/guides/editorial-style-guide.md) - App has been live on Base for at least 30 days - App has a Terms of Service and Privacy Policy - App supports HTTPS and 301 redirects HTTP requests -- App is not a TGE, ICO, airdrop, claim, or similar +- App is not a TGE (Token Generation Event), ICO (Initial Coin Offering), airdrop, claim, or similar +- Landing page is a Base-specific page for users who will becoming from base.org - Active development and community engagement can be observed without issue --- diff --git a/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-before.png b/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-before.png new file mode 100644 index 0000000000..39599d6680 Binary files /dev/null and b/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-before.png differ diff --git a/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-final.png b/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-final.png new file mode 100644 index 0000000000..e38455e417 Binary files /dev/null and b/apps/base-docs/assets/images/onchainkit-tutorials/swapped-theme-final.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/basescan-token-transfer.png b/apps/base-docs/assets/images/paymaster-tutorials/basescan-token-transfer.png new file mode 100644 index 0000000000..a62d847676 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/basescan-token-transfer.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/cdp-copy-endpoint.png b/apps/base-docs/assets/images/paymaster-tutorials/cdp-copy-endpoint.png new file mode 100644 index 0000000000..8b43831675 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/cdp-copy-endpoint.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/cdp-paymaster-config.png b/apps/base-docs/assets/images/paymaster-tutorials/cdp-paymaster-config.png new file mode 100644 index 0000000000..8739aacf28 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/cdp-paymaster-config.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/cdp-policy-settings.png b/apps/base-docs/assets/images/paymaster-tutorials/cdp-policy-settings.png new file mode 100644 index 0000000000..478dc94280 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/cdp-policy-settings.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/connect-wallet-mint-page.png b/apps/base-docs/assets/images/paymaster-tutorials/connect-wallet-mint-page.png new file mode 100644 index 0000000000..f2d43727d5 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/connect-wallet-mint-page.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/mint-cbbtc.png b/apps/base-docs/assets/images/paymaster-tutorials/mint-cbbtc.png new file mode 100644 index 0000000000..c85da3f5e0 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/mint-cbbtc.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/sponsored_mint_nft.png b/apps/base-docs/assets/images/paymaster-tutorials/sponsored_mint_nft.png new file mode 100644 index 0000000000..e678f5d7db Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/sponsored_mint_nft.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/wallet-home.png b/apps/base-docs/assets/images/paymaster-tutorials/wallet-home.png new file mode 100644 index 0000000000..8edda0d142 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/wallet-home.png differ diff --git a/apps/base-docs/assets/images/paymaster-tutorials/wallet-nft-page.png b/apps/base-docs/assets/images/paymaster-tutorials/wallet-nft-page.png new file mode 100644 index 0000000000..1e05dfc452 Binary files /dev/null and b/apps/base-docs/assets/images/paymaster-tutorials/wallet-nft-page.png differ diff --git a/apps/base-docs/base-learn/docs/advanced-functions/function-modifiers.md b/apps/base-docs/base-learn/docs/advanced-functions/function-modifiers.md index 8eb0565025..38e1f60bbd 100644 --- a/apps/base-docs/base-learn/docs/advanced-functions/function-modifiers.md +++ b/apps/base-docs/base-learn/docs/advanced-functions/function-modifiers.md @@ -20,7 +20,7 @@ By the end of this lesson you should be able to: By default, `public` functions can be called by **anyone**, without restriction. Often this is desirable. You want any user to be able to see what NFTs are for sale on your platform, sign up for a service, or read various items stored in state. -However, there will be many functions you **don't** want any user to be able to do, such as setting the fee for using the app, or withdrawing all of the funds in the contract! A common pattern to protect these functions is to use `modifier`s to make sure that only the owner can call these functions. +However, there will be many functions you **don't** want any user to be able to do, such as setting the fee for using the app, or withdrawing all funds in the contract! A common pattern to protect these functions is to use `modifier`s to make sure that only the owner can call these functions. :::caution diff --git a/apps/base-docs/base-learn/docs/arrays/arrays-exercise.md b/apps/base-docs/base-learn/docs/arrays/arrays-exercise.md index eefecff938..dbb3e6016a 100644 --- a/apps/base-docs/base-learn/docs/arrays/arrays-exercise.md +++ b/apps/base-docs/base-learn/docs/arrays/arrays-exercise.md @@ -50,7 +50,7 @@ Write a function called `appendToNumbers` that takes a `uint[] calldata` array c At the contract level, add an `address` array called `senders` and a `uint` array called `timestamps`. -Write a function called `saveTimestamp` that takes a `uint` called `_unixTimestamp` as an argument. When called, it should add the address of the caller to the end of `senders` and the `_unixTimeStamp` to `timestamps`. +Write a function called `saveTimestamp` that takes a `uint` called `_unixTimestamp` as an argument. When called, it should add the address of the caller to the end of `senders` and the `_unixTimestamp` to `timestamps`. :::tip diff --git a/apps/base-docs/base-learn/docs/arrays/arrays-in-solidity.md b/apps/base-docs/base-learn/docs/arrays/arrays-in-solidity.md index b01053975b..6e0b661200 100644 --- a/apps/base-docs/base-learn/docs/arrays/arrays-in-solidity.md +++ b/apps/base-docs/base-learn/docs/arrays/arrays-in-solidity.md @@ -69,7 +69,7 @@ contract StorageArray { You cannot use a `storage` array as a function parameter, and you cannot write a function that `return`s a `storage` array. -Storage arrays are dynamic, unless they are declared with an explicit size. However, their functionality is limited compared to other languages. The `.push(value)` function works as expected. the `.pop()` function removes the last value of an array, but it **does not** return that value. You also **may not** use `.pop()` with an index to remove an element from the middle of an array, or to remove more than one element. +Storage arrays are dynamic, unless they are declared with an explicit size. However, their functionality is limited compared to other languages. The `.push(value)` function works as expected. The `.pop()` function removes the last value of an array, but it **does not** return that value. You also **may not** use `.pop()` with an index to remove an element from the middle of an array, or to remove more than one element. You can use the `delete` keyword with an array. Doing so on an entire array will reset the array to zero length. Calling it on an element within the array will reset that value to its default. It **will not** resize the array! diff --git a/apps/base-docs/base-learn/docs/arrays/filtering-an-array-sbs.md b/apps/base-docs/base-learn/docs/arrays/filtering-an-array-sbs.md index 84f611fafb..7151aba48c 100644 --- a/apps/base-docs/base-learn/docs/arrays/filtering-an-array-sbs.md +++ b/apps/base-docs/base-learn/docs/arrays/filtering-an-array-sbs.md @@ -47,7 +47,7 @@ The simple and obvious solution is to simply iterate through `numbers` and count Go ahead and write it on your own. It needs to: - Instantiate a `uint` to hold the results -- Iterate through all of the values in `numbers` and increment that number if the value is even +- Iterate through all values in `numbers` and increment that number if the value is even - Return the result You should end up with something like: @@ -170,7 +170,7 @@ uint[] public numbers; uint numEven; ``` -Add a new function called `debugLoadArray` that takes a `uint` called `_number` as an argument, and fills the array by looping through `_numbers` times, pushing each number into the array. **For now, _don't_ update `numEven`**. +Add a new function called `debugLoadArray` that takes a `uint` called `_number` as an argument, and fills the array by looping through `_number` times, pushing each number into the array. **For now, _don't_ update `numEven`**.
diff --git a/apps/base-docs/base-learn/docs/contracts-and-basic-functions/basic-functions-exercise.md b/apps/base-docs/base-learn/docs/contracts-and-basic-functions/basic-functions-exercise.md index 57b7b80958..be026d9e4c 100644 --- a/apps/base-docs/base-learn/docs/contracts-and-basic-functions/basic-functions-exercise.md +++ b/apps/base-docs/base-learn/docs/contracts-and-basic-functions/basic-functions-exercise.md @@ -26,8 +26,8 @@ A function called `adder`. It must: - Accept two `uint` arguments, called `_a` and `_b` - Return a `uint` `sum` and a `bool` `error` -- If `_a` + `_b` do not overflow, it should return the `sum` and an `error` of `false` -- If `_a` + `_b` overflow, it should return `0` as the `sum`, and an `error` of `true` +- If `_a` + `_b` does not overflow, it should return the `sum` and an `error` of `false` +- If `_a` + `_b` overflows, it should return `0` as the `sum`, and an `error` of `true` ### Subtractor diff --git a/apps/base-docs/base-learn/docs/contracts-and-basic-functions/hello-world-step-by-step.md b/apps/base-docs/base-learn/docs/contracts-and-basic-functions/hello-world-step-by-step.md index 04929a660e..3c2c535d6b 100644 --- a/apps/base-docs/base-learn/docs/contracts-and-basic-functions/hello-world-step-by-step.md +++ b/apps/base-docs/base-learn/docs/contracts-and-basic-functions/hello-world-step-by-step.md @@ -77,7 +77,7 @@ Is `public` the most appropriate [visibility specifier]? It would work, but you won't be calling this function from within the contract, so `external` is more appropriate. -You also need to specify a return type, and we've decided this function should return a string. You'll learn more about this later, but in Solidity, many of the more complex types require you to specify if they are `storage` or `memory`. You can then have your function return a string of `"Hello World!`. +You also need to specify a return type, and we've decided this function should return a string. You'll learn more about this later, but in Solidity, many of the more complex types require you to specify if they are `storage` or `memory`. You can then have your function return a string of `"Hello World!"`. Don't forget your semicolon. They're mandatory in Solidity! @@ -136,7 +136,7 @@ function Greeter(string memory _name) external pure returns (string memory) { Unfortunately, this does not work in Solidity. The error message you receive is a little confusing: -> TypeError: Operator + not compatible with types literal_string "Hello " and string memory. +> TypeError: Operator + not compatible with types literal_string "Hello" and string memory. You might think that there is some sort of type casting or conversion error that could be solved by explicitly casting the string literal to string memory, or vice versa. This is a great instinct. Solidity is a very explicit language. diff --git a/apps/base-docs/base-learn/docs/deployment-to-testnet/contract-verification-sbs.md b/apps/base-docs/base-learn/docs/deployment-to-testnet/contract-verification-sbs.md index 41e84cc731..60e03e65d4 100644 --- a/apps/base-docs/base-learn/docs/deployment-to-testnet/contract-verification-sbs.md +++ b/apps/base-docs/base-learn/docs/deployment-to-testnet/contract-verification-sbs.md @@ -4,7 +4,7 @@ description: Verify your contract and interact with it. hide_table_of_contents: false --- -Once your contract is deployed, you can verify it using a number of popular services. Doing so will let you users have confidence that your contract does what you claim, and will allow you to interact with it using a similar interface to what you used in Remix. +Once your contract is deployed, you can verify it using a number of popular services. Doing so will let your users have confidence that your contract does what you claim, and will allow you to interact with it using a similar interface to what you used in Remix. --- @@ -46,7 +46,7 @@ Click the linked address to your contract to return to the contract page. You'll :::tip -If you have imports, you'll need to right click on the name of the file and choose `Flatten`. Submit the newly generated `filename_flattened.sol` for verification. +If you have imports, you'll need to right-click on the name of the file and choose `Flatten`. Submit the newly generated `filename_flattened.sol` for verification. ::: @@ -69,7 +69,7 @@ With your contracts verified, you can interact with them using online tools and [`sepolia.basescan.org`]: https://sepolia.basescan.org/ [coinbase]: https://www.coinbase.com/wallet [faucet]: https://docs.base.org/tools/network-faucets -[set up]: https://www.youtube.com/watch?v=CZDgLG6jpgw +[set up]: [coinbase settings]: https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings [BaseScan]: https://sepolia.basescan.org/ [faucets on the web]: https://coinbase.com/faucets diff --git a/apps/base-docs/base-learn/docs/deployment-to-testnet/deployment-to-base-sepolia-sbs.md b/apps/base-docs/base-learn/docs/deployment-to-testnet/deployment-to-base-sepolia-sbs.md index 42dd83791b..1c6d7183d9 100644 --- a/apps/base-docs/base-learn/docs/deployment-to-testnet/deployment-to-base-sepolia-sbs.md +++ b/apps/base-docs/base-learn/docs/deployment-to-testnet/deployment-to-base-sepolia-sbs.md @@ -102,7 +102,7 @@ You now have the power to put smart contracts on the blockchain! You've only dep [coinbase]: https://www.coinbase.com/wallet [metamask]: https://metamask.io/ [faucet]: https://docs.base.org/tools/network-faucets -[set up]: https://www.youtube.com/watch?v=CZDgLG6jpgw +[set up]: [coinbase settings]: https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings [Metamask Settings]: https://support.metamask.io/hc/en-us/articles/13946422437147-How-to-view-testnets-in-MetaMask [BaseScan]: https://sepolia.basescan.org/ diff --git a/apps/base-docs/base-learn/docs/erc-20-token/erc-20-token-sbs.md b/apps/base-docs/base-learn/docs/erc-20-token/erc-20-token-sbs.md index cca565b3c8..73f0364dcf 100644 --- a/apps/base-docs/base-learn/docs/erc-20-token/erc-20-token-sbs.md +++ b/apps/base-docs/base-learn/docs/erc-20-token/erc-20-token-sbs.md @@ -12,8 +12,8 @@ The ERC-20 is a standard that allows for the development of fungible tokens and By the end of this lesson you should be able to: -- Describe OpenZepplin -- Import the OpenZepplin ERC-20 implementation +- Describe OpenZeppelin +- Import the OpenZeppelin ERC-20 implementation - Describe the difference between the ERC-20 standard and OpenZeppelin's ERC20.sol - Build and deploy an ERC-20 compliant token diff --git a/apps/base-docs/base-learn/docs/error-triage/error-triage.md b/apps/base-docs/base-learn/docs/error-triage/error-triage.md index 1234fb638b..d50e34bcfe 100644 --- a/apps/base-docs/base-learn/docs/error-triage/error-triage.md +++ b/apps/base-docs/base-learn/docs/error-triage/error-triage.md @@ -406,7 +406,7 @@ function badRandomLoopFixed() public view returns (uint) { The `uint` type will _panic_ in the event of an overflow or underflow. ```solidity -function badSubstraction() public pure returns (uint) { +function badSubtraction() public pure returns (uint) { uint first = 1; uint second = 2; return first - second; 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/hardhat-deploy/hardhat-deploy-sbs.md b/apps/base-docs/base-learn/docs/hardhat-deploy/hardhat-deploy-sbs.md index bae9771ff1..c37b2f0611 100644 --- a/apps/base-docs/base-learn/docs/hardhat-deploy/hardhat-deploy-sbs.md +++ b/apps/base-docs/base-learn/docs/hardhat-deploy/hardhat-deploy-sbs.md @@ -159,9 +159,9 @@ Reuse `Lock__factory` but use the connect function and pass the address of the n ✔ should get the unlockTime value ✔ should have the right ether balance ✔ should have the right owner - ✔ shouldn"t allow to withdraw before unlock time (51ms) - ✔ shouldn"t allow to withdraw a non owner - ✔ should allow to withdraw a owner + ✔ shouldn't allow to withdraw before unlock time (51ms) + ✔ shouldn't allow to withdraw a non owner + ✔ should allow to withdraw an owner 6 passing (2s) ``` @@ -170,7 +170,7 @@ Reuse `Lock__factory` but use the connect function and pass the address of the n Deploying to a real test network involves configuring the network parameters in the hardhat config file. You need to include parameters such as: -- The JSON RPC url +- The JSON RPC URL - The account you want to use - Real test ether or the native Blockchain token for gas costs diff --git a/apps/base-docs/base-learn/docs/hardhat-testing/hardhat-testing-sbs.md b/apps/base-docs/base-learn/docs/hardhat-testing/hardhat-testing-sbs.md index 00f0b9f8ca..5e61bc4233 100644 --- a/apps/base-docs/base-learn/docs/hardhat-testing/hardhat-testing-sbs.md +++ b/apps/base-docs/base-learn/docs/hardhat-testing/hardhat-testing-sbs.md @@ -287,7 +287,7 @@ Finally, test that the owner can withdraw. You can manipulate the time similarly Reveal code ```tsx -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()); // Its value will be the one we lock at deployment time. @@ -320,7 +320,7 @@ You can then run `npx hardhat test` and you should get: ✔ should have the right owner ✔ shouldn"t allow to withdraw before unlock time (51ms) ✔ shouldn"t allow to withdraw a non owner - ✔ should allow to withdraw a owner + ✔ should allow to withdraw an owner 6 passing (2s) ``` diff --git a/apps/base-docs/base-learn/docs/imports/imports-sbs.md b/apps/base-docs/base-learn/docs/imports/imports-sbs.md index bd21b47fb0..83e5aba229 100644 --- a/apps/base-docs/base-learn/docs/imports/imports-sbs.md +++ b/apps/base-docs/base-learn/docs/imports/imports-sbs.md @@ -27,11 +27,11 @@ The [docs] start with installation instructions, which we'll return to when we s Find the documentation for the `EnumerableSet` under _Utils_. This library will allow you to create [sets] of `bytes32`, `address`, and `uint256`. Since they're enumerated, you can iterate through them. Neat! -### Implementing the OpenZeppelin EnumeratedSet +### Implementing the OpenZeppelin EnumerableSet Create a new file to work in and add the `pragma` and license identifier. -In Remix, you can import libraries directly from Github! +In Remix, you can import libraries directly from GitHub! ```solidity import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol"; 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/introduction-to-solidity/deployment-in-remix.md b/apps/base-docs/base-learn/docs/introduction-to-solidity/deployment-in-remix.md index 3e9a8ec59d..86f5d148f2 100644 --- a/apps/base-docs/base-learn/docs/introduction-to-solidity/deployment-in-remix.md +++ b/apps/base-docs/base-learn/docs/introduction-to-solidity/deployment-in-remix.md @@ -50,7 +50,7 @@ Click the chevron to expand your contract in the Deployed Contracts section of t ![Function Buttons](../../assets/images/introduction-to-solidity/remix-contract-buttons.png) -Let's click the retrieve button first. Before clicking, make a prediction: given that the `number` variable was instantiated without a value, what do you thing the return will be? +Let's click the retrieve button first. Before clicking, make a prediction: given that the `number` variable was instantiated without a value, what do you think the return will be? Go ahead and click – the result will appear below the button as: diff --git a/apps/base-docs/base-learn/docs/introduction-to-solidity/introduction-to-remix.md b/apps/base-docs/base-learn/docs/introduction-to-solidity/introduction-to-remix.md index 10498ec33f..fd9139d7a4 100644 --- a/apps/base-docs/base-learn/docs/introduction-to-solidity/introduction-to-remix.md +++ b/apps/base-docs/base-learn/docs/introduction-to-solidity/introduction-to-remix.md @@ -33,7 +33,7 @@ The editor pane loads with the Remix home screen, which contains news, helpful l ![Remix Editor](../../assets/images/introduction-to-solidity/editor-pane.png) -You'll edit your code in the editor pane. It also has most of the features you're expecting, such as syntax and error highlighting. Note that in Remix, errors are not underlines. Instead, you'll see an❗to the left of the line number where the error is present. +You'll edit your code in the editor pane. It also has most of the features you're expecting, such as syntax and error highlighting. Note that in Remix, errors are not underlined. Instead, you'll see an❗to the left of the line number where the error is present. At the top, you'll see a large green arrow similar to the _Run_ button in other editors. In Solidity, this compiles your code, but it does not run it because you must first deploy your code to the simulated blockchain. diff --git a/apps/base-docs/base-learn/docs/learning-objectives.md b/apps/base-docs/base-learn/docs/learning-objectives.md index d71e3573a4..3e60d19674 100644 --- a/apps/base-docs/base-learn/docs/learning-objectives.md +++ b/apps/base-docs/base-learn/docs/learning-objectives.md @@ -194,8 +194,8 @@ Use the script to regenerate this file. ### [ERC-20 Implementation](./erc-20-token/erc-20-token-sbs.md) -- Describe OpenZepplin -- Import the OpenZepplin ERC-20 implementation +- Describe OpenZeppelin +- Import the OpenZeppelin ERC-20 implementation - Describe the difference between the ERC-20 standard and OpenZeppelin's ERC20.sol - Build and deploy an ERC-20 compliant token @@ -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) @@ -255,4 +255,4 @@ Use the script to regenerate this file. - Implement wagmi's `useSimulateContract` and `useWriteContract` to send transactions to a smart contract - Configure the options in `useSimulateContract` and `useWriteContract` -- Call a smart contract function on-demand using the write function from `useWriteContract`, with arguments and a value \ No newline at end of file +- Call a smart contract function on-demand using the write function from `useWriteContract`, with arguments and a value diff --git a/apps/base-docs/base-learn/docs/mappings/mappings-sbs.md b/apps/base-docs/base-learn/docs/mappings/mappings-sbs.md index 4e1ad136a3..72472c83ef 100644 --- a/apps/base-docs/base-learn/docs/mappings/mappings-sbs.md +++ b/apps/base-docs/base-learn/docs/mappings/mappings-sbs.md @@ -118,7 +118,7 @@ Deploy and test again. Success! One challenging limitation of the `mapping` data type is that it is **not** iterable - you cannot loop through and manipulate or return **all** values in the `mapping`. -At least not with any built in features, but you can solve this on your own. A common practice in Solidity with this and similar problems is to use multiple variables or data types to store the right combination needed to address the issue. +At least not with any built-in features, but you can solve this on your own. A common practice in Solidity with this and similar problems is to use multiple variables or data types to store the right combination needed to address the issue. ### Using a Helper Array 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/reading-and-displaying-data/useReadContract.md b/apps/base-docs/base-learn/docs/reading-and-displaying-data/useReadContract.md index 9630ba46e9..1431d4beaf 100644 --- a/apps/base-docs/base-learn/docs/reading-and-displaying-data/useReadContract.md +++ b/apps/base-docs/base-learn/docs/reading-and-displaying-data/useReadContract.md @@ -58,19 +58,19 @@ Add the following two issues: ```text _issueDesc: We should enable light mode by default. -_quorom: 2 +_quorum: 2 ``` ```text _issueDesc: We should make inverted mouse controls the default selection. -_quorom: 2 +_quorum: 2 ``` Switch to a **different wallet address**. Claim your tokens with the new address, and add one more issue: ```text _issueDesc: Two spaces, not four, not tabs! -_quorom: 2 +_quorum: 2 ``` Call the `getAllIssues` function under the `Read Contract` tab to make sure all three are there. 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 8ea9451e62..bea6deeba4 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 @@ -4,7 +4,7 @@ description: Learn how to Store data on the blockchain. hide_table_of_contents: false --- -Ultimately, the power of the blockchain is that anyone can store their data on it via the `storage` in a smart contract. In this step by step guide, you'll learn how to access and use the `storage` data location. +Ultimately, the power of the blockchain is that anyone can store their data on it via the `storage` in a smart contract. In this step-by-step guide, you'll learn how to access and use the `storage` data location. --- @@ -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 simply 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 5773756324..8e2803380a 100644 --- a/apps/base-docs/docs/building-with-base/base-contracts.md +++ b/apps/base-docs/docs/building-with-base/base-contracts.md @@ -73,12 +73,20 @@ hide_table_of_contents: true | Name | Address | | :--------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | AddressManager | [0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2](https://etherscan.io/address/0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2) | +| AnchorStateRegistryProxy | [0xdB9091e48B1C42992A1213e6916184f9eBDbfEDf](https://etherscan.io/address/0xdB9091e48B1C42992A1213e6916184f9eBDbfEDf) | +| DelayedWETHProxy (FDG) | [0xa2f2aC6F5aF72e494A227d79Db20473Cf7A1FFE8](https://etherscan.io/address/0xa2f2aC6F5aF72e494A227d79Db20473Cf7A1FFE8) | +| DelayedWETHProxy (PDG) | [0x3E8a0B63f57e975c268d610ece93da5f78c01321](https://etherscan.io/address/0x3E8a0B63f57e975c268d610ece93da5f78c01321) | +| DisputeGameFactoryProxy | [0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e](https://etherscan.io/address/0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e) | +| FaultDisputeGame | [0xCd3c0194db74C23807D4B90A5181e1B28cF7007C](https://etherscan.io/address/0xCd3c0194db74C23807D4B90A5181e1B28cF7007C) | | L1CrossDomainMessenger | [0x866E82a600A1414e583f7F13623F1aC5d58b0Afa](https://etherscan.io/address/0x866E82a600A1414e583f7F13623F1aC5d58b0Afa) | | L1ERC721Bridge | [0x608d94945A64503E642E6370Ec598e519a2C1E53](https://etherscan.io/address/0x608d94945A64503E642E6370Ec598e519a2C1E53) | | L1StandardBridge | [0x3154Cf16ccdb4C6d922629664174b904d80F2C35](https://etherscan.io/address/0x3154Cf16ccdb4C6d922629664174b904d80F2C35) | | L2OutputOracle | [0x56315b90c40730925ec5485cf004d835058518A0](https://etherscan.io/address/0x56315b90c40730925ec5485cf004d835058518A0) | +| MIPS | [0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4](https://etherscan.io/address/0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4) | | OptimismMintableERC20Factory | [0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84](https://etherscan.io/address/0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84) | | OptimismPortal | [0x49048044D57e1C92A77f79988d21Fa8fAF74E97e](https://etherscan.io/address/0x49048044D57e1C92A77f79988d21Fa8fAF74E97e) | +| PermissionedDisputeGame | [0x19009dEBF8954B610f207D5925EEDe827805986e](https://etherscan.io/address/0x19009dEBF8954B610f207D5925EEDe827805986e) | +| PreimageOracle | [0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277](https://etherscan.io/address/0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277) | | ProxyAdmin | [0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E](https://etherscan.io/address/0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E) | | SystemConfig | [0x73a79Fab69143498Ed3712e519A88a918e1f4072](https://etherscan.io/address/0x73a79Fab69143498Ed3712e519A88a918e1f4072) | | SystemDictator | [0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557](https://etherscan.io/address/0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557) | @@ -97,18 +105,19 @@ Certain contracts are mandatory according to the [OP Stack SDK](https://stack.op | :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | | AddressManager | [0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B](https://sepolia.etherscan.io/address/0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B) | | AnchorStateRegistryProxy | [0x4C8BA32A5DAC2A720bb35CeDB51D6B067D104205](https://sepolia.etherscan.io/address/0x4C8BA32A5DAC2A720bb35CeDB51D6B067D104205) | -| DelayedWETHProxy | [0x7698b262B7a534912c8366dD8a531672deEC634e](https://sepolia.etherscan.io/address/0x7698b262B7a534912c8366dD8a531672deEC634e) | +| 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 | [0x48F9F3190b7B5231cBf2aD1A1315AF7f6A554020](https://sepolia.etherscan.io/address/0x48F9F3190b7B5231cBf2aD1A1315AF7f6A554020) | +| 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 | [0xFF760A87E41144b336E29b6D4582427dEBdB6dee](https://sepolia.etherscan.io/address/0xFF760A87E41144b336E29b6D4582427dEBdB6dee) | +| 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 | [0x54966d5A42a812D0dAaDe1FA2321FF8b102d1ee1](https://sepolia.etherscan.io/address/0x54966d5A42a812D0dAaDe1FA2321FF8b102d1ee1) | -| PreimageOracle | [0x627F825CBd48c4102d36f287be71f4234426b9e4](https://sepolia.etherscan.io/address/0x627F825CBd48c4102d36f287be71f4234426b9e4) | +| 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 new file mode 100644 index 0000000000..5875a52db4 --- /dev/null +++ b/apps/base-docs/docs/notices/decomissioning-public-geth-archive-snapshots.md @@ -0,0 +1,31 @@ +--- +title: Decommissioning Public Geth Archive Snapshots +slug: /decommissioning-public-geth-archive-snapshots +description: Public Geth archive snapshots were decommissioned on December 15th, 2024. +keywords: + [ + Geth, + Archive Node, + Node Snapshots, + Ethereum, + Infrastructure, + Reth, + Snapshots, + Base Node, + Beacon Endpoint, + OP Stack, + ] +hide_table_of_contents: true +--- + +# Decommissioning Public Geth Archive Snapshots + +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 + +We recommend switching to Reth going forward. We will continue to maintain the Reth archive snapshot. + +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. + +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/notices/preparing-for-fault-proofs-on-base.md b/apps/base-docs/docs/notices/preparing-for-fault-proofs-on-base.md deleted file mode 100644 index 8f68c6ff57..0000000000 --- a/apps/base-docs/docs/notices/preparing-for-fault-proofs-on-base.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Preparing for fault proofs on Base -slug: /preparing-for-fault-proofs-on-base -description: Fault proofs are expected to go live on Base Mainnet in late October. -keywords: - [ - Fault proofs, - Base, - L2 decentralization, - Permissionless output proposals, - Permissionless challenges, - Withdrawals, - Base Mainnet, - DisputeGameFactory, - L2OutputOracle, - Seven-day finalization, - Dispute game, - Bridge operators, - UI updates, - Contract upgrades, - Node operators, - Superbridge, - Superchain bridges, - L1 to L2 deposits, - L2 to L1 withdrawals, - Mid-July upgrade, - Ethereum, - Bridging logic, - Bridge funds, - Decentralized validation, - Community participation, - ] -hide_table_of_contents: true ---- - -# Preparing for fault proofs on Base Mainnet - -Fault proofs are a critical implementation in an L2’s path towards decentralization. They enable a more decentralized approach to validating L2 state and pave the way towards more community participation. - -They improve decentralization with two important capabilities: - -- **Permissionless output proposals:** In an L2 without fault proofs, only the centralized proposer can create and submit output roots about the state of the L2. Now with fault proofs, anyone can make claims about Base's current state instead of relying on a central party. -- **Permissionless challenges to output proposals:** If someone makes a faulty or fraudulent claim, anyone can challenge it. - -These changes allow anyone to withdraw funds from Base to L1 without having to rely on centralized actors. - -## Preparing for fault proofs - -Fault proofs are expected to go live for Base Mainnet in late October. - -**What’s changing for withdrawals:** - -- Withdrawals will involve proving and finalizing based on the fault proof system. -- In addition, the 'DisputeGameFactory' will replace the 'L2OutputOracle' as the new contract for proposing output root statements. This change is part of the broader shift towards the fault proofing system, which is expected to enhance the security and reliability of the platform. - -**If you are in the process of withdrawing your funds from L2 to L1:** - -- **Withdrawals _before_ the upgrade** must wait the 7-day challenge period before finalization. -- **Withdrawals _during_ or _after_ the fault proofs upgrade** for Base Mainnet will be proven by the Fault Proof system and generally take 7 days to finalize, but could see additional delays if challenged. - -**If your team is operating a bridge on Base Mainnet:** - -- Please provide your users with a notice on your UI to inform them that fault proofs will be enabled for Base Mainnet in late October. -- Assess and update your bridging logic, and make sure the new L1 contracts are being used. - -Fault proof contract upgrades will be completed atomically, meaning all affected L1 contracts will be upgraded in a single transaction. No action will be required from node operators. - -Please note, bridge.base.org now redirects to [Superbridge](https://superbridge.app/base) and other bridges (collectively, "Superchain bridges"). Superchain bridges are available to initiate and complete deposits and withdrawals to and from Base. Please refer to our [docs](https://bridge.base.org/deposit) for more information on bridging. diff --git a/apps/base-docs/docs/privacy-policy.md b/apps/base-docs/docs/privacy-policy.md index 765a0e4cde..8045f6f4a6 100644 --- a/apps/base-docs/docs/privacy-policy.md +++ b/apps/base-docs/docs/privacy-policy.md @@ -13,7 +13,7 @@ Last updated: July 12, 2023 At Base (referred to here as “**we**”, “**us**” or “**our**”), we respect and protect the privacy of those users and developers (“**you**” and “**your**” or “**Users**” and “**Developers**”, as relevant) who explore and use Base (“**Base**”) through the Base protocol or any other applications, tools, and features we operate  (collectively, the “**Services**”). -This Privacy Policy describes how we collect, use, and disclose personal information when you use our Services, which include the services offered on our website [https://base.org](https://base.org/) ( “**Site**”). This Privacy Policy does not apply to any processing which Base carries out as a processor on behalf of those Users and Developers who explore and use Base. Please note that we do not control websites, applications, or services operated by third parties, and we are not responsible for their actions. We encourage you to review the privacy policies of the other websites, decentralised applications, and services you use to access or interact with our Services. +This Privacy Policy describes how we collect, use, and disclose personal information when you use our Services, which include the services offered on our website [https://base.org](https://base.org/) ( “**Site**”). This Privacy Policy does not apply to any processing which Base carries out as a processor on behalf of those Users and Developers who explore and use Base. Please note that we do not control websites, applications, or services operated by third parties, and we are not responsible for their actions. We encourage you to review the privacy policies of the other websites, decentralized applications, and services you use to access or interact with our Services. # 1. WHAT INFORMATION WE COLLECT  @@ -44,7 +44,7 @@ We collect the following personal information when providing the Services: - Information from Coinbase Companies (“**Affiliates**”):  We may obtain information about you, such as Basic User Information from our Affiliates (for instance, if you use Base with your Coinbase-hosted wallet) as part of facilitating, supporting, or providing our Services. - Blockchain Data: We may analyze public blockchain data, including timestamps of transactions or events, transaction IDs, digital signatures, transaction amounts and wallet addresses -- Information from Analytics Providers: We receive information about your website usage and interactions from third party analytics providers. This includes browser fingerprint, device information,and IP address. +- Information from Analytics Providers: We receive information about your website usage and interactions from third party analytics providers. This includes browser fingerprint, device information, and IP address. - Error Tracking Data: We utilize information from third party service providers to provide automated error monitoring, reporting, alerting and diagnostic capture for Service and Site errors to allow User or Developers to build more effectively on the Base platform. # 2. HOW WE USE YOUR INFORMATION  @@ -54,14 +54,14 @@ We may use your personal information for the following purposes or as otherwise | | | | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | --------------------- | | **Purpose** | **Information Used** | **Our Legal Basis** | -| To provide you with the Base Services We use certain information that is necessary to conclude and perform our Terms of Service or other relevant contract(s) with you.  | Wallet AddressBlockchain Data | Contractual Necessity | -| To promote the safety, security and integrity of our Services  | Basic User InformationInformation from Analytics Providers | Contractual Necessity | +| To provide you with the Base Services We use certain information that is necessary to conclude and perform our Terms of Service or other relevant contract(s) with you.  | Wallet Address Blockchain Data | Contractual Necessity | +| To promote the safety, security and integrity of our Services  | Basic User Information Information from Analytics Providers | Contractual Necessity | | To allow Users or Developers to build more effectively on the Base platform | Error Tracking Data | Legitimate Interests | | To send you Base Forms for marketing and product development | Basic User Information | Legitimate Interests  | # 3. HOW AND WHY WE SHARE YOUR INFORMATION  -We share certain information about you  with service providers, partners and other third parties in order to help us provide our Services. Here’s how: +We share certain information about you with service providers, partners and other third parties in order to help us provide our Services. Here’s how: **Affiliates.** Basic User Information that we process and collect may be transferred between Affiliates, Services, and employees affiliated with us as a normal part of conducting business and offering our Services to you. diff --git a/apps/base-docs/docs/security.md b/apps/base-docs/docs/security.md deleted file mode 100644 index 3e57f89666..0000000000 --- a/apps/base-docs/docs/security.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Security -slug: /security -description: The Base bug bounty program and procedures for reporting vulnerabilities. -keywords: - [ - Base, - bug bounty program, - report vulnerability, - bug report, - cybersecurity, - HackerOne, - Base network, - Bedrock, - Optimism, - vulnerability reporting, - crypto security, - open source, - ] -hide_table_of_contents: true ---- - -# Security - ---- - -## Bug bounty program - -In line with our strategy of being the safest way for users to access crypto: - -- Coinbase will be extending our [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to cover the Base network, the Base bridge contracts, and Base infrastructure. -- Coinbase will be working in tandem with OP Labs to harden the security guarantees of Bedrock and accelerate the timeline for decentralized fault-proofs on the [OP Stack](https://stack.optimism.io/). -- Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/) to support the open source [Bedrock](https://stack.optimism.io/docs/releases/bedrock/) OP Stack framework. - ---- - -## Reporting vulnerabilities - -All potential vulnerability reports can be submitted via the [HackerOne](https://hackerone.com/coinbase) platform. - -The HackerOne platform allows us to have a centralized and single reporting source for us to deliver optimized SLA's and results. All reports submitted to the platform are triaged around the clock by our team of Coinbase engineers with domain knowledge, assuring the best quality of review. - -For more information on reporting vulnerabilities and our HackerOne bug bounty program, view our [security program policies](https://hackerone.com/coinbase?view_policy=true). - ---- diff --git a/apps/base-docs/docs/security/app-blocklist.md b/apps/base-docs/docs/security/app-blocklist.md new file mode 100644 index 0000000000..bff31a0a43 --- /dev/null +++ b/apps/base-docs/docs/security/app-blocklist.md @@ -0,0 +1,51 @@ +--- +title: How to avoid getting your app flagged as malicious +slug: /security/app-blocklist +description: The Base bug bounty program and procedures for reporting vulnerabilities. +keywords: + [ + Base, + Coinbase Wallet, + dapp, + app, + malicious warning, + browser, + dapp developer, + app developer, + best practice, + unblock, + remove warning, + ] +hide_table_of_contents: true +--- + +# How to avoid getting your app flagged as malicious + +--- + +Ensuring that your app is perceived as trustworthy and not flagged as malicious requires attention to best practices. Here’s a quick guide on how to build a secure and compliant app from day one + +## Smart Contracts + +- **Verify Source Code:** Ensure that the source code of your contracts is verified and publicly available on [block explorers](https://docs.base.org/docs/tools/block-explorers/). +- **Audit Your Contracts**: Having your contracts audited by a reputable firm is crucial. Publish the audit report and provide a reference link to it, so users can easily find it. Audits show that you’ve taken extra steps to secure your smart contracts. +- **Limit User Funds Exposure**: Design your contracts to minimize the exposure of user funds. Use efficient design to reduce any unnecessary risk. For example, request the minimum amount needed to fulfill the transaction. + +--- + +## App Best Practices + +- **Accessibility Across Regions**: Avoid geo-blocking or access restrictions that prevent certain regions or countries from accessing your app. +- **Consistent Web2 Behavior**: Avoid rapid or unexplained changes in UI that can make users feel uncertain about the app’s reliability. +- **Transparent Web3 Interactions**: Make sure your app’s web3 interactions are clear and match the UI actions. For example, a “Mint” button should clearly emit a mint transaction. +- **Standard Sign-in Methods**: Provide all standard connection methods for users to sign in, such as WalletConnect / Coinbase Wallet SDK or popular browser extension wallets. + +--- + +## Verification Request + +Once you’ve implemented these best practices, consider submitting a verification request through the following [form](https://report.blockaid.io/). This step helps ensure that your app is recognized as safe and verified by trusted sources in the ecosystem. + +By following these recommendations, you’ll significantly reduce the chances of your app being flagged as malicious and foster a secure and trustworthy environment for your users. + +--- diff --git a/apps/base-docs/docs/security/bounty.md b/apps/base-docs/docs/security/bounty.md new file mode 100644 index 0000000000..6b7c2cdfbe --- /dev/null +++ b/apps/base-docs/docs/security/bounty.md @@ -0,0 +1,18 @@ +--- +title: Bug bounty +slug: /security/bounty +description: The Base bug bounty program +keywords: + [Base, HackerOne, bug bounty program, bug report, Base network, Bedrock, Optimism, open source] +hide_table_of_contents: true +--- + +# Bug bounty program + +In line with our strategy of being the safest way for users to access crypto: + +- Coinbase will be extending our [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to cover the Base network, the Base bridge contracts, and Base infrastructure. +- Coinbase will be working in tandem with OP Labs to harden the security guarantees of Bedrock and accelerate the timeline for decentralized fault-proofs on the [OP Stack](https://stack.optimism.io/). +- Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/) to support the open source [Bedrock](https://stack.optimism.io/docs/releases/bedrock/) OP Stack framework. + +--- diff --git a/apps/base-docs/docs/security/report.md b/apps/base-docs/docs/security/report.md new file mode 100644 index 0000000000..506670bbab --- /dev/null +++ b/apps/base-docs/docs/security/report.md @@ -0,0 +1,29 @@ +--- +title: Report vulnerability +slug: /security/report +description: The Base procedures for reporting vulnerabilities. +keywords: + [ + Base, + report vulnerability, + cybersecurity, + HackerOne, + Base network, + Bedrock, + Optimism, + vulnerability reporting, + crypto security, + open source, + ] +hide_table_of_contents: true +--- + +# Reporting vulnerabilities + +All potential vulnerability reports can be submitted via the [HackerOne](https://hackerone.com/coinbase) platform. + +The HackerOne platform allows us to have a centralized and single reporting source for us to deliver optimized SLAs and results. All reports submitted to the platform are triaged around the clock by our team of Coinbase engineers with domain knowledge, assuring the best quality of review. + +For more information on reporting vulnerabilities and our HackerOne bug bounty program, view our [security program policies](https://hackerone.com/coinbase?view_policy=true). + +--- diff --git a/apps/base-docs/docs/terms-of-service.md b/apps/base-docs/docs/terms-of-service.md index 4a8c2d13d2..e2f5494121 100644 --- a/apps/base-docs/docs/terms-of-service.md +++ b/apps/base-docs/docs/terms-of-service.md @@ -7,11 +7,11 @@ hide_table_of_contents: true # Sequencer, Testnet, Basenames Interface Terms -Last Updated: August 5, 2024 +Last Updated: October 25, 2024 --- -We’re excited you’re interested in Base, a layer-two optimistic rollup on the Ethereum public blockchain. While we do not control Base, these Terms of Service (“Terms”) constitute a legally binding contract made between you and Coinbase Technologies, Inc. (“Coinbase,” “we,” or “us”) that governs your access to and use of the Coinbase Sequencer, Base Testnet, and Basenames Interface, each of which is defined below (collectively, the “Services”). By using the Services in any way, you agree to be bound by these Terms. If you do not accept the terms and conditions of these Terms, you are not permitted to access or otherwise use the Services. +We’re excited you’re interested in Base, a layer-two optimistic rollup on the Ethereum public blockchain. While we do not control Base, these Terms of Service (“Terms”) constitute a legally binding contract made between you and Coinbase Technologies, Inc. (“Coinbase,” “we,” or “us”) that governs your access to and use of the Coinbase Sequencer, Base Testnet, Basenames Interface, and Basenames Profile Pages each of which is defined below (collectively, the “Services”). By using the Services in any way, you agree to be bound by these Terms. If you do not accept the terms and conditions of these Terms, you are not permitted to access or otherwise use the Services. **BEFORE WE INCLUDE ANY OTHER DETAILS, WE WANT TO GIVE YOU NOTICE OF SOMETHING UP FRONT: BY AGREEING TO THESE TERMS, YOU AND WE AGREE TO RESOLVE ANY DISPUTES WE MAY HAVE WITH EACH OTHER VIA BINDING ARBITRATION OR IN SMALL CLAIMS COURT (INSTEAD OF A COURT OF GENERAL JURISDICTION), AND YOU AGREE TO DO SO AS AN INDIVIDUAL (INSTEAD OF, FOR EXAMPLE, AS A REPRESENTATIVE OR MEMBER OF A CLASS IN A CLASS ACTION). TO THE EXTENT THAT THE LAW ALLOWS, YOU ALSO WAIVE YOUR RIGHT TO A TRIAL BY JURY. FOR MORE INFORMATION, SEE OUR [ARBITRATION AGREEMENT](https://docs.base.org/docs/arbitration) “DISPUTE RESOLUTION, ARBITRATION AGREEMENT, CLASS ACTION WAIVER, AND JURY TRIAL WAIVER.”** @@ -21,7 +21,7 @@ The Base protocol (“Base”) is an open source, optimistic rollup protocol tha ### 2. Basenames -Basenames is an open source blockchain-based naming protocol that maintains a registry of all domains and subdomains on Base through a series of smart contracts deployed on Base. Basenames is not part of the Services. Users may, through interacting with the Basenames, search such registry, register domains and subdomains and manage their registered names. The Basenames interface located at https://base.org/names (the “Basenames Interface”) is one, but not the exclusive, means of accessing Basenames. You are responsible for conducting your own diligence on other interfaces enabling you to access Basenames to understand the fees and risks that they present. +Basenames is an open source blockchain-based naming protocol that maintains a registry of all domains and subdomains on Base through a series of smart contracts deployed on Base. Basenames is not part of the Services. Users may, through interacting with the Basenames, search such registry, register domains and subdomains and manage their registered names, including by adding metadata and other information (e.g., URLs) to the corresponding text records on the Basenames smart contract (such metadata and other information, the “Basename Profile Information”). The Basenames interface located at https://base.org/names (the “Basenames Interface”) is one, but not the exclusive, means of accessing Basenames. You are responsible for conducting your own diligence on other interfaces enabling you to access Basenames to understand the fees and risks that they present. You understand that anyone can register and own a domain name (and its subdomains) that is not already registered on the registry maintained by Basenames. You further understand that names registered on the registry maintained by Basenames may expire and you are responsible for monitoring and renewing the registration of such names. You acknowledge that Coinbase is not able to forcibly remove, prevent or otherwise interfere with the ability of any person to register a domain name on the registry operated by Basenames and you hereby acknowledge that Coinbase will not be liable for any claims or damages whatsoever associated with your use, inability to use any domain names subject of registration, or to be registered, on the registry maintained by Basenames. You agree that Basenames is purely non-custodial, meaning you are solely responsible for the custody of the cryptographic private keys to the digital asset wallets you hold and use to access Basenames. @@ -46,6 +46,7 @@ Coinbase offers the following Services that enable you to access and interact wi - **The Sequencer:** The Coinbase Sequencer is a node operated by Coinbase that receives, records, and reports transactions on Base. While The Coinbase Sequencer is, initially, the only sequencer node supporting transactions on Base, additional nodes may be provided by third parties in the future and there are other mechanisms for submitting transactions through Ethereum. The Coinbase Sequencer does not store, take custody of, control, send, or receive your virtual currency, except for receiving applicable gas fees. It also does not have the ability to modify, reverse, or otherwise alter any submitted transactions, and will not have access to your private key or the ability to control value on your behalf. We reserve the right to charge and modify the fees in connection with your use of the Coinbase Sequencer. These fees may also be subject to taxes under applicable law. - **Base Testnet:** The Base Testnet is a test environment that allows you to build applications integrated with Base. You are permitted to access and use the Base Testnet only to test and improve the experience, security, and design of Base or applications built on Base, subject to these Terms. Base Testnet Tokens will not be converted into any future rewards offered by Coinbase. Coinbase may change, discontinue, or terminate, temporarily or permanently, all or any part of the Base Testnet, at any time and without notice. - **Basenames Interface:** The Basenames Interface is a web application and graphical user display operated by Coinbase and located at base.org/names. It enables you to interact with Basenames by creating blockchain messages that you can sign and broadcast to Base using your Wallet. The Basenames Interface will not have access to your private key at any point. +- **Basenames Profile Pages:** Coinbase also operates a web application and graphical user display (the “Basenames Profile Pages”) that renders information about all registered Basenames domains and subdomains on Base, including any Basename Profile Information associated therewith. You understand that the information displayed on the Basenames Profile Pages, including all Basename Profile Information, is stored and publicly available on the Basenames decentralized protocol. Coinbase provides the Basenames Profile Pages only as a convenience, does not have control over any of third party content appearing therein, and does not warrant or endorse, nor bear responsibility for the availability or legitimacy of, the content on or accessible from any Basenames Profile Page (including any resources, interactive features, or links to Third-Party Services (as defined below) displayed therein). When viewing any Basenames Profile Page, you should assume that Coinbase has not verified the safety or legitimacy of, any content, resources, interactive features, or links appearing on such Basenames Profile Page (including any Farcaster Frames (or other open source products that provide substantially similar functionality) rendered thereon). It is your responsibility to ensure that you fully understand the nature of any links or other interactive features that you may be able to access on a Basenames Profile Page, including any financial risks that you may be exposed to when interacting with a Third-Party Service. ### 7. Acceptable Use @@ -53,7 +54,7 @@ You agree that you will not use the Services in any manner or for any purpose ot - Infringe or violate the intellectual property rights or any other rights of anyone else (including Coinbase) or attempt to decompile, disassemble, or reverse engineer the Services; - Violate any applicable law or regulation, including without limitation, any applicable anti-money laundering laws, anti-terrorism laws, export control laws, end user restrictions, privacy laws or economic sanctions laws/regulations, including those administered by the U.S. Department of Treasury’s Office of Foreign Assets Control; -- Use the Services in a way that is dangerous, harmful, fraudulent, misleading, deceptive, threatening, harassing, defamatory, obscene, or otherwise objectionable; +- Use the Services in a way that is illegal, dangerous, harmful, fraudulent, misleading, deceptive, threatening, harassing, defamatory, obscene, or otherwise objectionable; - Violate, compromise, or interfere with the security, integrity, or availability of any computer, network, or technology associated with the Services, including using the Services in a manner that constitutes excessive or abusive usage, attempts to disrupt, attack, or interfere with other users, or otherwise impacts the stability of the Services. - Use any Coinbase brands, logos, or trademarks (or any brands, logos, or trademarks that are confusingly similar) without our express prior written approval, which we may withhold at our discretion for any reason. @@ -62,7 +63,7 @@ You agree that you will not use the Services in any manner or for any purpose ot ‍By using the Services, Base, or the Bridging Smart Contracts, you represent that you understand there are risks inherent in using cryptographic and public blockchain-based systems, including, but not limited, to the Services and digital assets such as bitcoin (BTC) and ether (ETH). You expressly agree that you assume all risks in connection with your access and use of Base, the Bridging Smart Contracts, Basenames, and the separate Services offered by Coinbase. That means, among other things, you understand and acknowledge that: - The Base, the Bridging Smart Contracts, Basenames, and the separate Services may be subject to cyberattacks and exploits, which could result in the irrevocable loss or reduction in value of your digital assets or in additional copies of your digital assets being created or bridged without your consent. -- Base is subject to periodic upgrades by the Optimism Collective. The Optimism Collective may approve a protocol upgrade that, if implemented, may significantly impacts Base, and may introduce other risks, bugs, malfunctions, cyberattack vectors, or other changes to Base that could disrupt the operation of Base, the Bridging Smart Contracts, Basenames, or the Services or otherwise cause you damage or loss. +- Base is subject to periodic upgrades by the Optimism Collective. The Optimism Collective may approve a protocol upgrade that, if implemented, may significantly impact Base, and may introduce other risks, bugs, malfunctions, cyberattack vectors, or other changes to Base that could disrupt the operation of Base, the Bridging Smart Contracts, Basenames, or the Services or otherwise cause you damage or loss. - If you lose your Wallet seed phrase, private keys, or password, you might permanently be unable to access your digital assets. You bear sole responsibility for safeguarding and ensuring the security of your Wallet. You further expressly waive and release Coinbase, its parents, affiliates, related companies, their officers, directors, members, employees, consultants, representatives. agents, partners, licensors, and each of their respective successors and assigns (collectively, the “Coinbase Entities”) from any and all liability, claims, causes of action, or damages arising from or in any way related to your use of the Services, and your interaction with Base, the Bridging Smart Contracts, or Basenames. Also, to the extent applicable, you shall and hereby do waive the benefits and protections of California Civil Code § 1542, which provides: “[a] general release does not extend to claims that the creditor or releasing party does not know or suspect to exist in his or her favor at the time of executing the release and that, if known by him or her, would have materially affected his or her settlement with the debtor or released party.” @@ -97,7 +98,7 @@ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, BASE, THE BRIDGING SMART CONT ### 16. Limitation of Liability -TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER THE COINBASE ENTITIES NOR ITS SERVICE PROVIDERS INVOLVED IN CREATING, PRODUCING, OR DELIVERING THE SERVICES WILL BE LIABLE FOR ANY INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOST PROFITS, LOST REVENUES, LOST SAVINGS, LOST BUSINESS OPPORTUNITY, LOSS OF DATA OR GOODWILL, SERVICE INTERRUPTION, COMPUTER DAMAGE OR SYSTEM FAILURE, INTELLECTUAL PROPERTY INFRINGEMENT, OR THE COST OF SUBSTITUTE SERVICES OF ANY KIND ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT THE COINBASE ENTITIES OR ITS SERVICE PROVIDERS HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE. +TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER THE COINBASE ENTITIES NOR THEIR RESPECTIVE SERVICE PROVIDERS INVOLVED IN CREATING, PRODUCING, OR DELIVERING THE SERVICES WILL BE LIABLE FOR ANY INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOST PROFITS, LOST REVENUES, LOST SAVINGS, LOST BUSINESS OPPORTUNITY, LOSS OF DATA OR GOODWILL, SERVICE INTERRUPTION, COMPUTER DAMAGE OR SYSTEM FAILURE, INTELLECTUAL PROPERTY INFRINGEMENT, OR THE COST OF SUBSTITUTE SERVICES OF ANY KIND ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT THE COINBASE ENTITIES OR THEIR RESPECTIVE SERVICE PROVIDERS HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL THE COINBASE ENTITIES’ TOTAL LIABILITY ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES EXCEED THE AMOUNTS YOU HAVE PAID OR ARE PAYABLE BY YOU TO THE COINBASE ENTITIES FOR USE OF THE SERVICES OR ONE HUNDRED DOLLARS ($100), WHICHEVER IS HIGHER. THE EXCLUSIONS AND LIMITATIONS OF DAMAGES SET FORTH ABOVE ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN COINBASE AND YOU. @@ -144,7 +145,7 @@ These Terms shall not be construed to waive rights that cannot be waived under a Coinbase is an independent contractor for all purposes. Nothing in these Terms is intended to or shall operate to create a partnership or joint venture between you and Coinbase, or authorize you to act as agent of Coinbase. These Terms are not intended to, and do not, create or impose any fiduciary duties on us. To the fullest extent permitted by law, you acknowledge and agree that we owe no fiduciary duties or liabilities to you or any other party, and that to the extent any such duties or liabilities may exist at law or in equity, those duties and liabilities are hereby irrevocably disclaimed, waived, and foregone. You further agree that the only duties and obligations that we owe you are those set out expressly in these Terms. -### 26. Dispute Resolution, Arbitration Agreement, Class Action Waiver, And Jury Trial Waiver +### 27. Dispute Resolution, Arbitration Agreement, Class Action Waiver, And Jury Trial Waiver If you have a dispute with us, you agree to first contact Coinbase Support via our Customer Support page (https://help.coinbase.com). If Coinbase Support is unable to resolve your dispute, you agree to follow our Formal Complaint Process. You begin this process by submitting our [complaint form](https://help.coinbase.com/en/coinbase/other-topics/other/how-to-send-a-complaint). If you would prefer to send a written complaint via mail, please include as much information as possible in describing your complaint, including your support ticket number, how you would like us to resolve the complaint, and any other relevant information to us at 82 Nassau St #61234, New York, NY 10038. The Formal Complaint Process is completed when Coinbase responds to your complaint or 45 business days after the date we receive your complaint, whichever occurs first. You agree to complete the Formal Complaint Process before filing an arbitration demand or action in small claims court. 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-faq.md b/apps/base-docs/docs/tools/basenames-faq.md index 37f01fee2a..616dabf73c 100644 --- a/apps/base-docs/docs/tools/basenames-faq.md +++ b/apps/base-docs/docs/tools/basenames-faq.md @@ -76,7 +76,7 @@ Transferring all 3 to the same address will fully transfer ownership of the Base ### 11. What happens if I forget to renew my Basename? -If you forget to renew your Name, it will enter a grace period of 90 days, during which you can still renew it. If not renewed during this period, the Basename will become available for others to register. +If you forget to renew your Name, it will enter a grace period of 90-days, during which you can still renew it. If not renewed during this period, the Basename will become available for others to register. ### 12. What happens if a Basename is not renewed during the grace period? @@ -88,7 +88,7 @@ Currently, only one address at a time can be linked to a Basename. However, we p ### 14. I am a builder. How do I integrate Basenames to my app? -If you're a builder looking to integrate Basenames into your app, [OnchainKit](https://onchainkit.xyz/wallet/wallet-dropdown-basename) is the easiest way to get started (tutorial [here](https://docs.base.org/docs/tools/basenames-tutorial)). If you have ideas for new features or badges that you'd like to integrate with Basenames, we'd love to [hear from you](https://app.deform.cc/form/b9c1c39f-f238-459e-a765-5093ca638075/?page_number=0). +If you're a builder looking to integrate Basenames into your app, [OnchainKit](https://onchainkit.xyz/wallet/wallet-dropdown-basename) is the easiest way to get started (tutorial [here](https://docs.base.org/docs/basenames-tutorial-with-onchainkit)). If you have ideas for new features or badges that you'd like to integrate with Basenames, we'd love to [hear from you](https://app.deform.cc/form/b9c1c39f-f238-459e-a765-5093ca638075/?page_number=0). ### 15. How do I get a Basename for my app or project? diff --git a/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md b/apps/base-docs/docs/tools/basenames-onchainkit-tutorial.md index 54ac5f5590..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/block-explorers.md b/apps/base-docs/docs/tools/block-explorers.md index 1cac84bd67..5117b755ee 100644 --- a/apps/base-docs/docs/tools/block-explorers.md +++ b/apps/base-docs/docs/tools/block-explorers.md @@ -84,7 +84,7 @@ A testnet explorer for [Base Sepolia](https://sepolia.basescan.org/) is also ava ## Routescan -[Routescan](https://superscan.network/) superchain explorer allows you to search for transactions, addresses, tokens, prices and other activities taking place across all Superchain blockchains, including Base. +[Routescan](https://routescan.io) superchain explorer allows you to search for transactions, addresses, tokens, prices and other activities taking place across all Superchain blockchains, including Base. --- 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/cross-chain.md b/apps/base-docs/docs/tools/cross-chain.md index ac5eb2dfcc..fd51af8e3c 100644 --- a/apps/base-docs/docs/tools/cross-chain.md +++ b/apps/base-docs/docs/tools/cross-chain.md @@ -80,12 +80,12 @@ To get started with integrating Chainlink CCIP in your Base project, visit the C [LayerZero](https://layerzero.network/) is an omnichain interoperability protocol that enables cross-chain messaging. Applications built on Base can use the LayerZero protocol to connect to 35+ supported blockchains seamlessly. -To get started with integrating LayerZero, visit the LayerZero [documentation](https://layerzero.gitbook.io/docs/evm-guides/master/how-to-send-a-message) and provided examples on [GitHub](https://github.com/LayerZero-Labs/solidity-examples). +To get started with integrating LayerZero, visit the LayerZero [documentation](https://docs.layerzero.network/v1/developers/evm/evm-guides/send-messages) and provided examples on [GitHub](https://github.com/LayerZero-Labs/solidity-examples). #### Supported Networks -- [Base Mainnet](https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids) -- [Base Sepolia](https://layerzero.gitbook.io/docs/technical-reference/testnet/testnet-addresses#layerzero-endpoints-testnet) (Testnet) +- [Base Mainnet](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts#base) +- [Base Sepolia](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts#base-sepolia) (Testnet) --- diff --git a/apps/base-docs/docs/tools/data-indexers.md b/apps/base-docs/docs/tools/data-indexers.md index 6f72ec5f36..cd04a28c69 100644 --- a/apps/base-docs/docs/tools/data-indexers.md +++ b/apps/base-docs/docs/tools/data-indexers.md @@ -98,7 +98,7 @@ To get started, visit the [documentation](https://docs.envio.dev/docs/overview) ## GhostGraph -[GhostGraph](https://GhostGraph.xyz/) makes it easy to build blazingly fast indexers (subgraphs) for smart contracts. +[GhostGraph](https://ghostgraph.xyz/) makes it easy to build blazingly fast indexers (subgraphs) for smart contracts. GhostGraph is the first indexing solution that lets you write your index transformations in **Solidity**. Base dApps can query data with GraphQL using our hosted endpoints. @@ -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/foundry.md b/apps/base-docs/docs/tools/foundry.md index 1b0ec5d420..2fd840d885 100644 --- a/apps/base-docs/docs/tools/foundry.md +++ b/apps/base-docs/docs/tools/foundry.md @@ -44,13 +44,13 @@ Just provide the Base RPC URL and Chain ID when deploying and verifying your con ### Deploying a smart contract ```bash -forge create ... --rpc-url=https://mainnet.base.org/ +forge create --rpc-url=https://mainnet.base.org/ ``` ### Verifying a smart contract ```bash -forge verify-contract ... --chain-id 8453 +forge verify-contract --chain-id 8453 ``` ## Testnet @@ -58,11 +58,11 @@ forge verify-contract ... --chain-id 8453 ### Deploying a smart contract ```bash -forge create ... --rpc-url=https://sepolia.base.org/ +forge create --rpc-url=https://sepolia.base.org/ ``` ### Verifying a smart contract ```bash -forge verify-contract ... --chain-id 84532 +forge verify-contract --chain-id 84532 ``` 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/network-faucets.md b/apps/base-docs/docs/tools/network-faucets.md index cf3a104f40..3899211627 100644 --- a/apps/base-docs/docs/tools/network-faucets.md +++ b/apps/base-docs/docs/tools/network-faucets.md @@ -27,11 +27,11 @@ hide_table_of_contents: true ## Coinbase Developer Platform -The [Coinbase Developer Platform Faucet](https://portal.cdp.coinbase.com/products/faucet) provides free testnet ETH on Base Sepolia - one claim per 24 hours. +The [Coinbase Developer Platform Faucet](https://portal.cdp.coinbase.com/products/faucet) provides free testnet ETH on Base Sepolia - one claim every 7 days. :::info -Requests to Coinbase Developer Platform's Faucet are limited to one claim per 24 hours. +Requests to Coinbase Developer Platform's Faucet are limited to one every 7 days. ::: diff --git a/apps/base-docs/docs/tools/onboarding.md b/apps/base-docs/docs/tools/onboarding.md index 05dc9f8b70..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, @@ -44,7 +48,7 @@ hide_table_of_contents: true ## Openfort -[Openfort](https://openfort.xyz) is an infrastructure provider designed to simplify the development of games and gamified experiences across their suite of API endpoints. Authenticated users can instantly access the embedded, non-custodial [smart account](https://www.openfort.xyz/docs/guides/accounts/smart) natively in the game and sign blockchain transactions with one button. The Oepnfort platform is compatible with most EVM chains, including Base. +[Openfort](https://openfort.xyz) is an infrastructure provider designed to simplify the development of games and gamified experiences across their suite of API endpoints. Authenticated users can instantly access the embedded, non-custodial [smart account](https://www.openfort.xyz/docs/guides/accounts/smart) natively in the game and sign blockchain transactions with one button. The Openfort platform is compatible with most EVM chains, including Base. Use [Auth Guide](https://www.openfort.xyz/docs/guides/auth/overview) to allow several onboarding methods into your game regardless of the platform. @@ -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 fbb879e55a..03a3a07b39 100644 --- a/apps/base-docs/docs/tools/oracles.md +++ b/apps/base-docs/docs/tools/oracles.md @@ -17,7 +17,7 @@ keywords: Pyth, VRF, Gelato VRF, - Gelato verifable random function, + Gelato verifiable random function, verifiable random function, generate random numbers, RNG, @@ -36,17 +36,11 @@ hide_table_of_contents: true The API3 Market provides access to 200+ price feeds on [Base Mainnet](https://market.api3.org/base) and [Base Testnet](https://market.api3.org/base-sepolia-testnet). The price feeds operate as a native push oracle and can be activated instantly via the Market UI. -The price feeds are delivered by an aggregate of [first-party oracles](https://docs.api3.org/explore/airnode/why-first-party-oracles.html) using signed data and support [OEV recapture](https://docs.api3.org/explore/introduction/oracle-extractable-value.html). +The price feeds are delivered by an aggregate of first-party oracles using signed data and support OEV recapture. -Unlike traditional data feeds, reading [API3 price feeds](https://docs.api3.org/guides/dapis/) enables dApps to auction off the right to update the price feeds to searcher bots which facilitates more efficient liquidation processes for users and LPs of DeFi money markets. The OEV recaptured is returned to the dApp. +Unlike traditional data feeds, reading API3 price feeds enables dApps to auction off the right to update the price feeds to searcher bots which facilitates more efficient liquidation processes for users and LPs of DeFi money markets. The OEV recaptured is returned to the dApp. -Apart from data feeds, API3 also provides [Quantum Random Number Generation](https://docs.api3.org/explore/qrng/) on Base Mainnet and Testnet. QRNG is a free-to-use service that provides quantum randomness onchain. It is powered by [Airnode](https://docs.api3.org/reference/airnode/latest/understand/), the first-party oracle that is directly operated by the [QRNG API providers](https://docs.api3.org/reference/qrng/providers.html). Read more about QRNG [here](https://docs.api3.org/reference/qrng). - -Check out these guides to learn more: - -- [dAPIs](https://docs.api3.org/guides/dapis/subscribing-to-dapis/): First-party aggregated data feeds sourced directly from the data providers. -- [Airnode](https://docs.api3.org/guides/airnode/calling-an-airnode/): The first-party serverless Oracle solution to bring any REST API onchain. -- [QRNG](https://docs.api3.org/guides/qrng/): Quantum Random Number Generator for verifiable quantum RNG onchain. +Apart from data feeds, API3 also provides Quantum Random Number Generation on Base Mainnet and Testnet. QRNG is a free-to-use service that provides quantum randomness onchain. It is powered by Airnode, the first-party oracle that is directly operated by the QRNG API providers. #### Supported Networks @@ -137,19 +131,20 @@ The [Pyth Network](https://pyth.network/) is one of the largest first-party Orac - [Available on all major chains](https://docs.pyth.network/price-feeds/contract-addresses) #### Supported Networks for Base (Pyth Price Feeds): -- Base Mainnet: [`0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a`](https://basescan.org/address/0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a) -- Base Sepolia: [`0xA2aa501b19aff244D90cc15a4Cf739D2725B5729`](https://base-sepolia.blockscout.com/address/0xA2aa501b19aff244D90cc15a4Cf739D2725B5729) +- Base Mainnet: [`0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a`](https://basescan.org/address/0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a) +- Base Sepolia: [`0xA2aa501b19aff244D90cc15a4Cf739D2725B5729`](https://base-sepolia.blockscout.com/address/0xA2aa501b19aff244D90cc15a4Cf739D2725B5729) ### Pyth Entropy + Pyth Entropy allows developers to quickly and easily generate secure **random numbers** onchain. Check [how to generate random numbers in EVM contracts](https://docs.pyth.network/entropy/generate-random-numbers/evm) for a detailed walkthrough. #### Supported Networks for Base (Pyth Entropy): -- Base Mainnet: [`0x6E7D74FA7d5c90FEF9F0512987605a6d546181Bb`](https://basescan.org/address/0x6E7D74FA7d5c90FEF9F0512987605a6d546181Bb) -- Base Sepolia: [`0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c`](https://base-sepolia.blockscout.com/address/0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c) +- Base Mainnet: [`0x6E7D74FA7d5c90FEF9F0512987605a6d546181Bb`](https://basescan.org/address/0x6E7D74FA7d5c90FEF9F0512987605a6d546181Bb) +- Base Sepolia: [`0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c`](https://base-sepolia.blockscout.com/address/0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c) Check out the following links to get started with Pyth. @@ -178,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/docs/using-base.md b/apps/base-docs/docs/using-base.md index b5a5b4a98e..398805aefc 100644 --- a/apps/base-docs/docs/using-base.md +++ b/apps/base-docs/docs/using-base.md @@ -86,11 +86,11 @@ Your active network should now be switched to Base testnet. #### Other wallets -Base Sepolia can be added as a custom network to any EVM-compatible wallet (i.e. [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn)). +Base Sepolia can be added as a custom network to any EVM-compatible wallet (e.g., [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn)). #### MetaMask -To add Base Sepolia as a custom network to MetaMask: +To add Base Sepolia as a custom network in MetaMask: 1. Open the MetaMask browser extension. 2. Open the network selection dropdown menu by clicking the dropdown button at the top of the extension. diff --git a/apps/base-docs/docusaurus.config.js b/apps/base-docs/docusaurus.config.js index ef10f95fdf..dc73598cca 100644 --- a/apps/base-docs/docusaurus.config.js +++ b/apps/base-docs/docusaurus.config.js @@ -130,11 +130,11 @@ const config = { eventContext: 'navbar', }, { - to: 'https://base.org/getstarted', + to: 'https://base.org/build', navposition: 'bottomLeft', label: 'Get Started', type: 'custom-navbarLink', - eventLabel: 'getstarted', + eventLabel: 'build', eventContext: 'navbar', }, { @@ -317,7 +317,7 @@ const config = { }, ], }, - // Langauge selection dropdown will be supported in the future + // Language selection dropdown will be supported in the future // { // type: 'localeDropdown', // navposition: 'bottomRight', @@ -344,7 +344,7 @@ const config = { respectPrefersColorScheme: false, }, }, - // Langauge selection dropdown will be supported in the future + // Language selection dropdown will be supported in the future // i18n: { // defaultLocale: 'en', // locales: ['en', 'fr'], diff --git a/apps/base-docs/sidebars.js b/apps/base-docs/sidebars.js index ec5243aad7..11dad814ed 100644 --- a/apps/base-docs/sidebars.js +++ b/apps/base-docs/sidebars.js @@ -7,7 +7,7 @@ module.exports = { label: 'Notices', collapsible: false, collapsed: false, - items: ['notices/preparing-for-fault-proofs-on-base'], + items: ['notices/decomissioning-public-geth-archive-snapshots'], }, { type: 'category', @@ -86,7 +86,13 @@ module.exports = { items: ['tokens/token-list', 'tokens/wallet'], }, ['contracts'], - ['security'], + { + type: 'category', + label: 'Security', + collapsible: false, + collapsed: false, + items: ['security/bounty', 'security/report', 'security/app-blocklist'], + }, { type: 'link', label: 'Status', 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/components/DocFeedback/styles.module.css b/apps/base-docs/src/components/DocFeedback/styles.module.css index c58e19d6ea..fdcbe08eb6 100644 --- a/apps/base-docs/src/components/DocFeedback/styles.module.css +++ b/apps/base-docs/src/components/DocFeedback/styles.module.css @@ -71,7 +71,7 @@ transform: scale(-1, 1); } -/* Feedbak Modal Header/Footer */ +/* Feedback Modal Header/Footer */ .feedbackModalHeader { display: flex; justify-content: center; diff --git a/apps/base-docs/src/components/Hero/HeroButton/index.tsx b/apps/base-docs/src/components/Hero/HeroButton/index.tsx index 41f49bb192..431be92d85 100644 --- a/apps/base-docs/src/components/Hero/HeroButton/index.tsx +++ b/apps/base-docs/src/components/Hero/HeroButton/index.tsx @@ -12,7 +12,7 @@ export default function HeroButton() { return ( //Paymaster & Bundler endpoint +const rpcUrl = 'https://api.developer.coinbase.com/rpc/v1/base/' //Paymaster & Bundler endpoint ``` ```javascript @@ -328,7 +328,7 @@ Feel free to use your own contract to interact with the Paymaster. For learning You will be interacting with the NFT + ABI from a simple NFT contract deployed at: `0x83bd615eb93eE1336acA53e185b03B54fF4A17e8` -Copy and paste the NFT's abi into `index.js` +Copy and paste the NFT's ABI into `index.js` ```javascript const abi = [ diff --git a/apps/base-docs/tutorials/docs/0_intro-to-providers.md b/apps/base-docs/tutorials/docs/0_intro-to-providers.md index 8a1ff4bddc..58d1babecc 100644 --- a/apps/base-docs/tutorials/docs/0_intro-to-providers.md +++ b/apps/base-docs/tutorials/docs/0_intro-to-providers.md @@ -96,7 +96,7 @@ You'll encounter providers divided into three general categories: Public Provide Many tutorials and guides, including the getting started guide for [wagmi], use a _Public Provider_ as the default to get you up and running. Public means that they're open, permissionless, and free, so the guides will also usually warn you that you need to add another provider if you don't want to run into rate limiting. Listen to these warnings! The rate-limits of public providers are severe, and you'll start getting limited very quickly. -In wagmi, a public client is automatically included in the default confit. This client is just a wrapper setting up a [JSON RPC] provider using the `chain` and `rpcUrls` listed in Viem's directory of chain information. You can view the [data for Base Sepolia here]. +In wagmi, a public client is automatically included in the default config. This client is just a wrapper setting up a [JSON RPC] provider using the `chain` and `rpcUrls` listed in Viem's directory of chain information. You can view the [data for Base Sepolia here]. Most chains will list this information in their docs as well. For example, on the network information pages for [Base] and [Optimism]. If you wanted, you could manually set up a `jsonRpcProvider` in wagmi using this information. 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 809df5a642..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 @@ -105,16 +105,22 @@ If you're a prospective or current Base Node operator and would like to restore In the home directory of your Base Node, create a folder named `geth-data` or `reth-data`. If you already have this folder, remove it to clear the existing state and then recreate it. Next, run the following code and wait for the operation to complete. +:::info + +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_1_coinbase-smart-wallet.md b/apps/base-docs/tutorials/docs/1_1_coinbase-smart-wallet.md index 641a7b3f9c..2b111062dd 100644 --- a/apps/base-docs/tutorials/docs/1_1_coinbase-smart-wallet.md +++ b/apps/base-docs/tutorials/docs/1_1_coinbase-smart-wallet.md @@ -433,7 +433,7 @@ In this tutorial, you've learned how to connect users to your onchain app with t [Testnet Opensea]: https://testnets.opensea.io/ [deploy]: https://docs.base.org/tutorials?tag=smart%20contracts [Sepolia Basescan]: https://sepolia.basescan.org/ -[BOAT]: https://www.smartwallet.dev/guides/create-app/using-boat +[BOAT]: https://www.smartwallet.dev/guides/create-app/using-onchain-app-template [wagmi template]: https://www.smartwallet.dev/guides/create-app/using-wagmi [Coinbase Developer Platform (CDP)]: https://portal.cdp.coinbase.com/ [Base Gasless Campaign]: https://www.smartwallet.dev/base-gasless-campaign diff --git a/apps/base-docs/tutorials/docs/1_4_farcaster-frames-nft-minting.md b/apps/base-docs/tutorials/docs/1_4_farcaster-frames-nft-minting.md index 1bc3800f75..193142eec5 100644 --- a/apps/base-docs/tutorials/docs/1_4_farcaster-frames-nft-minting.md +++ b/apps/base-docs/tutorials/docs/1_4_farcaster-frames-nft-minting.md @@ -106,7 +106,7 @@ You'll also want to keep track of addresses that have already minted, to prevent :::danger -Make sure you added `.env.local` to ``.gitignore`! **If you don't do this you are going to expose your key and lose your wallet!** +Make sure you added `.env.local` to `.gitignore`! **If you don't do this you are going to expose your key and lose your wallet!** ::: diff --git a/apps/base-docs/tutorials/docs/1_ock-swap-theme.md b/apps/base-docs/tutorials/docs/1_ock-swap-theme.md new file mode 100644 index 0000000000..a6b77f6078 --- /dev/null +++ b/apps/base-docs/tutorials/docs/1_ock-swap-theme.md @@ -0,0 +1,196 @@ +--- +title: 'Create a Custom Themed Swap Component with OnchainKit' +slug: /create-custom-themed-swap-component +description: Learn how to implement a swap component with a custom theme using OnchainKit in your React application. +author: hughescoin +keywords: [OnchainKit, Swap Component, Custom Theme, React, TypeScript, ERC20 Tokens, Base Chain] +tags: ['frontend', 'defi', 'ethereum', 'base'] +difficulty: medium +displayed_sidebar: null +--- + +In this tutorial, you'll learn how to create a swap component with a custom theme using OnchainKit. We'll start with the OnchainKit App Template and modify it to include a swap interface for ERC20 tokens on Base. + +--- + +## Objectives + +By the end of this tutorial, you will be able to: + +- Set up a project using the OnchainKit App Template +- Implement a swap component for ERC20 tokens +- Customize the theme of your OnchainKit components +- Apply CSS overrides to fine-tune the appearance of your app + +## Prerequisites + +### React and TypeScript + +You should be familiar with React and TypeScript. If you're new to these technologies, consider reviewing their [official documentation](https://react.dev/) first. + +### OnchainKit + +This tutorial uses [OnchainKit]. Familiarity with its basic concepts will be helpful. + +--- + +## Setting up the Project + +To get started, clone the OnchainKit App Template by running: + +```bash +git clone git@github.com:coinbase/onchain-app-template.git +``` + +If you have an existing app that uses OnchainKit, update to the latest version: + +```bash +bun update @coinbase/onchainkit --latest +``` + +Now let's implement the Swap component by importing it from OnchainKit. Import it into a new route of your app or, if you're following along, the `src/app/page.tsx` file: + +```ts +import { + Swap, + SwapAmountInput, + SwapToggleButton, + SwapButton, + SwapMessage, + SwapToast, +} from '@coinbase/onchainkit/swap'; + +import type { Token } from 'node_modules/@coinbase/onchainkit/esm/token/types'; +``` + +The `` component enables you to swap any ERC20 token on Base. For this example, your users will be able to swap between USDC and ETH. Next, using the `Token` type, create instances of ETH and USDC. + +```ts +const ETHToken: Token = { + address: '', + chainId: 8453, + decimals: 18, + name: 'Ethereum', + symbol: 'ETH', + image: + 'https://dynamic-assets.coinbase.com/dbb4b4983bde81309ddab83eb598358eb44375b930b94687ebe38bc22e52c3b2125258ffb8477a5ef22e33d6bd72e32a506c391caa13af64c00e46613c3e5806/asset_icons/4113b082d21cc5fab17fc8f2d19fb996165bcce635e6900f7fc2d57c4ef33ae9.png', +}; + +const USDCToken: Token = { + address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + chainId: 8453, + decimals: 6, + name: 'USDC', + symbol: 'USDC', + image: + 'https://dynamic-assets.coinbase.com/3c15df5e2ac7d4abbe9499ed9335041f00c620f28e8de2f93474a9f432058742cdf4674bd43f309e69778a26969372310135be97eb183d91c492154176d455b8/asset_icons/9d67b728b6c8f457717154b3a35f9ddc702eae7e76c4684ee39302c4d7fd0bb8.png', +}; +``` + +![swap-component-default](../../assets/images/onchainkit-tutorials/swapped-theme-before.png) + +Here's a [sample](https://gist.github.com/hughescoin/4558feabb4f40b51f800091f04a945ae) of the full `page.tsx` file for reference. + +## Changing the Theme + +To change the theme of the site, navigate to `src/components/OnchainProviders.tsx` and add a `config` object to the `OnchainKitProvider`. This is the first step in enabling Themes for your project. + +```js +config={{ + appearance: { + mode: 'auto', // 'auto' | 'light' | 'dark' + theme: 'default', // 'default' | 'base' | 'cyberpunk' | 'hacker' + }, +}} +``` + +OnchainKit provides you with four preset themes. We'll use the "hacker" theme for its fonts but change the colors to a different palette. + +If you need help coming up with a color palette, there are many online tools available. For example, I used [color magic](https://colormagic.app). + +## Customizing the CSS + +Once you've chosen your colors, add them to the CSS file. Update the `src/app/global.css` file to include CSS overrides for OnchainKit properties. In the sample below, the comments provide guidance on which properties will change color. + +:::tip Having trouble changing an element? + +Use the "Inspect" feature in your browser to identify the element you wish to override in your `global.css` file. + +::: + +```css +@layer base { + :root, + .default-light, + .default-dark, + .base, + .cyberpunk, + .hacker { + /* Text colors */ + --ock-text-inverse: #f1d579; + --ock-text-foreground: #8c3e21; + --ock-text-foreground-muted: #f1d579; + --ock-text-error: #c85c2d; + --ock-text-primary: #e1a04c; + --ock-text-success: #f5b370; + --ock-text-warning: #f1d579; + --ock-text-disabled: #8c3e21; + + /* Background colors */ + --ock-bg-default: #8c3e21; + --ock-bg-default-hover: #c85c2d; + --ock-bg-default-active: #f1d579; + --ock-bg-alternate: #f1d579; + --ock-bg-alternate-hover: #e1a04c; + --ock-bg-alternate-active: #c85c2d; + --ock-bg-inverse: #c85c2d; + --ock-bg-inverse-hover: #e1a04c; + --ock-bg-inverse-active: #f5b370; + --ock-bg-primary: #c85c2d; + --ock-bg-primary-hover: #e1a04c; + --ock-bg-primary-active: #f1d579; + --ock-bg-primary-washed: #f5b370; + --ock-bg-primary-disabled: #8c3e21; + --ock-bg-secondary: #e1a04c; + --ock-bg-secondary-hover: #f1d579; + --ock-bg-secondary-active: #f5b370; + --ock-bg-error: #c85c2d; + --ock-bg-warning: #f1d579; + --ock-bg-success: #f5b370; + --ock-bg-default-reverse: #c85c2d; + + /* Icon colors */ + --ock-icon-color-primary: #c85c2d; + --ock-icon-color-foreground: #c85c2d; + --ock-icon-color-foreground-muted: #e1a04c; + --ock-icon-color-inverse: #f5b370; + --ock-icon-color-error: #c85c2d; + --ock-icon-color-success: #f5b370; + --ock-icon-color-warning: #f1d579; + + /* Line colors */ + --ock-line-primary: #c85c2d; + --ock-line-default: #8c3e21; + --ock-line-heavy: #f1d579; + --ock-line-inverse: #e1a04c; + } +} + +.ock-font-family.font-semibold.text-xl.leading-7 { + color: #f1d579; +} +``` + +Now refresh your page, and you should see your swap component change to your defined color palette! + +![swap-component](../../assets/images/onchainkit-tutorials/swapped-theme-final.png) + +If something looks off, remember to check that you've overridden the correct element. See the above tip to learn how to find the correct element. + +## Conclusion + +Congratulations! You've successfully implemented the `` component and customized it to a theme of your choice. Pretty neat, right? +[OnchainKit]: https://github.com/coinbase/onchainkit +[OnchainKit App Template]: https://github.com/coinbase/onchain-app-template +[color magic]: https://colormagic.app +[sample]: https://gist.github.com/hughescoin/4558feabb4f40b51f800091f04a945ae 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 c2579c72af..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 @@ -42,7 +42,7 @@ The [Coinbase Developer Platform] provides access to tools and services necessar ## Jump Right In -For this turotial, you will deploy a simple contract that is included in the Foundry quickstart. To do so, ensure that you have Foundry installed. +For this tutorial, you will deploy a simple contract that is included in the Foundry quickstart. To do so, ensure that you have Foundry installed. If you don't have Foundry install it: @@ -71,7 +71,7 @@ You should have a folder structure similar to this: └── test ``` -The `src` folder will contain a `Counter.sol` file which will serve as the country you want to deploy. +The `src` folder will contain a `Counter.sol` file which will serve as the contract you want to deploy. :::note You will need ETH on Base to deploy You (the deployer wallet) will need some ETH in order to broadcast the transaction to the Base network. Fortunately, transactions are usually < 1 cent on Base mainnet. @@ -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" @@ -114,7 +114,7 @@ Deployed to: 0xEF5fe818Cb814E5c8277C5F12B57106B4EC3DdaA Transaction hash: 0xb191f9679a1fee253cf430ac09a6838f6806cfb2a250757fef407880f5546836 ``` -Congrats! You've now deployed a contract to Base. The output of the deployment command contiains a contract address (e.g `Deployed to: 0xEF5fe818Cb814E5c8277C5F12B57106B4EC3DdaA`). Copy this address as you will need it in the next step. +Congrats! You've now deployed a contract to Base. The output of the deployment command contains a contract address (e.g `Deployed to: 0xEF5fe818Cb814E5c8277C5F12B57106B4EC3DdaA`). Copy this address as you will need it in the next step. ### Verify the contract @@ -155,7 +155,7 @@ To verify a contract you will use the `verifysourcecode` route, with the `contra :::tip Unsure what data to input? -In every foundry project you will have a `.json` file that contains the conrtacts metadata and ABI. For this particular project, this information is located in the `/verify_contracts/out/Counter.sol/Counter.json` +In every foundry project you will have a `.json` file that contains the contracts metadata and ABI. For this particular project, this information is located in the `/verify_contracts/out/Counter.sol/Counter.json` Under the `Metadata` object you will find the compiler version under `evmversion` ::: @@ -263,7 +263,7 @@ If successful, your terminal will output JSON text with three properties `status Result is the GUID and is a unique identifier for checking the status of your contracts verification. -To verify the contract, let's create a curl request with the following paramters +To verify the contract, let's create a curl request with the following parameters ```bash curl "https://api.basescan.org/api?module=contract&action=checkverifystatus&guid=cqjzzvppgswqw5adq4v6iq4xkmf519pj1higvcxsdiwcvwxemd&apikey=DK8M329VYXDSKTF633ABTK3SAEZ2U9P8FK" diff --git a/apps/base-docs/tutorials/docs/2_1_simple-onchain-nfts.md b/apps/base-docs/tutorials/docs/2_1_simple-onchain-nfts.md index 9970788ade..85569d19d2 100644 --- a/apps/base-docs/tutorials/docs/2_1_simple-onchain-nfts.md +++ b/apps/base-docs/tutorials/docs/2_1_simple-onchain-nfts.md @@ -299,11 +299,11 @@ function _update(address to, uint256 tokenId, address auth) internal override(ER Now that you have a list of NFTs owned by an address, you can add a function to retrieve all of them. While you're at it, add the json metadata for each token. Doing so lets you get the complete list of NFTs **and** their metadata for just one RPC call! ```solidity -function getNFftsOwned(address owner) public view returns (TokenAndMetatdata[] memory) { - TokenAndMetatdata[] memory tokens = new TokenAndMetatdata[](tokensOwned[owner].length()); +function getNftsOwned(address owner) public view returns (TokenAndMetadata[] memory) { + TokenAndMetadata[] memory tokens = new TokenAndMetadata[](tokensOwned[owner].length()); for (uint i = 0; i < tokensOwned[owner].length(); i++) { uint tokenId = tokensOwned[owner].at(i); - tokens[i] = TokenAndMetatdata(tokenId, tokenURI(tokenId)); + tokens[i] = TokenAndMetadata(tokenId, tokenURI(tokenId)); } return tokens; } @@ -354,16 +354,16 @@ contract RandomColorNFT is ERC721 { tokenIdToColor[counter] = generateRandomColor(); } - struct TokenAndMetatdata { + struct TokenAndMetadata { uint tokenId; string metadata; } - function getNftsOwned(address owner) public view returns (TokenAndMetatdata[] memory) { - TokenAndMetatdata[] memory tokens = new TokenAndMetatdata[](tokensOwned[owner].length()); + function getNftsOwned(address owner) public view returns (TokenAndMetadata[] memory) { + TokenAndMetadata[] memory tokens = new TokenAndMetadata[](tokensOwned[owner].length()); for (uint i = 0; i < tokensOwned[owner].length(); i++) { uint tokenId = tokensOwned[owner].at(i); - tokens[i] = TokenAndMetatdata(tokenId, tokenURI(tokenId)); + tokens[i] = TokenAndMetadata(tokenId, tokenURI(tokenId)); } return tokens; } @@ -763,7 +763,7 @@ contract RandomColorNFT is ERC721 { "type": "address" } ], - "name": "getNFftsOwned", + "name": "getNftsOwned", "outputs": [ { "components": [ @@ -778,7 +778,7 @@ contract RandomColorNFT is ERC721 { "type": "string" } ], - "internalType": "struct RandomColorNFT.TokenAndMetatdata[]", + "internalType": "struct RandomColorNFT.TokenAndMetadata[]", "name": "", "type": "tuple[]" } diff --git a/apps/base-docs/tutorials/docs/2_dynamic-nfts.md b/apps/base-docs/tutorials/docs/2_dynamic-nfts.md index 3dda54365f..d3422fc32e 100644 --- a/apps/base-docs/tutorials/docs/2_dynamic-nfts.md +++ b/apps/base-docs/tutorials/docs/2_dynamic-nfts.md @@ -187,7 +187,7 @@ irys upload image-level-3.png \ Create three metadata files similar to the ones below. Make sure to change the value of the image field to match the URLs generated in the previous step. -```jason filename="metadata-level-1.json" +```json filename="metadata-level-1.json" { "name": "SuperMon", "symbol": "SMON", @@ -202,7 +202,7 @@ Create three metadata files similar to the ones below. Make sure to change the v } ``` -```jason filename="metadata-level-2.json" +```json filename="metadata-level-2.json" { "name": "SuperMon", "symbol": "SMON", @@ -218,7 +218,7 @@ Create three metadata files similar to the ones below. Make sure to change the v } ``` -```jason filename="metadata-level-3.json" +```json filename="metadata-level-3.json" { "name": "SuperMon", "symbol": "SMON", @@ -314,6 +314,6 @@ Dynamic NFTs are commonly used with gaming projects, similar to the one we built [Download a zip containing PNGs]: https://gateway.irys.xyz/MoOvEzePMwFgc_v6Gw3U8ovV6ostgrkWb9tS4baAJhc [Irys CLI]: https://docs.irys.xyz/build/d/storage-cli/installation [mutability features]: https://docs.irys.xyz/build/d/features/mutability -[Opensea Testnet]: https://testnets.opensea.io/accoun +[Opensea Testnet]: https://testnets.opensea.io/account [Remix]: https://docs.base.org/tutorials/deploy-with-remix [server]: https://docs.irys.xyz/build/d/quickstart diff --git a/apps/base-docs/tutorials/docs/2_email-campaign-with-resend.md b/apps/base-docs/tutorials/docs/2_email-campaign-with-resend.md index 47d0866ec3..f4c0a6f23a 100644 --- a/apps/base-docs/tutorials/docs/2_email-campaign-with-resend.md +++ b/apps/base-docs/tutorials/docs/2_email-campaign-with-resend.md @@ -288,7 +288,7 @@ export const EmailTemplate: React.FC> = ({ firstNam ); ``` -In `src/app/page.tsx` add the following section to display wether the user is a member or not: +In `src/app/page.tsx` add the following section to display whether the user is a member or not: ```html
@@ -181,10 +181,10 @@ Finally, configure the Pay component within your JSX. Wrap the `PayButton` and ` {' '} {/* Added spacing */} {address ? ( - - - - + + + + ) : ( )} @@ -200,7 +200,7 @@ You may now test your implementation locally by running `bun run dev` Congratulations! You've successfully integrated Coinbase Commerce payments into your application using OnchainKit. This is a significant achievement that opens up new possibilities for your business. -As next steps, consider expanding your product catalog by adding more items to your site. Each new product can be seamlessly integrated using the same Pay component, allowing you to create a diverse and engaging e-commerce experience. Once you're satisfied with your application, you can easily deploy it using a service like Vercel, making your creation accessible to users worldwide. Keep exploring and building – the potential for your onchain commerce application is limitless! +As next steps, consider expanding your product catalog by adding more items to your site. Each new product can be seamlessly integrated using the same Checkout component, allowing you to create a diverse and engaging e-commerce experience. Once you're satisfied with your application, you can easily deploy it using a service like Vercel, making your creation accessible to users worldwide. Keep exploring and building – the potential for your onchain commerce application is limitless! --- 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 58a254b9a8..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, @@ -28,10 +28,10 @@ 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 Onchain Kit App Template -- Configure the app for to onboard users easily using [Smart Wallets] +- Set up a project using the [OnchainKit App Template] +- 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 funds to their wallet +- Use the Fund component to allow users to buy tokens from their wallet without leaving your app ## Prerequisites @@ -41,11 +41,11 @@ You should be familiar with React and TypeScript. If you're new to these technol ### OnchainKit -This tutorial uses Coinbase's Onchain Kit. Familiarity with its basic concepts will be helpful. +This tutorial uses Coinbase's OnchainKit. Familiarity with its basic concepts will be helpful. ### 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 @@ -58,7 +58,7 @@ If you see a "something went wrong" error message when navigating to pay.coinbas ## Setting up the Project -To get started, clone the Onchain Kit App Template by running +To get started, clone the OnchainKit App Template by running: ```bash git clone git@github.com:coinbase/onchain-app-template.git @@ -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,12 +167,13 @@ 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. --- -[Onchain Kit]: https://github.com/coinbase/onchainkit +[OnchainKit]: https://github.com/coinbase/onchainkit +[OnchainKit App Template]: https://github.com/coinbase/onchain-app-template [Viem]: https://viem.sh/ [Smart Wallets]: https://keys.coinbase.com/onboarding [viem]: https://viem.sh/docs/introduction diff --git a/apps/base-docs/tutorials/docs/2_paymaster-erc20-gas-payments.md b/apps/base-docs/tutorials/docs/2_paymaster-erc20-gas-payments.md new file mode 100644 index 0000000000..a9a141f7cf --- /dev/null +++ b/apps/base-docs/tutorials/docs/2_paymaster-erc20-gas-payments.md @@ -0,0 +1,199 @@ +--- +title: 'Enable ERC-20 Gas Payments with Coinbase Paymaster' +slug: /enable-erc20-gas-payments +description: Learn how to enable ERC-20 tokens as gas payment options for smart wallets using Coinbase Paymaster, improving UX and onboarding for your onchain application. +author: hughescoin +keywords: + [ + Paymaster, + ERC20 Gas Payments, + Wagmi, + React, + TypeScript, + Base, + cbBTC, + Bitcoin, + Smart Wallets, + Paymaster Policy, + ] +tags: ['backend', 'ethereum', 'base', 'erc20'] +difficulty: medium +displayed_sidebar: null +--- + +# Using a Custom ERC-20 Token for Gas Payments with Coinbase Paymaster + +Allowing users to pay gas fees with ERC-20 tokens can significantly improve the user experience by removing the dependency on native tokens. This simplifies onboarding for new users and aligns your application’s utility with its ecosystem token. + +With the added flexibility of Paymaster policies, you can further enhance the user journey, tailoring how transactions are sponsored and fees are handled. + +This tutorial demonstrates how to enable ERC-20 tokens (including your own custom tokens) as gas payment options for [smart wallets] using the Coinbase Paymaster. + +It builds on the [Integrating a Paymaster for Gasless Transactions] tutorial. If you're unfamiliar with integrating Paymasters, start there first. + +Ready? Let's build! + +--- + +## Objectives + +- Configure the Coinbase Paymaster to allow users to pay gas fees using a custom ERC-20 token, such as `cbBTC`. +- Integrate Paymaster policies to secure transactions and align them with your application’s user experience goals. +- Abstract native token dependencies (ETH) to simplify onboarding and provide a streamlined, user-friendly transaction flow for your onchain application. + +## Prerequisites + +### Access to the Coinbase Developer Platform + +You'll need to set up an account on with [Coinbase Developer Platform (CDP)](https://www.coinbase.com/cloud) account. 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. + +### Request Access for ERC-20 Gas Payments + +To enable ERC-20 tokens as gas payment options, you need to configure the Coinbase Paymaster to recognize your token. This involves submitting a request to whitelist your token and defining where the gas payments (in ERC-20 tokens) will be sent. + +Follow the steps below to request access and get your token approved: + +**Submit the Form** + Use [this form](https://app.deform.cc/form/9b59499b-e82e-4879-8100-40c603084747/?page_number=0) to request access to enable ERC-20 gas payments. You'll need: + +- **Contract Address**: The address of the ERC-20 token you want to use for gas payments. +- **Receiving Address**: An address where the tokens will be sent as users pay for gas. + +**Approval Notification** +Once approved, your Coinbase Developer Platform (CDP) dashboard under the **ERC-20 Paymaster** tab will show your token configuration. + +![cdp-erc20-configuration](../../assets/images/paymaster-tutorials/cdp-paymaster-config.png) + +## Configure Paymaster & Bundler Gas Policy + +Once your ERC-20 token is approved for gas payments, the next step is to configure your Paymaster’s gas policy. Gas policies allow you to fine-tune how transactions are handled, ensuring that your application remains secure, fair, and functional while providing a seamless experience for your users. + +For this example, you'll configure the policy to always require a custom ERC-20 token for gas payments. This setup ensures that users interact with your application in a predictable and consistent manner. + +:::info + +If users are new to your application and do not have the required token, consider sponsoring a few of their User Operations to improve onboarding. You can learn how to set gas policies in [this written guide] or the [YouTube walkthrough]. + +::: + +Navigate to the [Paymaster Configuration Tab](https://portal.cdp.coinbase.com/products/bundler-and-paymaster) and configure the policy parameters with a **per user limit of $0.01** and set the **maximum number of user operations to 1**. These settings ensure that all transactions will utilize the ERC-20 token for gas payments. + +This ensures all transactions use the ERC-20 token for gas. + +![cdp-policy-setting](../../assets/images/paymaster-tutorials/cdp-policy-settings.png) + +Save your Paymaster and Bundler endpoints as environment variables for use in your project. + +![cdp-pm-bundler-endpoint](../../assets/images/paymaster-tutorials/cdp-copy-endpoint.png) + +## Enable ERC-20 Gas Payments in Your Project + +Now that your token is approved and the Paymaster is configured, the next step is to update your project to enable ERC-20 gas payments. This section will guide you through setting up your project to allow users to mint NFTs using `cbBTC` for gas fees. + +### Set Up Constants and a Base Client + +Begin by defining key constants and initializing the Base client. These constants include the token's address, its number of decimals, and the amount required for approval. + +- `cbBtcAddress`: Address of the ERC-20 token (`cbBTC` in this case). +- `tokenDecimals`: Number of decimals for the token (8 for `cbBTC`). +- `minTokenThreshold`: Minimum token amount required for allowance checks. +- `tokenApprovalAmount`: Amount approved for gas payments. + +```typescript +const client = createPublicClient({ + chain: base, + transport: http(process.env.NEXT_PUBLIC_RPC_URL), +}); + +const cbBtcAddress = '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf' as `0x${string}`; +const tokenDecimals = 8; +const minTokenThreshold = BigInt(1 * 10 ** tokenDecimals); +const tokenApprovalAmount = BigInt(1 * 10 ** tokenDecimals); +const paymasterAddressMainnet = '0x2FAEB0760D4230Ef2aC21496Bb4F0b47D634FD4c'; +``` + +This ensures your application can interact with the cbBTC token and correctly manage allowances for gas payments. + +### Check Token Allowance + +Create a state variable and a `checkAllowance` function to verify if the user has approved enough tokens for gas payments. + +The `checkAllowance` function reads the token allowance granted to the Paymaster contract and updates `hasAllowance` if it exceeds the minimum threshold. This determines whether the user needs to approve more tokens before transacting. + +```typescript +const [hasAllowance, setHasAllowance] = useState(false); + +const checkAllowance = async () => { + try { + const allowance = await client.readContract({ + abi: parseAbi(['function allowance(address owner, address spender) returns (uint256)']), + address: cbBtcAddress, + functionName: 'allowance', + args: [account.address, paymasterAddressMainnet], + }); + console.log('allowance: ', allowance); + + setHasAllowance(allowance >= minTokenThreshold); + return allowance >= minTokenThreshold; + } catch (error) { + console.error('Error checking allowance:', error); + return false; + } +}; +``` + +This function ensures that users have sufficient tokens approved for gas payments before proceeding with any transaction. + +### Update the Mint Function + +To enable ERC-20 gas payments, the `handleMint` function must be enhanced to include two key steps. First, the function needs to approve the token for Paymaster use by calling the `approve` function. This ensures that the Paymaster is authorized to spend the user’s tokens for gas payments. + +Second, the function must include the `mintTo` call, which executes the NFT minting process. These actions are bundled into a `contracts` array, and the `writeContracts` function is used to execute them sequentially. This approach streamlines the process, allowing users to approve tokens and mint NFTs in one seamless operation. + +### Add the Mint Button + +Finally, update your component to include a button that triggers the `handleMint` function. This button will either connect the user's wallet or execute the mint process, depending on their connection status. + +```tsx + +``` + +![mint-with-cbbtc](../../assets/images/paymaster-tutorials/mint-cbbtc.png) + +## Verify the Transactions + +After minting, verify the gas payments and NFT minting on a block explorer like [Basescan](https://basescan.org/). Transactions will appear under the **Token Transfers (ERC-20)** tab for the receiving address. + +![basescan-transaction-page](../../assets/images/paymaster-tutorials/basescan-token-transfer.png) + +## Conclusion + +Congratulations! You’ve successfully integrated ERC-20 token-based gas payments into your application using the Coinbase Paymaster. By enabling users to pay for gas fees with tokens like `cbBTC`, you’ve significantly enhanced the onboarding experience and aligned your application’s functionality with its ecosystem token. + +This tutorial demonstrated how to request token approval, configure Paymaster gas policies, and implement the necessary functions and hooks in your project. With this setup, your application now offers a seamless and user-friendly experience that abstracts away native token dependencies. + +Next, explore further customization options for Paymaster policies to tailor your application’s transaction flow and improve user engagement. Happy building! + +--- + +[token allowance]: https://help.coinbase.com/en/wallet/security/dapp-permissions-token-approvals +[this written guide]: https://docs.base.org/tutorials/gasless-transaction-on-base-using-a-paymaster/ +[YouTube walkthrough]: https://www.youtube.com/watch?v=2HemR6jziZ0 +[smart wallets]: https://www.smartwallet.dev/why diff --git a/apps/base-docs/tutorials/docs/2_paymaster-sponsor-using-wagi.md b/apps/base-docs/tutorials/docs/2_paymaster-sponsor-using-wagi.md new file mode 100644 index 0000000000..63caa1fc9c --- /dev/null +++ b/apps/base-docs/tutorials/docs/2_paymaster-sponsor-using-wagi.md @@ -0,0 +1,383 @@ +--- +title: How to Implement Base Paymaster into a Wagmi Project +slug: /implement-base-paymaster-wagmi +description: 'A tutorial to create a Mint button for free NFT minting with Base Paymaster sponsorship' +author: hughescoin +keywords: ['Base Paymaster', 'NFT', 'Wagmi', 'WalletConnect', 'Coinbase Wallet'] +tags: ['smart wallets', 'NFT minting', 'Wagmi integration'] +difficulty: beginner +displayed_sidebar: null +--- + +# How to Implement Base Paymaster into a Wagmi Project + +In this tutorial, we’ll create a **Mint** button that allows users to mint an NFT for free through transaction sponsorship from a **Base Paymaster**. This setup enables users to mint NFTs directly to their wallets without incurring gas fees. By the end, you’ll have a fully functional NFT minting setup with transaction sponsorship via the Base Paymaster. Let's build! + +## Objectives + +- **Configure Wagmi for the Base Network** + Set up your Wagmi project to seamlessly interact with the Base blockchain, allowing users to connect their wallets and initiate transactions with ease. + +- **Define Essential Constants** + Learn how to manage key information such as contract ABIs and addresses, which are crucial for interacting with smart contracts in your application. + +- **Implement Paymaster-Sponsored NFT Minting** + Update onchain actions using Wagmi's `writeContracts` and `useCalls` hooks to enable gas-free NFT minting, allowing users to mint directly to their wallets without incurring transaction fees. + +- **Enhance User Experience with Gasless Transactions** + Create a user-friendly experience by abstracting away the concept of gas fees, making it easier for users to engage with your application and mint NFTs. + +## Prerequisites + +### Wallet Connect Project ID + +You’ll need to set up a cloud account with [Reown] (FKA, WalletConnect), a protocol that enables secure wallet connections across different platforms. + +### Base Paymaster + Bundler Endpoint + +You'll need to set up an account (free) with the [Coinbase Developer Platform (CDP)](https://www.coinbase.com/cloud) to obtain a Paymaster + Bundler endpoint, which is required for this tutorial. The CDP provides these essential services that enable transaction sponsorship. + +### Smart Wallet + +Smart Wallets enables users to create an account in seconds with no app or extension required through the use of Passkey signing. This tutorial uses the [Base Wallet] (FKA Coinbase Smart Wallet) to sign and mint transactions. + +--- + +## Set Up Your Project + +### Create a New Wagmi Project + +Start by creating a new Wagmi project with Bun: + +```bash +bun create wagmi +``` + +### Add WalletConnect Project ID + +Add your WalletConnect Project ID to the .env file to enable wallet connection in the app. Open the .env file and add the following lines: + +``` +NEXT_PUBLIC_WC_PROJECT_ID= +NEXT_TELEMETRY_DISABLED=1 +``` + +Replace`` with your actual WalletConnect Project ID. + +### Update Wagmi Configuration + +### Configure Wagmi for Base Network To integrate the Base network with Wagmi, update `wagmi.ts` as follows: + +```ts +import { http, cookieStorage, createConfig, createStorage } from 'wagmi'; +import { base } from 'wagmi/chains'; +import { coinbaseWallet, injected, walletConnect } from 'wagmi/connectors'; + +export function getConfig() { + return createConfig({ + chains: [base], + connectors: [ + injected(), + coinbaseWallet(), + walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID }), + ], + storage: createStorage({ + storage: cookieStorage, + }), + ssr: true, + transports: { + [base.id]: http(), + }, + }); +} + +declare module 'wagmi' { + interface Register { + config: ReturnType; + } +} +``` + +This configuration sets up your project to connect to the Base network and supports multiple connectors, including WalletConnect. + +### Create utils.ts for Contract ABI and Address + +Create a new file `utils.ts` in the `src` folder. This file will store the contract’s ABI and address. + +**`src/utils.ts`** + +```ts +// utils.js + +import { Abi } from 'viem'; + +export const contractAddress = '0x83bd615eb93ee1336aca53e185b03b54ff4a17e8' as `0x${string}`; + +export const abi = [ + { + type: 'constructor', + inputs: [ + { name: '_name', type: 'string', internalType: 'string' }, + { name: '_symbol', type: 'string', internalType: 'string' }, + ], + stateMutability: 'nonpayable', + }, + // ABI code here +] as Abi; +``` + +Replace the contract address and ABI as per your contract’s details. + +## Create the NFT Minting Page + +In this step, we’ll create a new page in our project where users can mint an NFT. The minting page will use Wagmi’s hooks, including [`useCapabilities`][useCapabilities] to check the capabilities supported by the connected wallet and [`useWriteContracts`][useWriteContracts] to execute a mint function on our smart contract. + +### Set Up `mint/page.tsx` + +In your project’s `src/app` folder, create a new file called `mint/page.tsx`. This file will contain the code to manage wallet connection, check for paymaster capabilities, and execute the minting action. + +:::info Experimental Hooks and Capabilities + +To ensure a smooth, gas-free NFT minting experience, it’s important to understand the purpose of two key hooks from Wagmi: + +- **[`useCapabilities`][useCapabilities]:** This hook retrieves the list of capabilities (such as `paymasterService`) supported by the connected wallet, grouped by chain ID. This is crucial because we need to confirm that the connected wallet supports paymaster sponsorship, which allows transactions to be sponsored by a third party (in this case, Base Paymaster). + +- **[`useWriteContracts`][useWriteContracts]:** This hook allows us to interact with smart contracts on the blockchain. Specifically, we’ll use it to trigger the `mintTo` function, which will mint an NFT to the user’s wallet. + +By combining these hooks, we can detect whether the user’s wallet is capable of sponsored transactions and, if so, use the `writeContracts` function to mint an NFT without charging the user any gas fees. + +::: + +### Add the Code for NFT Minting + +**For Wallet Connection:** +We use useAccount, useConnect, and useDisconnect to manage wallet connection. This allows users to connect via Coinbase Smart Wallet and disconnect as needed. + +```tsx + +'use client'; +import { useAccount, useConnect, useDisconnect } from 'wagmi'; +import { useState, useMemo } from 'react'; +import { coinbaseWallet } from 'wagmi/connectors'; +import { abi, contractAddress } from '../utils'; +import { useCapabilities, useWriteContracts } from 'wagmi/experimental'; + +export default function Home() { + const { address, isConnected } = useAccount(); + const { connect } = useConnect(); + const { disconnect } = useDisconnect(); + const [isMinting, setIsMinting] = useState(false); + const [id, setId] = useState(undefined); + + // Follow along for more code ... +``` + +**Capabilities Check with `useCapabilities`:** +Using `useCapabilities`, we retrieve the wallet’s supported capabilities, grouped by chain ID. In this example, we’re checking if the wallet has the `paymasterService` capability, which indicates it can use a Base Paymaster for gas-free transactions. If paymaster service is supported, we configure the capabilities object to include the Base Paymaster URL. + +```tsx +// Retrieve wallet capabilities to check for paymaster support +const { data: availableCapabilities } = useCapabilities({ + account: address, +}); +const capabilities = useMemo(() => { + if (!availableCapabilities || !address) return {}; + const capabilitiesForChain = availableCapabilities[address.chainId]; + if ( + capabilitiesForChain['paymasterService'] && + capabilitiesForChain['paymasterService'].supported + ) { + return { + paymasterService: { + url: `https://api.developer.coinbase.com/rpc/v1/base/rcNfIncd3jL3FztkZ7TPOV_sfHUGlcVP`, + }, + }; + } + return {}; +}, [availableCapabilities, address]); +``` + +**Minting Logic with `useWriteContracts`:** +We use `useWriteContracts` to interact with the smart contract and call the mintTo function, which mints the NFT. By passing capabilities, the transaction is sponsored by the Base Paymaster, covering gas fees for the user. + +The Mint button will either prompt the user to connect their wallet (if not connected), or execute the handleMint function to mint an NFT (if connected). During the minting process, the button shows “Minting…” to indicate the ongoing transaction. + +The full `src/app/mint/page.tsx` file should look something like this: + +:::tip Smart Wallet Only + +To enable [Base Wallet] functionality add the `smartWalletOnly` preference to the [wagmi connector] + +```jsx + + )} + + + + ); +} +``` + +This component detects if a wallet is connected, then allows users to mint an NFT. If no wallet is detected, it prompts the user to connect via the Coinbase Smart Wallet. + +### Testing + +Start your development server to test the minting functionality: + +```bash +bun run dev +``` + +Open your browser and navigate to your site’s local URL: + +```bash + +http://localhost:3000/mint +``` + +![image-of-server](../../assets/images/paymaster-tutorials/connect-wallet-mint-page.png) + +**Connect Your Wallet and Mint** +Once on the mint page, connect your wallet. You should see a Mint button appear. Upon clicking the Mint button, a smart wallet popup will prompt you to confirm the mint transaction. + +![image-of-mint-modal](../../assets/images/paymaster-tutorials/sponsored_mint_nft.png) + +## Verify Your NFT + +After minting, you can verify the NFT in your Base Wallet: + +Go to [Coinbase Wallet](https://wallet.coinbase.com/). + +Navigate to the **Assets** section and select the [**NFT** tab](https://wallet.coinbase.com/assets/nft). + +![smart-wallet-home](../../assets/images/paymaster-tutorials/wallet-home.png) + +You should see your newly minted NFT in your collection. + +![smart-wallet-assets](../../assets/images/paymaster-tutorials/wallet-nft-page.png) + +## Conclusion + +Congratulations! You’ve successfully integrated a Base Paymaster to enable gas-free NFT minting within your Wagmi project. By configuring your project with Base network support, defining contract details, and using Wagmi hooks for minting, you’ve created a user-friendly, gasless minting experience. Now your users can mint NFTs without transaction costs, enhancing both accessibility and engagement with your app. + +Happy building! + +--- + +[OnchainKit]: https://github.com/coinbase/onchainkit +[Viem]: https://viem.sh/ +[Smart Wallets]: https://keys.coinbase.com/onboarding +[viem]: https://viem.sh/docs/introduction +[react hooks]: https://react.dev/reference/react/hooks +[Onramp config page]: https://portal.cdp.coinbase.com/products/onramp +[official documentation]: https://react.dev/ +[useWriteContracts]: https://wagmi.sh/react/api/hooks/useWriteContract +[useCapabilities]: https://wagmi.sh/react/api/hooks/useCapabilities +[wagmi connector]: https://wagmi.sh/core/api/actions/connect#connect +[Base Wallet]: https://www.smartwallet.dev/ 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..f1f42d7678 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 @@ -64,7 +64,7 @@ You can select any frame from the available options. For this tutorial, we’ll Click on the dropdown menu to select the "Pay Me" Frame. -![frame-payme-](../../assets/images/basenames-tutorial/show-preview.png) +![frame-payme](../../assets/images/basenames-tutorial/show-preview.png) ## Preview the Frame diff --git a/apps/base-docs/tutorials/docs/5_cross-chain-with-ccip.md b/apps/base-docs/tutorials/docs/5_cross-chain-with-ccip.md index f1b2d0b288..76e98f9aff 100644 --- a/apps/base-docs/tutorials/docs/5_cross-chain-with-ccip.md +++ b/apps/base-docs/tutorials/docs/5_cross-chain-with-ccip.md @@ -66,7 +66,7 @@ The ETH is required for covering gas fees associated with deploying smart contra - To fund your wallet with ETH on Base Goerli, visit a faucet listed on the [Base Faucets](https://docs.base.org/tools/network-faucets) page. - To fund your wallet with ETH on Optimism Goerli, visit a faucet listed on the [Optimism Faucets](https://docs.optimism.io/builders/tools/faucets) page. -- To fund your wallet with LINK, visit the [Chainlink Faucet](https://faucets.chain.link/base-testnet). +- To fund your wallet with LINK, visit the [Chainlink Faucet](https://faucets.chain.link/base-sepolia). :::info 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 4784503feb..946a612e1b 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 @@ -67,7 +67,7 @@ The ETH is required for covering gas fees associated with deploying smart contra LayerZero is an interoperability protocol that allows developers to build applications (and tokens) that can connect to multiple blockchains. LayerZero defines these types of applications as "omnichain" applications. -The LayerZero protocol is made up of immutable on-chain [Endpoints](https://docs.layerzero.network/explore/layerzero-endpoint), a configurable [Security Stack](https://docs.layerzero.network/explore/decentralized-verifier-networks), and a permissionless set of [Executors](https://docs.layerzero.network/explore/executors) that transfer messages between chains. +The LayerZero protocol is made up of immutable on-chain [Endpoints](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts), a configurable [Security Stack](https://docs.layerzero.network/explore/decentralized-verifier-networks), and a permissionless set of [Executors](https://docs.layerzero.network/v2/home/permissionless-execution/executors) that transfer messages between chains. ### High-level concepts @@ -81,7 +81,7 @@ The [Security Stack](https://docs.layerzero.network/explore/decentralized-verifi #### Executors -[Executors](https://docs.layerzero.network/explore/executors) are responsible for initiating message delivery. They will automatically execute the `lzReceive` function of the endpoint on the destination chain once a message has been verified by the Security Stack. +[Executors](https://docs.layerzero.network/v2/home/permissionless-execution/executors) are responsible for initiating message delivery. They will automatically execute the `lzReceive` function of the endpoint on the destination chain once a message has been verified by the Security Stack. --- @@ -149,7 +149,7 @@ remappings = [ ## Getting started with LayerZero -LayerZero provides a smart contract standard called [OApp](https://docs.layerzero.network/contracts/oapp) that is intended for omnichain messaging and configuration. +LayerZero provides a smart contract standard called [OApp](https://docs.layerzero.network/v2/developers/evm/oapp/overview) that is intended for omnichain messaging and configuration. ```solidity // SPDX-License-Identifier: MIT @@ -180,17 +180,17 @@ To get started using LayerZero, developers simply need to inherit from the [OApp - `_lzSend`: A function used to send an omnichain message - `_lzReceive`: A function used to receive an omnichain message -In this tutorial, you will be implementing the [OApp](https://docs.layerzero.network/contracts/oapp) standard into your own project to add the capability to send messages from a smart contract on Base to a smart contract on Optimism. +In this tutorial, you will be implementing the [OApp](https://docs.layerzero.network/v2/developers/evm/oapp/overview) standard into your own project to add the capability to send messages from a smart contract on Base to a smart contract on Optimism. :::info -An extension of the [OApp](https://docs.layerzero.network/contracts/oapp) contract standard known as [OFT](https://docs.layerzero.network/contracts/oft) is also available for supporting omnichain fungible token transfers. +An extension of the [OApp](https://docs.layerzero.network/v2/developers/evm/oapp/overview) contract standard known as [OFT](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) is also available for supporting omnichain fungible token transfers. ::: :::info -For more information on transferring tokens across chains using LayerZero, visit the [LayerZero documentation](https://docs.layerzero.network/contracts/oft). +For more information on transferring tokens across chains using LayerZero, visit the [LayerZero documentation](https://docs.layerzero.network/v2/developers/evm/oft/quickstart). ::: @@ -215,18 +215,18 @@ 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. ::: ### Implementing message sending (`_lzSend`) -To send messages to another chain, your smart contract must call the `_lzSend` function inherited from the [OApp](https://docs.layerzero.network/contracts/oapp) contract. +To send messages to another chain, your smart contract must call the `_lzSend` function inherited from the [OApp](https://docs.layerzero.network/v2/developers/evm/oapp/overview) contract. Add a new custom function named `sendMessage` to your smart contract that has the following content: @@ -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 @@ -302,7 +302,7 @@ Your contract’s `estimateFee` function should always be called immediately bef ### Implementing message receiving (`_lzReceive`) -To receive messages on the destination chain, your smart contract must override the `_lzReceive` function inherited from the [OApp](https://docs.layerzero.network/contracts/oapp) contract. +To receive messages on the destination chain, your smart contract must override the `_lzReceive` function inherited from the [OApp](https://docs.layerzero.network/v2/developers/evm/oapp/overview) contract. Add the following code snippet to your `ExampleContract` contract to override the `_lzReceive` function: @@ -335,8 +335,8 @@ The overridden `_lzReceive` function receives the following arguments when recei | `_origin` | `Origin` | The origin information containing the source endpoint and sender address. | | `_guid` | `bytes32` | The unique identifier for the received LayerZero message. | | `payload` | `bytes` | The payload of the received message (encoded). | -| `_executor` | `address` | The `address` of the [Executor](https://docs.layerzero.network/explore/executors) for the received message. | -| `_extraData ` | `bytes` | Additional arbitrary data provided by the corresponding [Executor](https://docs.layerzero.network/explore/executors). | +| `_executor` | `address` | The `address` of the [Executor](https://docs.layerzero.network/v2/home/permissionless-execution/executors) for the received message. | +| `_extraData ` | `bytes` | Additional arbitrary data provided by the corresponding [Executor](https://docs.layerzero.network/v2/home/permissionless-execution/executors). | Note that the overridden method decodes the message payload, and stores the string into a variable named `data` that you can read from later to fetch the latest message. @@ -354,7 +354,7 @@ contract ExampleContract is OApp { :::info -Overriding the `_lzReceive` function allows you to provide any custom logic you wish when receiving messages, including making a call back to the source chain by invoking `_lzSend`. Visit the LayerZero [Message Design Patterns](https://docs.layerzero.network/contracts/message-design-patterns) for common messaging flows. +Overriding the `_lzReceive` function allows you to provide any custom logic you wish when receiving messages, including making a call back to the source chain by invoking `_lzSend`. Visit the LayerZero [Message Design Patterns](https://docs.layerzero.network/v2/developers/evm/oapp/message-design-patterns) for common messaging flows. ::: @@ -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/explore/executors) pays for message delivery, the order of message execution, or dropping an amount of gas to a destination address. +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_deploy-with-fleek.md b/apps/base-docs/tutorials/docs/5_deploy-with-fleek.md index 7351ec0d59..ff819792f9 100644 --- a/apps/base-docs/tutorials/docs/5_deploy-with-fleek.md +++ b/apps/base-docs/tutorials/docs/5_deploy-with-fleek.md @@ -42,7 +42,7 @@ The tutorial assumes you're comfortable with the basics of deploying an app and You can skip this section if you've already built an app based off the template, such as our tutorial for [How to Mint on Zora with an App]. -Open [Onchain App Template], click the green `Use this template` button, and create a new repository from the template. Clone your repo and open it in an editor. +Open [Onchain App Template], click the green `Use this template` button, and create a new repository from the template. Clone your repo and open it in an editor. Install _bun_ if you need to, and install dependencies. @@ -113,7 +113,7 @@ Then, **in the root of your project** run: fleek login ``` -Click the link in your terminal, then click `Confirm` in the web page that opens up. Once your are connected, click the `Visit Dashboard` button. The site automatically creates a project called `First Project`. If you'd like, you can rename it, or add a new one. +Click the link in your terminal, then click `Confirm` in the web page that opens up. Once you are connected, click the `Visit Dashboard` button. The site automatically creates a project called `First Project`. If you'd like, you can rename it, or add a new one. Each project can include more than one site. 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..f5ec9dad5c 100644 --- a/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md +++ b/apps/base-docs/tutorials/docs/5_oracles-supra-vrf.md @@ -78,7 +78,7 @@ Supra dVRF V2 requires subscription to the service with a customer controlled wa Therefore you must register your wallet with the Supra team if you plan to consume Supra dVRF V2 within your smart contracts. -Please refer to the [Supra documentation](https://supraoracles.com/docs/vrf/vrf-subscription-model-v2) for the latest steps on how to register your wallet for their service. +Please refer to the [Supra documentation](https://docs.supra.com/oracles/dvrf/vrf-subscription-model) for the latest steps on how to register your wallet for their service. ::: @@ -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/pages/503.tsx b/apps/bridge/pages/503.tsx index 76269addeb..d2fab19ace 100644 --- a/apps/bridge/pages/503.tsx +++ b/apps/bridge/pages/503.tsx @@ -20,7 +20,7 @@ export default memo(function ServerError() {
-

Error has occured

+

Error has occurred

We encountered a problem with our servers. Please try refreshing. diff --git a/apps/bridge/pages/api/tos.ts b/apps/bridge/pages/api/tos.ts index be54946c8d..2d7316c983 100644 --- a/apps/bridge/pages/api/tos.ts +++ b/apps/bridge/pages/api/tos.ts @@ -1,36 +1,38 @@ import type { NextApiRequest, NextApiResponse } from 'next'; +// Array of two-letter country codes of European Union members (according to ISO 3166-1 alpha-2) const EU_COUNTRIES = [ - 'AT', - 'BE', - 'BG', - 'CY', - 'CZ', - 'DE', - 'DK', - 'EE', - 'ES', - 'FI', - 'FR', - 'GB', - 'GR', - 'HU', - 'HR', - 'IE', - 'IT', - 'LT', - 'LU', - 'LV', - 'MT', - 'NL', - 'PL', - 'PT', - 'RO', - 'SE', - 'SI', - 'SK', + 'AT', // Austria + 'BE', // Belgium + 'BG', // Bulgaria + 'CY', // Cyprus + 'CZ', // Czech Republic + 'DE', // Germany + 'DK', // Denmark + 'EE', // Estonia + 'ES', // Spain + 'FI', // Finland + 'FR', // France + 'GB', // United Kingdom + 'GR', // Greece + 'HU', // Hungary + 'HR', // Croatia + 'IE', // Ireland + 'IT', // Italy + 'LT', // Lithuania + 'LU', // Luxembourg + 'LV', // Latvia + 'MT', // Malta + 'NL', // Netherlands + 'PL', // Poland + 'PT', // Portugal + 'RO', // Romania + 'SE', // Sweden + 'SI', // Slovenia + 'SK', // Slovakia ]; + export default function handler(req: NextApiRequest, res: NextApiResponse) { const country = res.getHeader('x-cf-country') as string; const tosRegion = EU_COUNTRIES.includes(country) ? 'EU' : 'US'; diff --git a/apps/bridge/src/components/Nav/DesktopNav.tsx b/apps/bridge/src/components/Nav/DesktopNav.tsx index ede91f5bca..df4621cf64 100644 --- a/apps/bridge/src/components/Nav/DesktopNav.tsx +++ b/apps/bridge/src/components/Nav/DesktopNav.tsx @@ -119,7 +119,7 @@ function IconLink({ function DesktopNav({ color }: DesktopNavProps) { return ( -
+
>( - // 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/.gitignore b/apps/web/.gitignore new file mode 100644 index 0000000000..e985853ed8 --- /dev/null +++ b/apps/web/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/apps/web/app/(base-org)/(root)/page.tsx b/apps/web/app/(base-org)/(root)/page.tsx index 679adf60ee..eae30c1862 100644 --- a/apps/web/app/(base-org)/(root)/page.tsx +++ b/apps/web/app/(base-org)/(root)/page.tsx @@ -12,27 +12,23 @@ import TransactionsFeesSection from 'apps/web/src/components/base-org/root/Trans import BuildAndRewardSection from 'apps/web/src/components/base-org/root/BuildAndRewardSection'; import ErrorsProvider from 'apps/web/contexts/Errors'; import BlogSection from 'apps/web/src/components/base-org/root/BlogSection'; -import dynamic from 'next/dynamic'; import Link from 'apps/web/src/components/Link'; import MissionSection from 'apps/web/src/components/base-org/root/MissionSection'; import OpLogo from 'apps/web/public/images/op_logo.svg'; - -const DynamicThreeHero = dynamic(async () => import('apps/web/src/components/ThreeHero'), { - ssr: false, -}); +import SceneDynamic from 'apps/web/src/components/ThreeHero/dynamic'; export default async function Home() { return (
- +
Base is for everyone.
- + diff --git a/apps/web/app/(base-org)/build/page.tsx b/apps/web/app/(base-org)/build/page.tsx new file mode 100644 index 0000000000..04c33811ee --- /dev/null +++ b/apps/web/app/(base-org)/build/page.tsx @@ -0,0 +1,38 @@ +import type { Metadata } from "next"; +import AnalyticsProvider from "../../../contexts/Analytics"; +import Hero from "../../../src/components/GetStarted/Hero"; +import Essentials from "../../../src/components/GetStarted/Essentials"; +import Funding from "../../../src/components/GetStarted/Funding"; +import GetNoticed from "../../../src/components/GetStarted/GetNoticed"; +import GetInvolved from "apps/web/src/components/GetStarted/GetInvolved"; +import StartBuilding from "../../../src/components/GetStarted/StartBuilding"; +import BuildWithUsFooter from "../../../src/components/GetStarted/BuildWithUsFooter"; +import Container from "apps/web/src/components/base-org/Container"; + +export const metadata: Metadata = { + metadataBase: new URL("https://base.org"), + title: "Base | Build", + openGraph: { + title: "Base | Build", + url: "/build", + images: ["https://base.org/images/getstarted-open-graph.png"], + }, +}; + +export default async function GoToCommunity() { + return ( + + + +
+ + + + + + +
+
+
+ ); +} diff --git a/apps/web/app/(base-org)/builder-anniversary-nft/page.tsx b/apps/web/app/(base-org)/builder-anniversary-nft/page.tsx index 80efceb319..355dfc619e 100644 --- a/apps/web/app/(base-org)/builder-anniversary-nft/page.tsx +++ b/apps/web/app/(base-org)/builder-anniversary-nft/page.tsx @@ -1,3 +1,4 @@ +import CryptoProviders from 'apps/web/app/CryptoProviders'; import { BuilderNftHero } from 'apps/web/src/components/BuilderNft/BuilderNftHero'; import type { Metadata } from 'next'; @@ -13,7 +14,9 @@ export const metadata: Metadata = { export default async function About() { return (
- + + +
); } diff --git a/apps/web/app/(base-org)/ecosystem/page.tsx b/apps/web/app/(base-org)/ecosystem/page.tsx index c7569c6a16..d7bb9dc62f 100644 --- a/apps/web/app/(base-org)/ecosystem/page.tsx +++ b/apps/web/app/(base-org)/ecosystem/page.tsx @@ -1,4 +1,5 @@ import type { Metadata } from 'next'; +import { Suspense } from 'react'; import Content from 'apps/web/src/components/Ecosystem/Content'; import Container from 'apps/web/src/components/base-org/Container'; import Button from 'apps/web/src/components/base-org/Button'; @@ -30,8 +31,8 @@ async function EcosystemHero() { return (
-
-
+
+
Base ecosystem apps and integrations overview. @@ -39,11 +40,13 @@ async function EcosystemHero() { href="https://github.com/base-org/web?tab=readme-ov-file#updating-the-base-ecosystem-page" target="_blank" rel="noreferrer noopener" + className="max-w-fit" + tabIndex={-1} // Prevents focus on anchor (want to focus on button) >
-
+
{topKeys.map((key, i) => (
@@ -78,7 +81,9 @@ export default async function Ecosystem() { - + }> + + ); diff --git a/apps/web/app/(base-org)/getstarted/page.tsx b/apps/web/app/(base-org)/getstarted/page.tsx deleted file mode 100644 index 132ecbaffb..0000000000 --- a/apps/web/app/(base-org)/getstarted/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import type { Metadata } from 'next'; -import AnalyticsProvider from '../../../contexts/Analytics'; -import Hero from '../../../src/components/GetStarted/Hero'; -import Essentials from '../../../src/components/GetStarted/Essentials'; -import Funding from '../../../src/components/GetStarted/Funding'; -import GetNoticed from '../../../src/components/GetStarted/GetNoticed'; -import GetInvolved from 'apps/web/src/components/GetStarted/GetInvolved'; -import StartBuilding from '../../../src/components/GetStarted/StartBuilding'; -import BuildWithUsFooter from '../../../src/components/GetStarted/BuildWithUsFooter'; -import Container from 'apps/web/src/components/base-org/Container'; - -export const metadata: Metadata = { - metadataBase: new URL('https://base.org'), - title: `Base | Get Started`, - openGraph: { - title: `Base | Get Started`, - url: '/getstarted', - images: ['https://base.org/images/getstarted-open-graph.png'], - }, -}; - -export default async function GoToCommunity() { - return ( - - - -
- - - - - - -
-
-
- ); -} diff --git a/apps/web/app/(base-org)/jobs/page.tsx b/apps/web/app/(base-org)/jobs/page.tsx index 39593fdb20..d992386006 100644 --- a/apps/web/app/(base-org)/jobs/page.tsx +++ b/apps/web/app/(base-org)/jobs/page.tsx @@ -15,8 +15,13 @@ export const metadata: Metadata = { }, }; +// Revalidate every 30 minutes +export const revalidate = 60 * 30; + async function getJobs() { - const res = await fetch(`${greenhouseApiUrl}/boards/basejobs/jobs?content=true`); + const res = await fetch(`${greenhouseApiUrl}/boards/basejobs/jobs?content=true`, { + next: { revalidate }, + }); try { const { jobs } = (await res.json()) as { jobs: JobType[] }; return jobs; 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)/api/basenames/getUsernames/route.ts b/apps/web/app/(basenames)/api/basenames/getUsernames/route.ts new file mode 100644 index 0000000000..b1baae10cf --- /dev/null +++ b/apps/web/app/(basenames)/api/basenames/getUsernames/route.ts @@ -0,0 +1,29 @@ +import { NextRequest, NextResponse } from 'next/server'; + +import type { ManagedAddressesResponse } from 'apps/web/src/types/ManagedAddresses'; + +export async function GET(request: NextRequest) { + const address = request.nextUrl.searchParams.get('address'); + if (!address) { + return NextResponse.json({ error: 'No address provided' }, { status: 400 }); + } + + const network = request.nextUrl.searchParams.get('network') ?? 'base-mainnet'; + if (network !== 'base-mainnet' && network !== 'base-sepolia') { + return NextResponse.json({ error: 'Invalid network provided' }, { status: 400 }); + } + + const response = await fetch( + `https://api.cdp.coinbase.com/platform/v1/networks/${network}/addresses/${address}/identity?limit=50`, + { + headers: { + Authorization: `Bearer ${process.env.CDP_BEARER_TOKEN}`, + 'Content-Type': 'application/json', + }, + }, + ); + + const data = (await response.json()) as ManagedAddressesResponse; + + return NextResponse.json(data, { status: 200 }); +} diff --git a/apps/web/app/(basenames)/layout.tsx b/apps/web/app/(basenames)/layout.tsx index 493d746931..87db756f35 100644 --- a/apps/web/app/(basenames)/layout.tsx +++ b/apps/web/app/(basenames)/layout.tsx @@ -1,3 +1,4 @@ +import CryptoProviders from 'apps/web/app/CryptoProviders'; import ErrorsProvider from 'apps/web/contexts/Errors'; import UsernameNav from 'apps/web/src/components/Layout/UsernameNav'; @@ -27,10 +28,12 @@ export default async function BasenameLayout({ }) { return ( -
- - {children} -
+ +
+ + {children} +
+
); } diff --git a/apps/web/app/(basenames)/manage-names/page.tsx b/apps/web/app/(basenames)/manage-names/page.tsx new file mode 100644 index 0000000000..1aec6958aa --- /dev/null +++ b/apps/web/app/(basenames)/manage-names/page.tsx @@ -0,0 +1,32 @@ +import ErrorsProvider from 'apps/web/contexts/Errors'; +import type { Metadata } from 'next'; +import { initialFrame } from 'apps/web/pages/api/basenames/frame/frameResponses'; +import NamesList from 'apps/web/src/components/Basenames/ManageNames/NamesList'; + +export const metadata: Metadata = { + metadataBase: new URL('https://base.org'), + title: `Basenames`, + description: + 'Basenames are a core onchain building block that enables anyone to establish their identity on Base by registering human-readable names for their address(es). They are a fully onchain solution which leverages ENS infrastructure deployed on Base.', + openGraph: { + title: `Basenames`, + url: `/manage-names`, + }, + twitter: { + site: '@base', + card: 'summary_large_image', + }, + other: { + ...(initialFrame as Record), + }, +}; + +export default async function Page() { + return ( + +
+ +
+
+ ); +} diff --git a/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx b/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx index d63dfe2dbc..2339e9d17f 100644 --- a/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx +++ b/apps/web/app/(basenames)/name/[username]/ProfileProviders.tsx @@ -1,6 +1,6 @@ 'use client'; -import { BaseName } from '@coinbase/onchainkit/identity'; +import { Basename } from '@coinbase/onchainkit/identity'; import AnalyticsProvider from 'apps/web/contexts/Analytics'; import UsernameProfileProvider from 'apps/web/src/components/Basenames/UsernameProfileContext'; @@ -9,7 +9,7 @@ const usernameProfileAnalyticContext = 'username_profile'; type ProfileProvidersProps = { children: React.ReactNode; - username: BaseName; + username: Basename; }; export default function ProfileProviders({ children, username }: ProfileProvidersProps) { diff --git a/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx b/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx index 9c3affb6a3..3e2131ea33 100644 --- a/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx +++ b/apps/web/app/(basenames)/name/[username]/configure-frames/page.tsx @@ -1,4 +1,4 @@ -import { BaseName } from '@coinbase/onchainkit/identity'; +import { Basename } from '@coinbase/onchainkit/identity'; import ProfileProviders from 'apps/web/app/(basenames)/name/[username]/ProfileProviders'; import ErrorsProvider from 'apps/web/contexts/Errors'; import FrameBuilder from 'apps/web/src/components/Basenames/ConfigureFramesPageContent/FrameBuilder'; @@ -7,11 +7,11 @@ import { redirectIfNotNameOwner } from 'apps/web/src/utils/redirectIfNotNameOwne import { formatDefaultUsername } from 'apps/web/src/utils/usernames'; export type ConfigureFramesProps = { - params: { username: BaseName }; + params: { username: Basename }; }; export default async function ConfigureFrames({ params }: ConfigureFramesProps) { - let username = await formatDefaultUsername(decodeURIComponent(params.username) as BaseName); + let username = await formatDefaultUsername(decodeURIComponent(params.username) as Basename); await redirectIfNotNameOwner(username); return ( diff --git a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx index bcd0ef107a..47b7500a2b 100644 --- a/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx +++ b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx @@ -7,11 +7,16 @@ import { isDevelopment } from 'apps/web/src/constants'; import { formatBaseEthDomain, getBasenameImage, + getChainForBasename, USERNAME_DOMAINS, + UsernameTextRecordKeys, } from 'apps/web/src/utils/usernames'; import { base, baseSepolia } from 'viem/chains'; import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames'; -import { CLOUDFARE_IPFS_PROXY } from 'apps/web/src/utils/urls'; +import { getIpfsGatewayUrl, IpfsUrl, IsValidIpfsUrl } from 'apps/web/src/utils/urls'; +import { Basename } from '@coinbase/onchainkit/identity'; +import { getCloudinaryMediaUrl } from 'apps/web/src/utils/images'; +import { logger } from 'apps/web/src/utils/logger'; export const runtime = 'edge'; const size = { @@ -63,24 +68,35 @@ export default async function OpenGraphImage(props: ImageRouteProps) { const domainName = isDevelopment ? `http://localhost:3000` : 'https://www.base.org'; const profilePicture = getBasenameImage(username); + 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(base.id); - const avatar = await client.getEnsAvatar({ + const client = getBasenamePublicClient(chain.id); + const avatar = await client.getEnsText({ name: username, - universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[base.id], - assetGatewayUrls: { - ipfs: CLOUDFARE_IPFS_PROXY, - }, + key: UsernameTextRecordKeys.Avatar, + universalResolverAddress: USERNAME_L2_RESOLVER_ADDRESSES[chain.id], }); - // Satori Doesn't support webp - if (avatar && !avatar.endsWith('.webp')) { - imageSource = avatar; + if (avatar) { + // IPFS Resolution + if (IsValidIpfsUrl(avatar)) { + const ipfsUrl = getIpfsGatewayUrl(avatar as IpfsUrl); + if (ipfsUrl) { + imageSource = ipfsUrl; + } + } else { + imageSource = avatar; + } + + // Cloudinary resize / fetch + imageSource = getCloudinaryMediaUrl({ media: imageSource, format: 'png', width: 80 }); } - } catch (error) {} + } catch (error) { + logger.error('Error fetching basename Avatar:', error); + } return new ImageResponse( ( diff --git a/apps/web/app/(basenames)/name/[username]/page.tsx b/apps/web/app/(basenames)/name/[username]/page.tsx index 99a517c41a..8428e78291 100644 --- a/apps/web/app/(basenames)/name/[username]/page.tsx +++ b/apps/web/app/(basenames)/name/[username]/page.tsx @@ -1,7 +1,6 @@ -import { BaseName } from '@coinbase/onchainkit/identity'; +import { Basename } from '@coinbase/onchainkit/identity'; import ProfileProviders from 'apps/web/app/(basenames)/name/[username]/ProfileProviders'; import ErrorsProvider from 'apps/web/contexts/Errors'; -import DynamicProfilePromo from 'apps/web/src/components/Basenames/ProfilePromo/dynamic'; import UsernameProfile from 'apps/web/src/components/Basenames/UsernameProfile'; import { redirectIfNotNameOwner } from 'apps/web/src/utils/redirectIfNotNameOwner'; import { @@ -13,7 +12,7 @@ import classNames from 'classnames'; import { Metadata } from 'next'; export type UsernameProfileProps = { - params: { username: BaseName }; + params: { username: Basename }; }; export async function generateMetadata({ params }: UsernameProfileProps): Promise { @@ -36,11 +35,11 @@ export async function generateMetadata({ params }: UsernameProfileProps): Promis } export default async function Username({ params }: UsernameProfileProps) { - let username = await formatDefaultUsername(decodeURIComponent(params.username) as BaseName); + let username = await formatDefaultUsername(decodeURIComponent(params.username) as Basename); await redirectIfNotNameOwner(username); const usernameProfilePageClasses = classNames( - 'mx-auto mt-32 flex min-h-screen w-full max-w-[1440px] flex-col justify-between gap-10 px-4 px-4 pb-40 md:flex-row md:px-8', + 'mx-auto mt-32 flex min-h-screen w-full max-w-[1440px] flex-col justify-between gap-10 px-4 px-4 pb-16 md:flex-row md:px-8', ); return ( @@ -48,7 +47,6 @@ export default async function Username({ params }: UsernameProfileProps) {
-
diff --git a/apps/web/app/(stats)/layout.tsx b/apps/web/app/(stats)/layout.tsx new file mode 100644 index 0000000000..7baa778472 --- /dev/null +++ b/apps/web/app/(stats)/layout.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + metadataBase: new URL('https://base.org'), + title: `Base`, + description: + 'Base is a secure, low-cost, builder-friendly Ethereum L2 built to bring the next billion users onchain.', + openGraph: { + type: 'website', + title: `Base`, + description: + 'Base is a secure, low-cost, builder-friendly Ethereum L2 built to bring the next billion users onchain.', + url: `/`, + images: ['https://base.org/images/base-open-graph.png'], + }, + twitter: { + site: '@base', + card: 'summary_large_image', + }, +}; + +export default async function StatsLayout({ + children, // will be a page or nested layout +}: { + children: React.ReactNode; +}) { + return ( +
+ {children} +
+ ); +} diff --git a/apps/web/app/(stats)/stats/page.tsx b/apps/web/app/(stats)/stats/page.tsx new file mode 100644 index 0000000000..bfa6a24a23 --- /dev/null +++ b/apps/web/app/(stats)/stats/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + metadataBase: new URL('https://base.org'), + title: `Base | Stats`, + description: 'Live stats for the Base network', +}; + +export default async function Page() { + return ( +