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/.vscode/settings.json b/.vscode/settings.json index ea70eb1c9d..aaca799c8d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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/README.md b/README.md index b82b6dd746..c61cfdd9c7 100644 --- a/README.md +++ b/README.md @@ -86,24 +86,31 @@ If you're a builder who wants to add or update your project on the [Base Ecosyst ```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. 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-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/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..9444062239 100644 --- a/apps/base-docs/base-learn/docs/imports/imports-sbs.md +++ b/apps/base-docs/base-learn/docs/imports/imports-sbs.md @@ -27,7 +27,7 @@ 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. 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/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..82605b02cd 100644 --- a/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md +++ b/apps/base-docs/base-learn/docs/storage/simple-storage-sbs.md @@ -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 simple increments age when called.
diff --git a/apps/base-docs/docs/building-with-base/base-contracts.md b/apps/base-docs/docs/building-with-base/base-contracts.md index 0267e59379..8e2803380a 100644 --- a/apps/base-docs/docs/building-with-base/base-contracts.md +++ b/apps/base-docs/docs/building-with-base/base-contracts.md @@ -108,15 +108,15 @@ Certain contracts are mandatory according to the [OP Stack SDK](https://stack.op | DelayedWETHProxy (FDG) | [0x489c2E5ebe0037bDb2DC039C5770757b8E54eA1F](https://sepolia.etherscan.io/address/0x489c2E5ebe0037bDb2DC039C5770757b8E54eA1F) | | DelayedWETHProxy (PDG) | [0x27A6128F707de3d99F89Bf09c35a4e0753E1B808](https://sepolia.etherscan.io/address/0x27A6128F707de3d99F89Bf09c35a4e0753E1B808) | | DisputeGameFactoryProxy | [0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1](https://sepolia.etherscan.io/address/0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1) | -| FaultDisputeGame | [0x5062792ED6A85cF72a1424a1b7f39eD0f7972a4B](https://sepolia.etherscan.io/address/0x5062792ED6A85cF72a1424a1b7f39eD0f7972a4B) | +| FaultDisputeGame | [0xB7fB44a61fdE2b9DB28a84366e168b14D1a1b103](https://sepolia.etherscan.io/address/0xB7fB44a61fdE2b9DB28a84366e168b14D1a1b103) | | L1CrossDomainMessenger | [0xC34855F4De64F1840e5686e64278da901e261f20](https://sepolia.etherscan.io/address/0xC34855F4De64F1840e5686e64278da901e261f20) | | L1ERC721Bridge | [0x21eFD066e581FA55Ef105170Cc04d74386a09190](https://sepolia.etherscan.io/address/0x21eFD066e581FA55Ef105170Cc04d74386a09190) | | L1StandardBridge | [0xfd0Bf71F60660E2f608ed56e1659C450eB113120](https://sepolia.etherscan.io/address/0xfd0Bf71F60660E2f608ed56e1659C450eB113120) | | L2OutputOracle | [0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254](https://sepolia.etherscan.io/address/0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254) | -| MIPS | [0x47B0E34C1054009e696BaBAAd56165e1e994144d](https://sepolia.etherscan.io/address/0x47B0E34C1054009e696BaBAAd56165e1e994144d) | +| MIPS | [0x69470D6970Cd2A006b84B1d4d70179c892cFCE01](https://sepolia.etherscan.io/address/0x69470D6970Cd2A006b84B1d4d70179c892cFCE01) | | OptimismMintableERC20Factory | [0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37](https://sepolia.etherscan.io/address/0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37) | | OptimismPortal | [0x49f53e41452C74589E85cA1677426Ba426459e85](https://sepolia.etherscan.io/address/0x49f53e41452C74589E85cA1677426Ba426459e85) | -| PermissionedDisputeGame | [0x593D20C4c69485B95D11507239BE2C725ea2A6fD](https://sepolia.etherscan.io/address/0x593D20C4c69485B95D11507239BE2C725ea2A6fD) | +| PermissionedDisputeGame | [0x68f600e592799c16D1b096616eDbf1681FB9c0De](https://sepolia.etherscan.io/address/0x68f600e592799c16D1b096616eDbf1681FB9c0De) | | PreimageOracle | [0x92240135b46fc1142dA181f550aE8f595B858854](https://sepolia.etherscan.io/address/0x92240135b46fc1142dA181f550aE8f595B858854) | | ProxyAdmin | [0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3](https://sepolia.etherscan.io/address/0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3) | | SystemConfig | [0xf272670eb55e895584501d564AfEB048bEd26194](https://sepolia.etherscan.io/address/0xf272670eb55e895584501d564AfEB048bEd26194) | diff --git a/apps/base-docs/docs/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..5af3c8cf7b --- /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/base-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/app-blocklist.md b/apps/base-docs/docs/security/app-blocklist.md index 3f8f29ad37..bff31a0a43 100644 --- a/apps/base-docs/docs/security/app-blocklist.md +++ b/apps/base-docs/docs/security/app-blocklist.md @@ -38,7 +38,7 @@ Ensuring that your app is perceived as trustworthy and not flagged as malicious - **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 / WalletLink or popular browser extension wallets. +- **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. --- diff --git a/apps/base-docs/docs/security/report.md b/apps/base-docs/docs/security/report.md index f67678a92d..506670bbab 100644 --- a/apps/base-docs/docs/security/report.md +++ b/apps/base-docs/docs/security/report.md @@ -22,7 +22,7 @@ hide_table_of_contents: true 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. +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 7bc6621333..e2f5494121 100644 --- a/apps/base-docs/docs/terms-of-service.md +++ b/apps/base-docs/docs/terms-of-service.md @@ -63,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.” @@ -145,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/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..3bf6592781 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,7 +102,7 @@ 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'); +'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/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/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/onboarding.md b/apps/base-docs/docs/tools/onboarding.md index 05dc9f8b70..9d5679a986 100644 --- a/apps/base-docs/docs/tools/onboarding.md +++ b/apps/base-docs/docs/tools/onboarding.md @@ -44,7 +44,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. diff --git a/apps/base-docs/docs/tools/oracles.md b/apps/base-docs/docs/tools/oracles.md index fbb879e55a..affb144a7d 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. 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 4bf6b60c60..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', 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_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_verify-contract-with-basescan.md b/apps/base-docs/tutorials/docs/1_verify-contract-with-basescan.md index c2579c72af..feb8a0d401 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. @@ -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_nft-minting-with-zora.md b/apps/base-docs/tutorials/docs/2_nft-minting-with-zora.md index 4fe08e4119..7ef8727928 100644 --- a/apps/base-docs/tutorials/docs/2_nft-minting-with-zora.md +++ b/apps/base-docs/tutorials/docs/2_nft-minting-with-zora.md @@ -73,7 +73,7 @@ This tutorial won't cover all of the frontend development, auth, databases, or o - Add tokens to that collection - Allow other people to mint the tokens -Begin by opening `src/app/page.tsx` and doing some cleanup. Delete everything expect the wallet integration, and add some copy that is friendly to non-crypto-native users: +Begin by opening `src/app/page.tsx` and doing some cleanup. Delete everything except the wallet integration, and add some copy that is friendly to non-crypto-native users: ```tsx 'use client'; diff --git a/apps/base-docs/tutorials/docs/2_ock-pay-tutorial.md b/apps/base-docs/tutorials/docs/2_ock-checkout-tutorial.md similarity index 84% rename from apps/base-docs/tutorials/docs/2_ock-pay-tutorial.md rename to apps/base-docs/tutorials/docs/2_ock-checkout-tutorial.md index af3b81c93e..5dc83f2dc1 100644 --- a/apps/base-docs/tutorials/docs/2_ock-pay-tutorial.md +++ b/apps/base-docs/tutorials/docs/2_ock-checkout-tutorial.md @@ -1,6 +1,6 @@ --- title: 'Build a eCommerce App using Coinbase Commerce and OnchainKit' -slug: /coinbase-commerce-payment-integration +slug: /coinbase-commerce-onchainkit-checkout description: Learn how to integrate Coinbase Commerce payments into your application using OnchainKit. author: hughescoin keywords: [ @@ -56,7 +56,7 @@ Here, you'll need to add a detailed description of the product or service you're ![pay-commerce-uuid](../../assets/images/onchainkit-tutorials/pay-create-product-details.png) -Once your product is created you will be presented with a small popup that contains a link to your products hosted page. Click on the `View product` button. This will take you to a page with more details about your newly created product. Pay close attention to the URL of this page, as it contains a crucial piece of information: the product's UUID. You'll need to copy this UUID from the URL. +After creating your product, click `View product` in the popup to access the product page and copy the UUID from its URL. ![pay-commerce-uuid](../../assets/images/onchainkit-tutorials/pay-copy-product-link.png) @@ -142,12 +142,12 @@ export const NEXT_PUBLIC_WC_PROJECT_ID = process.env.NEXT_PUBLIC_WC_PROJECT_ID; ## Implementing the Payment Component -To implement the payment component, start by opening the `src/app/page.tsx` file. You'll need to add some new imports at the top of the file: import the `Pay`, `PayButton`, and `PayStatus` components from '@coinbase/onchainkit', as well as the `Image` component from 'next/image'. +To implement the payment component, start by opening the `src/app/page.tsx` file. You'll need to add some new imports at the top of the file: import the `Checkout`, `CheckoutButton`, `CheckoutStatus` components from '@coinbase/onchainkit', as well as the `Image` component from 'next/image'. Next, create a constant for your product ID using the environment variable you set up earlier. This will allow you to easily reference your product in the payment component. ```typescript -import { Pay, PayButton, PayStatus } from '@coinbase/onchainkit'; +import { Checkout, CheckoutButton, CheckoutStatus } from '@coinbase/onchainkit/checkout'; import Image from 'next/image'; const productId = process.env.NEXT_PUBLIC_PRODUCT_ID; @@ -168,7 +168,7 @@ For visual appeal, add an image of your product to the `/public` folder. This im When setting up the payment component, it's important to implement conditional rendering. This ensures that the payment button only appears once the user's wallet is connected. This approach provides a smoother user experience and prevents potential errors from attempting to initiate a payment before a wallet is available. ::: -Finally, configure the Pay component within your JSX. Wrap the `PayButton` and `PayStatus` components inside the `Pay` component, passing your `productId` as a prop to the `Pay` component. Set the `coinbaseBranded` prop on the `PayButton` to true for consistent branding. This setup creates a complete payment flow, allowing users to initiate a payment and view its status all within your application. +Finally, configure the Checkout component within your JSX. Wrap the `CheckoutButton` and `CheckoutStatus` components inside the `Checkout` component, passing your `productId` as a prop to the `Checkout` component. Set the `coinbaseBranded` prop on the `CheckoutButton` to true for consistent branding. This setup creates a complete payment flow, allowing users to initiate a payment and view its status all within your application. ```jsx
@@ -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..d6d2e247b0 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,7 +41,7 @@ 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 @@ -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..456b46b140 --- /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 Passskey 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 Experimenal 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` prefence 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/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..1833d78cf6 100644 --- a/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md +++ b/apps/base-docs/tutorials/docs/5_cross-chain-with-layerzero.md @@ -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. @@ -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/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 ( -
+
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/(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]/opengraph-image.tsx b/apps/web/app/(basenames)/name/[username]/opengraph-image.tsx index bcd0ef107a..eb9f0f744f 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? 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 51c34d33e5..8428e78291 100644 --- a/apps/web/app/(basenames)/name/[username]/page.tsx +++ b/apps/web/app/(basenames)/name/[username]/page.tsx @@ -39,7 +39,7 @@ export default async function Username({ params }: UsernameProfileProps) { 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 ( 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 ( +