# https://docs.base.org llms-full.txt ## Base Documentation [Skip to content](https://docs.base.org/#vocs-content) Menu Overview On this page Chevron Right # Base Documentation Base is a secure, low-cost, builder-friendly Ethereum L2 built to bring the next billion users onchain. Base is incubated within Coinbase and plans to progressively decentralize in the years ahead. We believe that decentralization is critical to creating an open, global cryptocurrency that is accessible to everyone. ## Browse by use cases [**Onboard anyone** \\ \\ Let users sign up and sign in with Smart Wallet — the universal account for the onchain world.](https://docs.base.org/use-cases/onboard-any-user) [**Accept crypto payments** \\ \\ Integrate secure and efficient crypto payment solutions for your applications.](https://docs.base.org/use-cases/accept-crypto-payments) [**Launch AI agents** \\ \\ Build and deploy AI agents that can interact with onchain data and smart contracts.](https://docs.base.org/use-cases/launch-ai-agents) [**Create engaging social experiences** \\ \\ Add decentralized social features in your app for new content and identity.](https://docs.base.org/use-cases/decentralize-social-app) [**DeFi your app** \\ \\ Integrate DeFi protocols and services directly into your applications.](https://docs.base.org/use-cases/defi-your-app) [**Remove first-timer friction** \\ \\ Enable gasless transactions and account abstraction solutions.](https://docs.base.org/use-cases/go-gasless) ## Browse by tools [**OnchainKit** \\ \\ Build an app in 10 minutes with this all-in-one toolkit and full-stack components.](https://docs.base.org/builderkits/onchainkit/getting-started) [**Smart Wallet** \\ \\ A passkey-based universal account to connect with the onchain world.](https://docs.base.org/identity/smart-wallet/quickstart) [**AgentKit** \\ \\ Give every AI agent a crypto wallet and the ability to transact and interact onchain.](https://docs.cdp.coinbase.com/agentkit/docs/welcome) [**Paymaster** \\ \\ Build gasless apps with bundled infrastructure. Start with free credits.](https://docs.cdp.coinbase.com/paymaster/docs/welcome) [**MiniKit** \\ \\ Feature your mini app on Warpcast and Coinbase Wallet with a few lines of code..](https://replit.com/@tina-he/ock-frames-template?v=1#README.md) [**Verifications** \\ \\ Identify high-quality users and build compliant apps with verifiable attestations.](https://docs.cdp.coinbase.com/verifications/docs/welcome) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Onchain App Quickstart [Skip to content](https://docs.base.org/quickstart#vocs-content) Menu Quickstart On this page Chevron Right Welcome to the Base quickstart guide! In this walkthrough, we'll create a simple onchain app from start to finish. Whether you're a seasoned developer or just starting out, this guide has got you covered. ## What You'll Achieve By the end of this quickstart, you'll have built an onchain app by: - Configuring your development environment - Deploying your smart contracts to Base - Interacting with your deployed contracts from the frontend Our simple app will be an onchain tally app which lets you add to a total tally, stored onchain, by pressing a button. ## Set Up Your Development Environment ### Bootstrap with OnchainKit OnchainKit is a library of ready-to-use React components and Typescript utilities for building onchain apps. Run the following command in your terminal and follow the prompts to bootstrap your project. Terminal Terminal ```vocs_Code Copynpm create onchain@latest ``` The prompots will ask you for a CDP API Key which you can get [here](https://portal.cdp.coinbase.com/projects/api-keys/client-key). Once you've gone through the prompts, you'll have a new project directory with a basic OnchainKit app. Run the following to see it live. Terminal Terminal ```vocs_Code Copycd my-onchainkit-app npm install npm run dev ``` You should see the following screen. ![OnchainKit Template](https://docs.base.org/images/onchainkit/quickstart.png) Once we've deployed our contracts, we'll add a button that lets us interact with our contracts. ### Install and initialize Foundry The total tally will be stored onchain in a smart contract. We'll use the Foundry framework to deploy our contract to the Base Sepolia testnet. 1. Create a new "contracts" folder in the root of your project Terminal Terminal ```vocs_Code Copymkdir contracts && cd contracts ``` 2. Install and initialize Foundry Terminal Terminal ```vocs_Code Copycurl -L https://foundry.paradigm.xyz | bash foundryup forge init --no-git ``` Open the project and find the `Counter.sol` contract file in the `/contracts/src` folder. You'll find the simple logic for our tally app. ### Configure Foundry with Base To deploy your smart contracts to Base, you need two key components: 1. A node connection to interact with the Base network 2. A funded private key to deploy the contract Let's set up both of these: - Create a `.env` file in your `contracts` directory and add the Base and Base Sepolia RPC URLs Terminal contracts/.env ```vocs_Code CopyBASE_RPC_URL="https://mainnet.base.org" BASE_SEPOLIA_RPC_URL="https://sepolia.base.org" ``` -Load your environment variables Terminal Terminal ```vocs_Code Copysource .env ``` ### Secure your private key A private key with testnet funds is required to deploy the contract. You can generate a fresh private key [here](https://visualkey.link/). 1. Store your private key in Foundry's secure keystore Terminal Terminal ```vocs_Code Copycast wallet import deployer --interactive ``` 2. When prompted enter your private key and a password. Your private key is stored in `~/.foundry/keystores` which is not tracked by git. ## Deploy Your Contracts Now that your environment is set up, let's deploy your contracts to Base Sepolia. The foundry project provides a deploy script that will deploy the Counter.sol contract. ### Run the deploy script 1. Use the following command to compile and deploy your contract Terminal Terminal ```vocs_Code Copyforge create ./src/Counter.sol:Counter --rpc-url $BASE_SEPOLIA_RPC_URL --account deployer ``` Note the format of the contract being deployed is `:`. ### Save the contract address After successful deployment, the transaction hash will be printed to the console output Copy the deployed contract address and add it to your `.env` file ```vocs_Code CopyCOUNTER_CONTRACT_ADDRESS="0x..." ``` ### Load the new environment variable Terminal Terminal ```vocs_Code Copysource .env ``` ### Verify Your Deployment To ensure your contract was deployed successfully: 1. Check the transaction on [Sepolia Basescan](https://sepolia.basescan.org/). 2. Use the `cast` command to interact with your deployed contract from the command line ```vocs_Code Copycast call $COUNTER_CONTRACT_ADDRESS "number()(uint256)" --rpc-url $BASE_SEPOLIA_RPC_URL ``` This will return the initial value of the Counter contract's `number` storage variable, which will be `0`. **Congratulations! You've deployed your smart contract to Base Sepolia!** Now lets connect the frontend to interact with your recently deployed contract. ## Interacting with your contract To interact with the smart contract logic, we need to submit an onchain transaction. We can do this easily with the `Transaction` component. This is a simplified version of the `Transaction` component, designed to streamline the integration process. Instead of manually defining each subcomponent and prop, we can use this shorthand version which renders our suggested implementation of the component and includes the `TransactionButton` and `TransactionToast` components. ### Add the `Transaction` component Lets add the `Transaction` component to our `page.tsx` file. Delete the existing content in the `main` tag and replace it with the snippet below. File page.tsx ```vocs_Code Copyimport { Transaction } from '@coinbase/onchainkit/transaction'; import { calls } from '@/calls';
; ``` ### Defining the contract calls In the previous code snippet, you'll see we imported `calls` from the `calls.ts` file. This file provides the details needed to interact with our contract and call the `increment` function. Create a new `calls.ts` file in the same folder as your `page.tsx` file and add the following code. File calls.ts ```vocs_Code Copyconst counterContractAddress = '0x...'; // add your contract address here const counterContractAbi = [\ {\ type: 'function',\ name: 'increment',\ inputs: [],\ outputs: [],\ stateMutability: 'nonpayable',\ },\ ] as const; export const calls = [\ {\ address: counterContractAddress,\ abi: counterContractAbi,\ functionName: 'increment',\ args: [],\ },\ ]; ``` ### Testing the component Now, when you connect a wallet and click on the `Transact` button and approve the transaction, it will increment the tally onchain by one. We can verify that the onchain count took place onchain by once again using `cast` to call the `number` function on our contract. Terminal Terminal ```vocs_Code Copycast call $COUNTER_CONTRACT_ADDRESS "number()(uint256)" --rpc-url $BASE_SEPOLIA_RPC_URL ``` If the transaction was successful, the tally should have incremented by one! We now have a working onchain tally app! While the example is simple, it illustrates the end to end process of building on onchain app. We: - Configured a project with frontend and onchain infrastructure - Deployed a smart contract to Base Sepolia - Interacted with the contract from the frontend ## Further Improvements This is just the beginning. There are many ways we can improve upon this app. For example, we could: - Make the `increment` transaction gasless by integrating with [Paymaster](https://docs.base.org/builderkits/onchainkit/transaction/transaction#sponsor-with-paymaster-capabilities) - Improve the wallet connection and sign up flow with the [WalletModal](https://docs.base.org/builderkits/onchainkit/wallet/wallet-modal) component - Add onchain [Identity](https://docs.base.org/builderkits/onchainkit/identity/identity) so we know who added the most recent tally We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Documentation [Skip to content](https://docs.base.org/#vocs-content) Menu Overview On this page Chevron Right # Base Documentation Base is a secure, low-cost, builder-friendly Ethereum L2 built to bring the next billion users onchain. Base is incubated within Coinbase and plans to progressively decentralize in the years ahead. We believe that decentralization is critical to creating an open, global cryptocurrency that is accessible to everyone. ## Browse by use cases [**Onboard anyone** \\ \\ Let users sign up and sign in with Smart Wallet — the universal account for the onchain world.](https://docs.base.org/use-cases/onboard-any-user) [**Accept crypto payments** \\ \\ Integrate secure and efficient crypto payment solutions for your applications.](https://docs.base.org/use-cases/accept-crypto-payments) [**Launch AI agents** \\ \\ Build and deploy AI agents that can interact with onchain data and smart contracts.](https://docs.base.org/use-cases/launch-ai-agents) [**Create engaging social experiences** \\ \\ Add decentralized social features in your app for new content and identity.](https://docs.base.org/use-cases/decentralize-social-app) [**DeFi your app** \\ \\ Integrate DeFi protocols and services directly into your applications.](https://docs.base.org/use-cases/defi-your-app) [**Remove first-timer friction** \\ \\ Enable gasless transactions and account abstraction solutions.](https://docs.base.org/use-cases/go-gasless) ## Browse by tools [**OnchainKit** \\ \\ Build an app in 10 minutes with this all-in-one toolkit and full-stack components.](https://docs.base.org/builderkits/onchainkit/getting-started) [**Smart Wallet** \\ \\ A passkey-based universal account to connect with the onchain world.](https://docs.base.org/identity/smart-wallet/introduction/install-web) [**AgentKit** \\ \\ Give every AI agent a crypto wallet and the ability to transact and interact onchain.](https://docs.cdp.coinbase.com/agentkit/docs/welcome) [**Paymaster** \\ \\ Build gasless apps with bundled infrastructure. Start with free credits.](https://docs.cdp.coinbase.com/paymaster/docs/welcome) [**MiniKit** \\ \\ Feature your mini app on Warpcast and Coinbase Wallet with a few lines of code..](https://replit.com/@tina-he/ock-frames-template?v=1#README.md) [**Verifications** \\ \\ Identify high-quality users and build compliant apps with verifiable attestations.](https://docs.cdp.coinbase.com/verifications/docs/welcome) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Documentation [Skip to content](https://docs.base.org/chain/#vocs-content) Menu Overview On this page Chevron Right We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Smart Contract Learning [Skip to content](https://docs.base.org/learn/welcome#vocs-content) Menu Welcome On this page Chevron Right ![Welcome](https://docs.base.org/images/learn/welcome/Base_Learn_Hero.png) ## Introduction Welcome to Base Learn, your guide to learning smart contract development. Base Learn's curriculum has been expertly crafted to equip you with the skills and knowledge needed to build and deploy smart contracts on Base, or any EVM-compatible chain, including Ethereum, Optimism, and many more. Plus, you'll be eligible to earn NFTs as you complete each module, showcasing your mastery of the material. Whether you're a curious novice or a seasoned pro looking to stay ahead of the game, our dynamic lessons cater to all levels of experience. You can start with the basics and work your way up, or dive straight into the more advanced concepts and push your limits to new heights. Begin your journey today! ## What you can learn in this program Base Learn covers the following topics. If you're looking for quickstarts, or deeper guides on advanced topics, check out our [Base Builder Tutorials](https://docs.base.org/tutorials/)! ### [Ethereum Applications](https://docs.base.org/learn/introduction-to-ethereum/ethereum-applications) - Describe the origin and goals of the Ethereum blockchain - List common types of applications that can be developed with the Ethereum blockchain - Compare and contrast Web2 vs. Web3 development - Compare and contrast the concept of "ownership" in Web2 vs. Web3 ### [Gas Use in Ethereum Transactions](https://docs.base.org/learn/introduction-to-ethereum/gas-use-in-eth-transactions) - Explain what gas is in Ethereum - Explain why gas is necessary in Ethereum - Understand how gas works in Ethereum transactions ### [EVM Diagram](https://docs.base.org/learn/introduction-to-ethereum/evm-diagram) - Diagram the EVM ### [Setup and Overview](https://docs.base.org/learn/hardhat-setup-overview/hardhat-setup-overview-sbs) - Install and create a new Hardhat project with Typescript support - Describe the organization and folder structure of a Hardhat project - List the use and properties of hardhat.config.ts ### [Testing with Hardhat and Typechain](https://docs.base.org/learn/hardhat-testing/hardhat-testing-sbs) - Set up TypeChain to enable testing - Write unit tests for smart contracts using Mocha, Chai, and the Hardhat Toolkit - Set up multiple signers and call smart contract functions with different signers ### [Etherscan](https://docs.base.org/learn/etherscan/etherscan-sbs) - List some of the features of Etherscan - Read data from the Bored Ape Yacht Club contract on Etherscan - Write data to a contract using Etherscan. ### [Deploying Smart Contracts](https://docs.base.org/learn/hardhat-deploy/hardhat-deploy-sbs) - Deploy a smart contract to the Base Sepolia Testnet with hardhat-deploy - Deploy a smart contract to the Sepolia Testnet with hardhat-deploy - Use BaseScan to view a deployed smart contract ### [Verifying Smart Contracts](https://docs.base.org/learn/hardhat-verify/hardhat-verify-sbs) - Verify a deployed smart contract on Etherscan - Connect a wallet to a contract in Etherscan - Use etherscan to interact with your own deployed contract ### [Hardhat Forking](https://docs.base.org/learn/hardhat-forking/hardhat-forking) - Use Hardhat Network to create a local fork of mainnet and deploy a contract to it - Utilize Hardhat forking features to configure the fork for several use cases ### ['Introduction to Remix'](https://docs.base.org/learn/introduction-to-solidity/introduction-to-remix) - List the features, pros, and cons of using Remix as an IDE - Deploy and test the Storage.sol demo contract in Remix ### [Deployment in Remix](https://docs.base.org/learn/introduction-to-solidity/deployment-in-remix) - Deploy and test the Storage.sol demo contract in Remix ### [Hello World](https://docs.base.org/learn/contracts-and-basic-functions/hello-world-step-by-step) - Construct a simple "Hello World" contract - List the major differences between data types in Solidity as compared to other languages - Select the appropriate visibility for a function ### [Basic Types](https://docs.base.org/learn/contracts-and-basic-functions/basic-types) - Categorize basic data types - List the major differences between data types in Solidity as compared to other languages - Compare and contrast signed and unsigned integers ### [Test Networks](https://docs.base.org/learn/deployment-to-testnet/test-networks) - Describe the uses and properties of the Base testnet - Compare and contrast Ropsten, Rinkeby, Goerli, and Sepolia ### [Deployment to Base Sepolia](https://docs.base.org/learn/deployment-to-testnet/deployment-to-base-sepolia-sbs) - Deploy a contract to the Base Sepolia testnet and interact with it in \[BaseScan\] ### [Contract Verification](https://docs.base.org/learn/deployment-to-testnet/contract-verification-sbs) - Verify a contract on the Base Sepolia testnet and interact with it in \[BaseScan\] ### [Control Structures](https://docs.base.org/learn/control-structures/control-structures) - Control code flow with `if`, `else`, `while`, and `for` - List the unique constraints for control flow in Solidity - Utilize `require` to write a function that can only be used when a variable is set to `true` - Write a `revert` statement to abort execution of a function in a specific state - Utilize `error` to control flow more efficiently than with `require` ### [Storing Data](https://docs.base.org/learn/storage/simple-storage-sbs) - Use the constructor to initialize a variable - Access the data in a public variable with the automatically generated getter - Order variable declarations to use storage efficiently ### [How Storage Works](https://docs.base.org/learn/storage/how-storage-works) - Diagram how a contract's data is stored on the blockchain (Contract -> Blockchain) - Order variable declarations to use storage efficiently - Diagram how variables in a contract are stored (Variable -> Contract) ### [Arrays](https://docs.base.org/learn/arrays/arrays-in-solidity) - Describe the difference between storage, memory, and calldata arrays ### [Filtering an Array](https://docs.base.org/learn/arrays/filtering-an-array-sbs) - Write a function that can return a filtered subset of an array ### [Mappings](https://docs.base.org/learn/mappings/mappings-sbs) - Construct a Map (dictionary) data type - Recall that assignment of the Map data type is not as flexible as for other data types/in other languages - Restrict function calls with the `msg.sender` global variable - Recall that there is no collision protection in the EVM and why this is (probably) ok ### [Function Visibility and State Mutability](https://docs.base.org/learn/advanced-functions/function-visibility) - Categorize functions as public, private, internal, or external based on their usage - Describe how pure and view functions are different than functions that modify storage ### [Function Modifiers](https://docs.base.org/learn/advanced-functions/function-modifiers) - Use modifiers to efficiently add functionality to multiple functions ### [Structs](https://docs.base.org/learn/structs/structs-sbs) - Construct a `struct` (user-defined type) that contains several different data types - Declare members of the `struct` to maximize storage efficiency - Describe constraints related to the assignment of `struct` s depending on the types they contain ### [Inheritance](https://docs.base.org/learn/inheritance/inheritance-sbs) - Write a smart contract that inherits from another contract - Describe the impact inheritance has on the byte code size limit ### [Multiple Inheritance](https://docs.base.org/learn/inheritance/multiple-inheritance) - Write a smart contract that inherits from multiple contracts ### [Abstract Contracts](https://docs.base.org/learn/inheritance/abstract-contracts-sbs) - Use the virtual, override, and abstract keywords to create and use an abstract contract ### [Imports](https://docs.base.org/learn/imports/imports-sbs) - Import and use code from another file - Utilize OpenZeppelin contracts within Remix ### [Error Triage](https://docs.base.org/learn/error-triage/error-triage) - Debug common solidity errors including transaction reverted, out of gas, stack overflow, value overflow/underflow, index out of range, etc. ### [The New Keyword](https://docs.base.org/learn/new-keyword/new-keyword-sbs) - Write a contract that creates a new contract with the new keyword ### ['Contract to Contract Interaction'](https://docs.base.org/learn/interfaces/contract-to-contract-interaction) - Use interfaces to allow a smart contract to call functions in another smart contract - Use the `call()` function to interact with another contract without using an interface ### [Events](https://docs.base.org/learn/events/hardhat-events-sbs) - Write and trigger an event - List common uses of events - Understand events vs. smart contract storage ### [Address and Payable in Solidity](https://docs.base.org/learn/address-and-payable/address-and-payable) - Differentiate between address and address payable types in Solidity - Determine when to use each type appropriately in contract development - Employ address payable to send Ether and interact with payable functions ### [Minimal Token](https://docs.base.org/learn/minimal-tokens/minimal-token-sbs) - Construct a minimal token and deploy to testnet - Identify the properties that make a token a token ### [The ERC-20 Token Standard](https://docs.base.org/learn/erc-20-token/erc-20-standard) - Analyze the anatomy of an ERC-20 token - Review the formal specification for ERC-20 ### [ERC-20 Implementation](https://docs.base.org/learn/erc-20-token/erc-20-token-sbs) - 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 ### [The ERC-721 Token Standard](https://docs.base.org/learn/erc-721-token/erc-721-standard) - Analyze the anatomy of an ERC-721 token - Compare and contrast the technical specifications of ERC-20 and ERC-721 - Review the formal specification for ERC-721 ### [ERC-721 Token](https://docs.base.org/learn/erc-721-token/erc-721-sbs) - Analyze the anatomy of an ERC-721 token - Compare and contrast the technical specifications of ERC-20 and ERC-721 - Review the formal specification for ERC-721 - Build and deploy an ERC-721 compliant token - Use an ERC-721 token to control ownership of another data structure ### [Wallet Connectors](https://docs.base.org/learn/frontend-setup/wallet-connectors) - Identify the role of a wallet aggregator in an onchain app - Debate the pros and cons of using a template - Scaffold a new onchain app with RainbowKit - Support users of EOAs and the Coinbase Smart Wallet with the same app ### [Building an Onchain App](https://docs.base.org/learn/frontend-setup/building-an-onchain-app) - Identify the role of a wallet aggregator in an onchain app - Debate the pros and cons of using a template - Add a wallet connection to a standard template app ### [The `useAccount` Hook](https://docs.base.org/learn/reading-and-displaying-data/useAccount) - 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](https://docs.base.org/learn/reading-and-displaying-data/useReadContract) - Implement wagmi's `useReadContract` hook to fetch data from a smart contract - Convert data fetched from a smart contract to information displayed to the user - Identify the caveats of reading data from automatically-generated getters ### [Configuring `useReadContract`](https://docs.base.org/learn/reading-and-displaying-data/configuring-useReadContract) - Use `useBlockNumber` and the `queryClient` to automatically fetch updates from the blockchain - Describe the costs of using the above, and methods to reduce those costs - Configure arguments to be passed with a call to a `pure` or `view` smart contract function - Call an instance of `useReadContract` on demand - Utilize `isLoading` and `isFetching` to improve user experience ### [The `useWriteContract` hook](https://docs.base.org/learn/writing-to-contracts/useWriteContract) - Implement wagmi's `useWriteContract` hook to send transactions to a smart contract - Configure the options in `useWriteContract` - Display the execution, success, or failure of a function with button state changes, and data display ### [The `useSimulateContract` hook](https://docs.base.org/learn/writing-to-contracts/useSimulateContract) - 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 We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Oracle Solutions [Skip to content](https://docs.base.org/chain/oracles#vocs-content) Menu Oracles On this page Chevron Right ## API3 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). 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. 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. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Chainlink [Chainlink](https://chain.link/) provides a number of [price feeds](https://docs.chain.link/data-feeds/price-feeds/addresses/?network=base) for Base. See [this guide](https://docs.chain.link/docs/get-the-latest-price/) to learn how to use the Chainlink feeds. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Chronicle [Chronicle](https://chroniclelabs.org/) provides a number of [Oracles](https://chroniclelabs.org/dashboard) for Base. See [this guide](https://docs.chroniclelabs.org/Builders/tutorials/Remix) to learn how to use the Chronicle Oracles. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## DIA [DIA](https://www.diadata.org/) provides 2000+ [price feeds](https://www.diadata.org/app/price/) for Base. See [this guide](https://docs.diadata.org/introduction/intro-to-dia-oracles/request-an-oracle) to learn how to use the DIA feeds. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Gelato Gelato VRF (Verifiable Random Function) provides a unique system offering trustable randomness on Base. See this guide to learn how to get started with [Gelato VRF](https://docs.gelato.network/web3-services/vrf/quick-start). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## ORA [ORA](https://ora.io/) provides an [Onchain AI Oracle](https://docs.ora.io/doc/oao-onchain-ai-oracle/introduction) for Base. See [this guide](https://docs.ora.io/doc/oao-onchain-ai-oracle/develop-guide/tutorials/interaction-with-oao-tutorial) to learn how to use ORA Onchain AI Oracle. #### Supported Networks - Base Mainnet ## Pyth The [Pyth Network](https://pyth.network/) is one of the largest first-party Oracle network, delivering real-time data across [a vast number of chains](https://docs.pyth.network/price-feeds/contract-addresses). Pyth introduces an innovative low-latency [pull oracle design](https://docs.pyth.network/documentation/pythnet-price-feeds/on-demand), where users can pull price updates onchain when needed, enabling everyone in the onchain environment to access that data point most efficiently. Pyth network updates the prices every **400ms**, making Pyth one of the fastest onchain oracles. #### Pyth Price Feeds Features: - 400ms latency - Efficient and cost-effective Oracle - [First-party](https://pyth.network/publishers) data sourced directly from financial institutions - [Price feeds ranging from Crypto, Stock, FX, Metals](https://pyth.network/developers/price-feed-ids) - [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) ### 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) Check out the following links to get started with Pyth. - [Pyth Price Feed EVM Integration Guide](https://docs.pyth.network/price-feeds/use-real-time-data/evm) - [Pyth Docs](https://docs.pyth.network/home) - [Pyth Price Feed API Reference](https://api-reference.pyth.network/price-feeds/evm/getPrice) - [Pyth Examples](https://github.com/pyth-network/pyth-examples) - [Website](https://pyth.network/) - [Twitter](https://x.com/PythNetwork) ## RedStone [RedStone](https://redstone.finance/) provides 1200+ [price feeds](https://app.redstone.finance/) for Base. See [this guide](https://docs.redstone.finance/) to learn how to use the RedStone feeds. #### Supported Networks - Base Mainnet ## Supra [Supra](https://supraoracles.com/) provides VRF and decentralized oracle price feeds that can be used for onchain and offchain use-cases such as spot and perpetual DEXes, lending protocols, and payments protocols. Supra’s oracle chain and consensus algorithm makes it one of the fastest-to-finality oracle providers, with layer-1 security guarantees. The pull oracle has a sub-second response time. Aside from speed and security, Supra’s rotating node architecture gathers data from 40+ data sources and applies a robust calculation methodology to get the most accurate value. The node provenance on the data dashboard also provides a fully transparent historical audit trail. Supra’s Distributed Oracle Agreement (DORA) paper was accepted into ICDCS 2023, the oldest distributed systems conference. Visit the Supra [documentation](https://supraoracles.com/docs/) to learn more about integrating Supra's oracle and VRF into your Base project. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Fiat-to-Crypto Onramps [Skip to content](https://docs.base.org/chain/onramps#vocs-content) Menu Onramps On this page Chevron Right ## Coinbase Onramp [Coinbase Onramp](https://www.coinbase.com/developer-platform/products/onramp) is a fiat-to-crypto onramp that allows users to buy or transfer crypto directly from self-custody wallets and apps. Coinbase Onramp supports 60+ fiat currencies with regulatory compliance and licensing, as well as 100+ cryptocurrencies, including ETH on Base. [Get started here](https://docs.cdp.coinbase.com/onramp/docs/getting-started/) to use the Coinbase Developer Platform. ## MoonPay [MoonPay](https://www.moonpay.com/business/onramps) is a crypto onramp that provides global coverage, seamless revenue sharing, and zero risk of fraud or chargebacks. MoonPay supports 30+ fiat currencies and 110+ cryptocurrencies, including ETH on Base. ## Onramp [Onramp](https://onramp.money/) is a fiat-to-crypto payment gateway, which helps users seamlessly convert fiat currency to the desired cryptocurrency. Onramp currently supports 300+ cryptocurrencies and 20+ blockchain networks, including ETH on Base. ## Ramp [Ramp](https://ramp.network/) is an onramp and offramp that empowers users to buy & sell crypto inside your app. Ramp supports 40+ fiat currencies and 90+ crypto assets, including ETH on Base. ## Transak [Transak](https://transak.com/) is a developer integration toolkit to let users buy/sell crypto in any app, website or web plugin. It is available across 170 cryptocurrencies on 75+ blockchains, including ETH on Base. ## Alchemy Pay [Alchemy Pay](https://ramp.alchemypay.org/) (ACH) is a payment solutions provider that seamlessly connects fiat and crypto economies for global consumers, merchants, developers, and institutions. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Privacy Policy Overview [Skip to content](https://docs.base.org/privacy-policy#vocs-content) Menu Privacy Policy On this page Chevron Right 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, decentralized applications, and services you use to access or interact with our Services. We collect the following personal information when providing the Services: **Information you provide** - Your public wallet address (“ **Wallet Address**”) - Publicly available blockchain data (“ **Blockchain Data**”) - Where you agree to engage in our surveys or sign up to receive marketing communications about Base products and offerings, we will ask for the following “ **Basic User Information**” - Name - Email - Social media handles - Business name **Information Collected Automatically** - App, Browser and Device Information: - Information about the device, operating system, and browser you’re using~~ ~~ - Other device characteristics or identifiers (e.g. plugins, the network you connect to) - IP address/derived location information **Information we obtain from Affiliates and third parties** - 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. - 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. We may use your personal information for the following purposes or as otherwise described at the time of collection. If you reside outside the United Kingdom or European Economic Area (“ **EEA”)**, the legal bases on which we rely in your country may differ from those listed below. | | | | | --- | --- | --- | | **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 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 | 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. **Linked Third Party Websites or Services.** When you use third-party services (like when you connect your self-custodial wallet to decentralized applications on the Base network) or websites that are linked through our Services, the providers of those services or products may receive information about you (like your wallet address) from Base, you, or others. Please note that when you use third-party services or connect to third-party websites which are not governed by this Privacy Policy, their own terms and privacy policies will govern your use of those services and products. **Professional advisors, industry partners, authorities and regulators.** We share your information described in **Section 1. What Information We Collect** with our advisors, regulators, tax authorities, law enforcement, government agencies, and industry partners when needed to: - respond pursuant to applicable law or regulations, court orders, legal process or government requests; - detect, investigate, prevent, or address fraud and other illegal activity or security and technical issues; and - protect the rights, property, and safety of our Users, Developers, Affiliates, or others, including to prevent death or imminent bodily harm. **Vendors and Third-Party Service Providers.** When we share information with third-party service providers to help us provide our Services, we require them to use your information on our behalf in accordance with our instructions and terms and only process as necessary for the purpose of the contract. We retain your information as needed to provide our Services, comply with legal obligations or protect our or others’ interests. While retention requirements vary by country, we maintain internal retention policies on the basis of how information needs to be used. This includes considerations such as when the information was collected or created, whether it is necessary in order to continue offering you our Services or to protect the safety, security and integrity of our Services, and whether we are required to hold the information to comply with our legal obligations. The Services are not directed to persons under the age of 18, and we do not knowingly request or collect any information about persons under the age of 18. If you are under the age of 18, please do not provide any personal information through the Site or Services. If a User submitting personal information is suspected of being younger than 18 years of age, we will take steps to delete the individual’s information as soon as possible. To facilitate our global operations, we and our  third-party partners and service providers may transfer and store throughout the world, including in the United States. If you reside in the EEA, Switzerland, or the United Kingdom, we rely upon a variety of legal mechanisms to facilitate these transfers of your personal information (collectively, “ **European Personal Data”**). \*\*\*\* - We rely primarily on the European Commission’s Standard Contractual Clauses to facilitate the international and onward transfer of European Personal Data to third countries, including from our EU operating entities to Coinbase, Inc. in the United States, who provides the primary infrastructure for the Services. - We also rely on [adequacy decisions](https://ec.europa.eu/info/law/law-topic/data-protection/international-dimension-data-protection/adequacy-decisions_en) from the European Commission where available and exemptions provided for under data protection law (e.g. Article 49 GDPR). If you have questions or concerns regarding this Privacy Policy, or if you have a complaint, please contact us at [privacy@base.org](mailto:privacy@base.org). We’re constantly trying to improve our Services, so we may need to change this Privacy Policy from time to time as well. We post any changes we make to our Privacy Policy on this page and, where appropriate, we will provide you with reasonable notice of any material changes before they take effect or as otherwise required by law. The date the Privacy Policy was last updated is identified at the top of this page. Coinbase Technologies, Inc., 251 Little Falls Drive, City of Wilmington, County of New Castle, Delaware 19808, acts as controller of your personal data. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Coinbase Arbitration Agreement [Skip to content](https://docs.base.org/arbitration#vocs-content) Menu Arbitration On this page Chevron Right ### 1\. Applicability of Arbitration Agreement Subject to the terms of this Sequencer, Testnet, and Basenames Interface Terms Arbitration Agreement (as amended, restated, supplemented or otherwise modified and in effect from time to time, the “Arbitration Agreement”), you and Coinbase agree that any dispute, claim, or disagreement arising out of or relating in any way to your access to or use of Base, the Site, a Coinbase Sequencer, the Services, or the Base Terms (the “Base ToS”) and prior versions of the Base ToS, including claims and disputes that arose between us before the effective date of the Base ToS (each, a “Dispute”) will be resolved by binding arbitration, rather than in court, except that: (1) you and Coinbase may assert claims or seek relief in small claims court if such claims qualify and remain in small claims court; and (2) you and Coinbase must resolve in court any Dispute about infringement, misuse, or misappropriation of intellectual property rights (such as trademarks, trade dress, domain names, trade secrets, copyrights, and patents). For purposes of this Arbitration Agreement, “Dispute” will also include disputes that arose or involve facts occurring before the existence of this or any prior versions of the Base ToS as well as claims that may arise after the termination of the Base ToS. Any capitalized term used herein without definition shall have the meaning assigned thereto in the Base ToS. ### 2\. Waiver of Jury Trial YOU AND COINBASE HEREBY WAIVE ANY CONSTITUTIONAL AND STATUTORY RIGHTS TO SUE IN COURT AND HAVE A TRIAL IN FRONT OF A JUDGE OR A JURY. You and Coinbase are instead electing that all Disputes shall be resolved by arbitration under this Arbitration Agreement, except as specified in the section entitled “Applicability of Arbitration Agreement” above. There is no judge or jury in arbitration, and court review of an arbitration award is subject to very limited review. ### 3\. Waiver of Class and Other Non-Individualized Relief YOU AND COINBASE AGREE THAT, EXCEPT AS SPECIFIED IN SECTION 8, EACH OF US MAY BRING CLAIMS AGAINST THE OTHER ONLY ON AN INDIVIDUAL BASIS AND NOT ON A CLASS, REPRESENTATIVE, OR COLLECTIVE BASIS, AND THE PARTIES HEREBY WAIVE ALL RIGHTS TO HAVE ANY DISPUTE BE BROUGHT, HEARD, ADMINISTERED, RESOLVED, OR ARBITRATED ON A CLASS, COLLECTIVE, REPRESENTATIVE, OR MASS ACTION BASIS. ONLY INDIVIDUAL RELIEF IS AVAILABLE, AND DISPUTES OF MORE THAN ONE CUSTOMER OR USER CANNOT BE ARBITRATED OR CONSOLIDATED WITH THOSE OF ANY OTHER CUSTOMER OR USER. Subject to this Arbitration Agreement, the arbitrator may award declaratory or injunctive relief only in favor of the individual party seeking relief and only to the extent necessary to provide relief warranted by the party's individual claim. Nothing in this paragraph is intended to, nor shall it, affect the terms and conditions under Section 8 entitled “Batch Arbitration.” Notwithstanding anything to the contrary in this Arbitration Agreement, if a court decides by means of a final decision, not subject to any further appeal or recourse, that the limitations of this section, “Waiver of Class and Other Non-Individualized Relief,” are invalid or unenforceable as to a particular claim or request for relief (such as a request for public injunctive relief), you and Coinbase agree that that particular claim or request for relief (and only that particular claim or request for relief) shall be severed from the arbitration and may be litigated in the state or federal courts located in the State of California. All other Disputes that are not severed shall be litigated in small claims court or arbitrated. This section does not prevent you or Coinbase from participating in a class-wide settlement of claims. ### 4\. Rules and Forum The Base ToS evidences a transaction involving interstate commerce; and notwithstanding any other provision herein with respect to the applicable substantive law, the Federal Arbitration Act, 9 U.S.C. § 1 et seq., will govern the interpretation and enforcement of this Arbitration Agreement and any arbitration proceedings. The arbitration will be administered by the American Arbitration Association ( **“AAA”**), in accordance with the Consumer Arbitration Rules (the **"AAA Rules"**) then in effect, except as modified by this Arbitration Agreement. The AAA Rules are currently available at [https://www.adr.org/sites/default/files/Consumer%20Rules.pdf](https://www.adr.org/sites/default/files/Consumer%20Rules.pdf). A party who wishes to initiate arbitration must provide the other party with a request for arbitration (the **“Request”**). If you initiate the arbitration, you must provide Coinbase a copy of your Request by email at \[ [arbitration@coinbase.com](mailto:arbitration@coinbase.com)\] or through Coinbase's registered agent for service of process. The Request must include: (1) the name, telephone number, mailing address, email address of the party seeking arbitration, and the username and wallet addresses (if any) associated with the applicable Account(s); (2) a statement of the legal claims being asserted and the factual bases of those claims; (3) a description of the remedy sought, including an accurate, good faith calculation of the amount in controversy in United States Dollars; (4) if you are the party making the Request, a statement certifying completion of the Formal Complaint Process as described in the Base ToS; and (5) evidence that the requesting party has paid any necessary filing fees in connection with such arbitration. If the party requesting arbitration is represented by counsel, the Request shall also include counsel's name, telephone number, mailing address, and email address. Such counsel must also sign the Request. By signing the Request, counsel certifies to the best of counsel's knowledge, information, and belief, formed after an inquiry reasonable under the circumstances, that: (1) the Request is not being presented for any improper purpose, such as to harass, cause unnecessary delay, or needlessly increase the cost of dispute resolution; (2) the claims, defenses and other legal contentions are warranted by existing law or by a nonfrivolous argument for extending, modifying, or reversing existing law or for establishing new law; and (3) the factual and damages contentions have evidentiary support or, if specifically so identified, will likely have evidentiary support after a reasonable opportunity for further investigation or discovery. Unless you and Coinbase otherwise agree, or the Batch Arbitration process discussed in Section 8 is triggered, the arbitration will be conducted in the county where you reside. Subject to the AAA Rules, the arbitrator may direct a limited and reasonable exchange of information between the parties, consistent with the expedited nature of the arbitration. If the AAA is not available to arbitrate, the parties will select an alternative arbitral forum. Your responsibility to pay any AAA fees and costs will be solely as set forth in the applicable AAA Rules. You and Coinbase agree that all materials and documents exchanged during the arbitration proceedings shall be kept confidential and shall not be shared with anyone except the parties' attorneys, accountants, or business advisors, and then subject to the condition that they agree to keep all materials and documents exchanged during the arbitration proceedings confidential. ### 5\. Arbitrator The arbitrator will be either a retired judge or an attorney licensed to practice law in the state of California and will be selected by the parties from the AAA's roster of consumer dispute arbitrators. If the parties are unable to agree upon an arbitrator within thirty-five (35) business days of delivery of the Request, then the AAA will appoint the arbitrator in accordance with the AAA Rules, provided that if the Batch Arbitration process under Section 8 is triggered, the AAA will appoint the arbitrator for each batch. ### 6\. Authority of Arbitrator The arbitrator shall have exclusive authority to resolve any Dispute, including, without limitation, disputes arising out of or related to the interpretation or application of the Arbitration Agreement, including the enforceability, revocability, scope, or validity of the Arbitration Agreement or any portion of the Arbitration Agreement, except for the following: (1) all Disputes arising out of or relating to the section entitled “Waiver of Class and Other Non-Individualized Relief,” including any claim that all or part of the section entitled “Waiver of Class and Other Non-Individualized Relief” is unenforceable, illegal, void or voidable, or that such Section entitled “Waiver of Class and Other Non-Individualized Relief” has been breached, shall be decided by a court of competent jurisdiction and not by an arbitrator; (2) except as expressly contemplated in the section entitled “Batch Arbitration,” all Disputes about the payment of arbitration fees shall be decided only by a court of competent jurisdiction and not by an arbitrator; (3) all Disputes about whether either party has satisfied any condition precedent to arbitration shall be decided only by a court of competent jurisdiction and not by an arbitrator; (4) all Disputes about which version of the Arbitration Agreement applies shall be decided only by a court of competent jurisdiction and not by an arbitrator; and (5) all Disputes about whether a Dispute is carved out from arbitration in the Section above entitled “Applicability of Arbitration Agreement” shall be decided only by a court of competent jurisdiction and not by an arbitrator. The arbitration proceeding will not be consolidated with any other matters or joined with any other cases or parties, except as expressly provided in the section entitled “Batch Arbitration.” The arbitrator shall have the authority to grant motions dispositive of all or part of any Dispute. The arbitrator shall issue a written award and statement of decision describing the essential findings and conclusions on which the award is based, including the calculation of any damages awarded. The award of the arbitrator is final and binding upon you and us. This means that, among other things, you and we agree that an arbitral award shall have no preclusive effect in any other proceeding involving other parties. Judgment on the arbitration award may be entered in any court having jurisdiction. In any award of damages, the arbitrator shall abide by the “Limitation of Liability” section of the Terms. ### 7\. Attorneys' Fees and Costs The parties shall bear their own attorneys' fees and costs in arbitration unless the arbitrator finds that either the substance of the Dispute or the relief sought in the Request was frivolous or was brought for an improper purpose (as measured by the standards set forth in Federal Rule of Civil Procedure 11(b)). If you or Coinbase need to invoke the authority of a court of competent jurisdiction to compel arbitration, then the party that obtains an order compelling arbitration in such action shall have the right to collect from the other party its reasonable costs, necessary disbursements, and reasonable attorneys' fees incurred in securing an order compelling arbitration. The prevailing party in any court action relating to whether either party has satisfied any condition precedent to arbitration, including the Formal Complaint Process, is entitled to recover their reasonable costs, necessary disbursements, and reasonable attorneys' fees and costs. ### 8\. Batch Arbitration To increase the efficiency of administration and resolution of arbitrations, you and Coinbase agree that in the event that there are one hundred (100) or more individual Requests of a substantially similar nature filed against Coinbase by or with the assistance of the same law firm, group of law firms, or organizations, within a thirty (30) day period (or as soon as possible thereafter), the AAA shall (1) administer the arbitration demands in batches of 100 Requests per batch (plus, to the extent there are less than 100 Requests left over after the batching described above, a final batch consisting of the remaining Requests); (2) appoint one arbitrator for each batch; and (3) provide for the resolution of each batch as a single consolidated arbitration with one set of filing and administrative fees due per side per batch, one procedural calendar, one hearing (if any) in a place to be determined by the arbitrator, and one final award ( **“Batch Arbitration”**). All parties agree that Requests are of a “substantially similar nature” if they arise out of or relate to the same event or factual scenario and raise the same or similar legal issues and seek the same or similar relief. To the extent the parties disagree on the application of the Batch Arbitration process, the disagreeing party shall advise the AAA, and the AAA shall appoint a sole standing arbitrator to determine the applicability of the Batch Arbitration process ( **“Administrative Arbitrator”**). In an effort to expedite resolution of any such dispute by the Administrative Arbitrator, the parties agree the Administrative Arbitrator may set forth such procedures as are necessary to resolve any disputes promptly. The Administrative Arbitrator's fees shall be paid by Coinbase. You and Coinbase agree to cooperate in good faith with the AAA to implement the Batch Arbitration process including the payment of single filing and administrative fees for batches of Requests, as well as any steps to minimize the time and costs of arbitration, which may include: (1) the appointment of a discovery special master to assist the arbitrator in the resolution of discovery disputes; and (2) the adoption of an expedited calendar of the arbitration proceedings. This Batch Arbitration provision shall in no way be interpreted as authorizing a class, collective and/or mass arbitration or action of any kind, or arbitration involving joint or consolidated claims under any circumstances, except as expressly set forth in this provision. ### 9\. Modification If we make any updates to the Arbitration Agreement, we will make the updated terms available to you by publishing them on the Site. Your continued use of the Site and/or Services, including the acceptance of products and services offered on the Site following the posting of changes to this Arbitration Agreement constitutes your acceptance of any such changes. ### 10\. Severability If any provision of this Arbitration Agreement shall be determined to be invalid or unenforceable under any rule, law, or regulation of any local, state, or federal government agency, such provision will be changed and interpreted to accomplish the objectives of the provision to the greatest extent possible under any applicable law and the validity or enforceability of any other provision of this Arbitration Agreement shall not be affected. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Foundry Tools Overview 404 The requested path could not be found ## Base Contract Addresses [Skip to content](https://docs.base.org/chain/base-contracts#vocs-content) Menu Base Contracts On this page Chevron Right ## L2 Contract Addresses ### Base Mainnet | Name | Address | | --- | --- | | WETH9 | [0x4200000000000000000000000000000000000006](https://basescan.org/address/0x4200000000000000000000000000000000000006) | | L2CrossDomainMessenger | [0x4200000000000000000000000000000000000007](https://basescan.org/address/0x4200000000000000000000000000000000000007) | | L2StandardBridge | [0x4200000000000000000000000000000000000010](https://basescan.org/address/0x4200000000000000000000000000000000000010) | | SequencerFeeVault | [0x4200000000000000000000000000000000000011](https://basescan.org/address/0x4200000000000000000000000000000000000011) | | OptimismMintableERC20Factory | [0xF10122D428B4bc8A9d050D06a2037259b4c4B83B](https://basescan.org/address/0xF10122D428B4bc8A9d050D06a2037259b4c4B83B) | | GasPriceOracle | [0x420000000000000000000000000000000000000F](https://basescan.org/address/0x420000000000000000000000000000000000000F) | | L1Block | [0x4200000000000000000000000000000000000015](https://basescan.org/address/0x4200000000000000000000000000000000000015) | | L2ToL1MessagePasser | [0x4200000000000000000000000000000000000016](https://basescan.org/address/0x4200000000000000000000000000000000000016) | | L2ERC721Bridge | [0x4200000000000000000000000000000000000014](https://basescan.org/address/0x4200000000000000000000000000000000000014) | | OptimismMintableERC721Factory | [0x4200000000000000000000000000000000000017](https://basescan.org/address/0x4200000000000000000000000000000000000017) | | ProxyAdmin | [0x4200000000000000000000000000000000000018](https://basescan.org/address/0x4200000000000000000000000000000000000018) | | BaseFeeVault | [0x4200000000000000000000000000000000000019](https://basescan.org/address/0x4200000000000000000000000000000000000019) | | L1FeeVault | [0x420000000000000000000000000000000000001a](https://basescan.org/address/0x420000000000000000000000000000000000001a) | | EAS | [0x4200000000000000000000000000000000000021](https://basescan.org/address/0x4200000000000000000000000000000000000021) | | EASSchemaRegistry | [0x4200000000000000000000000000000000000020](https://basescan.org/address/0x4200000000000000000000000000000000000020) | | LegacyERC20ETH | [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://basescan.org/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) | ### Base Testnet (Sepolia) | Name | Address | | --- | --- | | WETH9 | [0x4200000000000000000000000000000000000006](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000006) | | L2CrossDomainMessenger | [0x4200000000000000000000000000000000000007](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000007) | | L2StandardBridge | [0x4200000000000000000000000000000000000010](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000010) | | SequencerFeeVault | [0x4200000000000000000000000000000000000011](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000011) | | OptimismMintableERC20Factory | [0x4200000000000000000000000000000000000012](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000012) | | GasPriceOracle | [0x420000000000000000000000000000000000000F](https://sepolia.basescan.org/address/0x420000000000000000000000000000000000000F) | | L1Block | [0x4200000000000000000000000000000000000015](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000015) | | L2ToL1MessagePasser | [0x4200000000000000000000000000000000000016](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000016) | | L2ERC721Bridge | [0x4200000000000000000000000000000000000014](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000014) | | OptimismMintableERC721Factory | [0x4200000000000000000000000000000000000017](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000017) | | ProxyAdmin | [0x4200000000000000000000000000000000000018](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000018) | | BaseFeeVault | [0x4200000000000000000000000000000000000019](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000019) | | L1FeeVault | [0x420000000000000000000000000000000000001a](https://sepolia.basescan.org/address/0x420000000000000000000000000000000000001a) | | EAS | [0x4200000000000000000000000000000000000021](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000021) | | EASSchemaRegistry | [0x4200000000000000000000000000000000000020](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000020) | | LegacyERC20ETH | [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://sepolia.basescan.org/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) | \* _L2 contract addresses are the same on both mainnet and testnet._ ## L1 Contract Addresses ### Ethereum Mainnet | Name | Address | | --- | --- | | AddressManager | [0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2](https://etherscan.io/address/0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2) | | AnchorStateRegistryProxy | [0xdB9091e48B1C42992A1213e6916184f9eBDbfEDf](https://etherscan.io/address/0xdB9091e48B1C42992A1213e6916184f9eBDbfEDf) | | DelayedWETHProxy (FDG) | [0xa2f2aC6F5aF72e494A227d79Db20473Cf7A1FFE8](https://etherscan.io/address/0xa2f2aC6F5aF72e494A227d79Db20473Cf7A1FFE8) | | DelayedWETHProxy (PDG) | [0x3E8a0B63f57e975c268d610ece93da5f78c01321](https://etherscan.io/address/0x3E8a0B63f57e975c268d610ece93da5f78c01321) | | DisputeGameFactoryProxy | [0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e](https://etherscan.io/address/0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e) | | FaultDisputeGame | [0xCd3c0194db74C23807D4B90A5181e1B28cF7007C](https://etherscan.io/address/0xCd3c0194db74C23807D4B90A5181e1B28cF7007C) | | L1CrossDomainMessenger | [0x866E82a600A1414e583f7F13623F1aC5d58b0Afa](https://etherscan.io/address/0x866E82a600A1414e583f7F13623F1aC5d58b0Afa) | | L1ERC721Bridge | [0x608d94945A64503E642E6370Ec598e519a2C1E53](https://etherscan.io/address/0x608d94945A64503E642E6370Ec598e519a2C1E53) | | L1StandardBridge | [0x3154Cf16ccdb4C6d922629664174b904d80F2C35](https://etherscan.io/address/0x3154Cf16ccdb4C6d922629664174b904d80F2C35) | | L2OutputOracle | [0x56315b90c40730925ec5485cf004d835058518A0](https://etherscan.io/address/0x56315b90c40730925ec5485cf004d835058518A0) | | MIPS | [0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4](https://etherscan.io/address/0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4) | | OptimismMintableERC20Factory | [0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84](https://etherscan.io/address/0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84) | | OptimismPortal | [0x49048044D57e1C92A77f79988d21Fa8fAF74E97e](https://etherscan.io/address/0x49048044D57e1C92A77f79988d21Fa8fAF74E97e) | | PermissionedDisputeGame | [0x19009dEBF8954B610f207D5925EEDe827805986e](https://etherscan.io/address/0x19009dEBF8954B610f207D5925EEDe827805986e) | | PreimageOracle | [0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277](https://etherscan.io/address/0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277) | | ProxyAdmin | [0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E](https://etherscan.io/address/0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E) | | SystemConfig | [0x73a79Fab69143498Ed3712e519A88a918e1f4072](https://etherscan.io/address/0x73a79Fab69143498Ed3712e519A88a918e1f4072) | | SystemDictator | [0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557](https://etherscan.io/address/0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557) | **Unneeded contract addresses** Certain contracts are mandatory according to the [OP Stack SDK](https://stack.optimism.io/docs/build/sdk/#unneeded-contract-addresses), despite not being utilized. For such contracts, you can simply assign the zero address: - `StateCommitmentChain` - `CanonicalTransactionChain` - `BondManager` ### Ethereum Testnet (Sepolia) | Name | Address | | --- | --- | | AddressManager | [0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B](https://sepolia.etherscan.io/address/0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B) | | AnchorStateRegistryProxy | [0x4C8BA32A5DAC2A720bb35CeDB51D6B067D104205](https://sepolia.etherscan.io/address/0x4C8BA32A5DAC2A720bb35CeDB51D6B067D104205) | | 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 | [0x9cd8b02e84df3ef61db3b34123206568490cb279](https://sepolia.etherscan.io/address/0x9cd8b02e84df3ef61db3b34123206568490cb279) | | 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) | | OptimismMintableERC20Factory | [0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37](https://sepolia.etherscan.io/address/0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37) | | OptimismPortal | [0x49f53e41452C74589E85cA1677426Ba426459e85](https://sepolia.etherscan.io/address/0x49f53e41452C74589E85cA1677426Ba426459e85) | | PermissionedDisputeGame | [0xcca6a4916fa6de5d671cc77760a3b10b012cca16](https://sepolia.etherscan.io/address/0xcca6a4916fa6de5d671cc77760a3b10b012cca16) | | PreimageOracle | [0x92240135b46fc1142dA181f550aE8f595B858854](https://sepolia.etherscan.io/address/0x92240135b46fc1142dA181f550aE8f595B858854) | | ProxyAdmin | [0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3](https://sepolia.etherscan.io/address/0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3) | | SystemConfig | [0xf272670eb55e895584501d564AfEB048bEd26194](https://sepolia.etherscan.io/address/0xf272670eb55e895584501d564AfEB048bEd26194) | ## Base Admin Addresses ### Base Mainnet | Admin Role | Address | Type of Key | | --- | --- | --- | | Batch Sender | [0x5050f69a9786f081509234f1a7f4684b5e5b76c9](https://etherscan.io/address/0x5050f69a9786f081509234f1a7f4684b5e5b76c9) | EOA managed by Coinbase Technologies | | Batch Inbox | [0xff00000000000000000000000000000000008453](https://etherscan.io/address/0xff00000000000000000000000000000000008453) | EOA (with no known private key) | | Output Proposer | [0x642229f238fb9de03374be34b0ed8d9de80752c5](https://etherscan.io/address/0x642229f238fb9de03374be34b0ed8d9de80752c5) | EOA managed by Coinbase Technologies | | Proxy Admin Owner (L1) | [0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c](https://etherscan.io/address/0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c) | 2-of-2 Nested Gnosis Safe (signers below) | | L1 Nested Safe Signer (Coinbase) | [0x9855054731540A48b28990B63DcF4f33d8AE46A1](https://etherscan.io/address/0x9855054731540A48b28990B63DcF4f33d8AE46A1) | Gnosis Safe | | L1 Nested Safe Signer (Optimism) | [0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A](https://etherscan.io/address/0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A) | Gnosis Safe | | Challenger | [0x6f8c5ba3f59ea3e76300e3becdc231d656017824](https://etherscan.io/address/0x6f8c5ba3f59ea3e76300e3becdc231d656017824) | 1-of-2 Smart contract | | System config owner | [0x14536667Cd30e52C0b458BaACcB9faDA7046E056](https://etherscan.io/address/0x14536667Cd30e52C0b458BaACcB9faDA7046E056) | Gnosis Safe | | Guardian | [0x14536667Cd30e52C0b458BaACcB9faDA7046E056](https://etherscan.io/address/0x14536667Cd30e52C0b458BaACcB9faDA7046E056) | Gnosis Safe | ### Base Testnet (Sepolia) | Admin Role | Address | Type of Key | | --- | --- | --- | | Batch Sender | [0x6CDEbe940BC0F26850285cacA097C11c33103E47](https://sepolia.etherscan.io/address/0x6CDEbe940BC0F26850285cacA097C11c33103E47) | EOA managed by Coinbase Technologies | | Batch Inbox | [0xff00000000000000000000000000000000084532](https://sepolia.etherscan.io/address/0xff00000000000000000000000000000000084532) | EOA (with no known private key) | | Output Proposer | [0x20044a0d104E9e788A0C984A2B7eAe615afD046b](https://sepolia.etherscan.io/address/0x20044a0d104E9e788A0C984A2B7eAe615afD046b) | EOA managed by Coinbase Technologies | | Proxy Admin Owner (L1) | [0x0fe884546476dDd290eC46318785046ef68a0BA9](https://sepolia.etherscan.io/address/0x0fe884546476dDd290eC46318785046ef68a0BA9) | Gnosis Safe | | Challenger | [0xDa3037Ff70Ac92CD867c683BD807e5A484857405](https://sepolia.etherscan.io/address/0xDa3037Ff70Ac92CD867c683BD807e5A484857405) | EOA managed by Coinbase Technologies | | System config owner | [0x0fe884546476dDd290eC46318785046ef68a0BA9](https://sepolia.etherscan.io/address/0x0fe884546476dDd290eC46318785046ef68a0BA9) | Gnosis Safe | | Guardian | [0xA9FF930151130fd19DA1F03E5077AFB7C78F8503](https://sepolia.etherscan.io/address/0xA9FF930151130fd19DA1F03E5077AFB7C78F8503) | EOA managed by Coinbase Technologies | We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Onchain Registry API [Skip to content](https://docs.base.org/chain/registry-api#vocs-content) Menu Onchain Registry API On this page Chevron Right ## Instructions 1. Users of this API can use the `/entries` and `/featured` endpoints to display Onchain Registry entries on their own surfaces 2. If your team would like to use referral codes to point your users to entries, we recommend appending your referral code to the link provided in the `target_url` field 3. If your team would like to filter entries based on where they are hosted or by creator, we recommend implementing logic based on the `target_url` and `creator_name` fields ## Endpoints ### GET /entries This endpoint will display all Onchain Registry entries subject to any query parameters set below #### Query Parameters | Name | Type | Description | | --- | --- | --- | | page | number | The page number (default 1) | | limit | number | The number of entries per page (default 10) | | category | array | The category or categories of the entries of interest
(Options: Games, Social, Creators, Finance, Media) | | curation | string | The entry's level of curation
(Options: Featured, Curated, Community) | #### Response JSON ```vocs_Code Copy{ "data": [\ {\ "id": "7AsRdN8uf601fCkH1e084F",\ "category": "Creators",\ "content": {\ "title": "Based Project",\ "short_description": "Short description of this based project with max char count of 30",\ "full_description": "Full description of this based project with max char count of 200",\ "image_url": "https://base.org/image.png",\ "target_url": "https://base.org/target-page",\ "cta_text": "Mint",\ "function_signature": "mint(uint256)",\ "contract_address": "0x1FC10ef15E041C5D3C54042e52EB0C54CB9b710c",\ "token_id": "2",\ "token_amount": "0.01",\ "featured": true,\ "creator_name": "Base",\ "creator_image_url": "https://base.org/creator-image.png",\ "curation": "featured",\ "start_ts": "2024-06-25T04:00:00Z",\ "expiration_ts": "2024-07-29T00:00:00Z"\ },\ "updated_at": null,\ "created_at": "2024-07-10T18:20:42.000Z"\ },\ {\ "id": "8fRbdN8uf601fCkH1e084F",\ "category": "Games",\ "content": {\ "title": "Based Project II",\ "short_description": "Short description of this second based project with max char count of 30",\ "full_description": "Full description of this second based project with max char count of 200",\ "image_url": "https://base.org/image2.png",\ "target_url": "https://base.org/second-target-page",\ "cta_text": "Mint",\ "function_signature": "mint(uint256)",\ "contract_address": "0x1FC10ef15E041C5D3C54042e52EB0C54CB9b710c",\ "token_id": "1",\ "token_amount": "0.005",\ "featured": false,\ "creator_name": "Base",\ "creator_image_url": "https://base.org/creator-image2.png",\ "curation": "community",\ "start_ts": "2024-06-25T04:00:00Z",\ "expiration_ts": "2024-07-29T00:00:00Z"\ },\ "updated_at": "2024-07-11T18:20:42.000Z",\ "created_at": "2024-07-10T18:20:42.000Z"\ }\ ], "pagination": { "total_records": 2, "current_page": 1, "total_pages": 1, "limit": 10 } } ``` ### GET /featured This endpoint will display a single Onchain Registry entry that is being actively featured #### Response JSON ```vocs_Code Copy{ "data": { "id": "7AsRdN8uf601fCkH1e084F", "category": "Creators", "content": { "title": "Based Project", "short_description": "Short description of this based project with max char count of 30", "full_description": "Full description of this based project with max char count of 200", "image_url": "https://base.org/image.png", "target_url": "https://base.org/target-page", "cta_text": "Mint", "function_signature": "mint(uint256)", "contract_address": "0x1FC10ef15E041C5D3C54042e52EB0C54CB9b710c", "token_id": "2", "token_amount": "0.01", "featured": true, "creator_name": "Base", "creator_image_url": "https://base.org/creator-image.png", "curation": "featured", "start_ts": "2024-06-25T04:00:00Z", "expiration_ts": "2024-07-29T00:00:00Z" }, "updated_at": null, "created_at": "2024-07-10T18:20:42.000Z" } } ``` ## Entry Schema | Name | Type | Description | | --- | --- | --- | | id | string | Unique entry ID | | category | string | The category of the entry
(Options: Games, Social, Creators, Finance, Media) | | title | string | The title of the entry | | short\_description | string | Short version of the entry description (max 30 char) | | full\_description | string | Full version of the entry description (max 200 char) | | image\_url | string | URL of the entry's featured image | | target\_url | string | URL for the entry's desired user action | | cta\_text | string | This is the type of user action for the entry
(Options: Play, Mint, Buy, Trade, Explore) | | function\_signature | string | The function signature associated with the desired user action on the entry's contract | | contract\_address | string | The contract address associated with the entry | | token\_id | string | The token ID if this is an ERC-1155 | | token\_amount | string | The price of the entry's desired user action | | featured | boolean | A true or false based on whether the entry is actively featured | | creator\_name | string | The name of the entry's creator | | creator\_image\_url | string | The logo of the entry's creator | | curation | string | The entry's level of curation
Options:
- Featured - one entry per day with top placement
- Curated - community entries being
- Community - all other community entries | | start\_ts | string | The UTC timestamp that the entry is open to users | | expiration\_ts | string | The UTC timestamp that the entry is no longer open to users | | updated\_at | string \|\| null | The UTC timestamp that the entry was last updated (null if the entry has not been updated since creation) | | created\_at | string | The UTC timestamp that the entry was created | ## Terms & Conditions We grant third parties a non-exclusive, worldwide, royalty-free license to use the Onchain Registry API solely for the purpose of integrating it into their applications or services. This license does not extend to any data or content accessed through the Onchain API, which remains the sole responsibility of the third party. By using the Onchain Registry API, third parties agree to comply with our license terms and any applicable laws and regulations as set forth in Coinbase Developer Platform Terms of Service. We make no warranties regarding the Onchain Registry API, and users accept all risks associated with its use. The Onchain App Registry API is an Early Access Product per Section 18 of the [Coinbase Developer Platform Terms of Service](https://www.coinbase.com/legal/developer-platform/terms-of-service) and the Coinbase [Prohibited Use Policy](https://www.coinbase.com/legal/prohibited_use), and all terms and conditions therein govern your use of the Onchain Registry API. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Blockchain Explorers [Skip to content](https://docs.base.org/chain/block-explorers#vocs-content) Menu Block Explorers On this page Chevron Right ## Arkham The Arkham [Platform](https://platform.arkhamintelligence.com/) supports Base. Arkham is a crypto intelligence platform that systematically analyzes blockchain transactions, showing users the people and companies behind blockchain activity, with a suite of advanced tools for analyzing their activity. ## Blockscout A Blockscout explorer is available for [Base](https://base.blockscout.com/). Blockscout provides tools to help you debug smart contracts and transactions: - View, verify, and interact with smart contract source code. - View detailed transaction information A testnet explorer for [Base Sepolia](https://base-sepolia.blockscout.com/) is also available. ## Etherscan An Etherscan block explorer is available for [Base](https://basescan.org/). Etherscan provides tools to help you view transaction data and debug smart contracts: - Search by address, transaction hash, batch, or token - View, verify, and interact with smart contract source code - View detailed transaction information - View L1-to-L2 and L2-to-L1 transactions A testnet explorer for [Base Sepolia](https://sepolia.basescan.org/) is also available. ## DexGuru [DexGuru](https://base.dex.guru/) provides a familiar UI with data on transactions, blocks, account balances and more. Developers can use it to verify smart contracts and debug transactions with interactive traces and logs visualization. ## L2scan Explorer [L2scan Explorer](https://base.l2scan.co/) is a web-based tool that allows users to analyze Base and other layer 2 networks. It provides a user-friendly interface for viewing transaction history, checking account balances, and tracking the status of network activity. ## OKLink [OKLink](https://www.oklink.com/base) is a multi-chain blockchain explorer that supports Base and provides the following features for developers: - Search by address, transaction, block, or token - View, verify, and interact with smart contract source code - Access a comprehensive and real-time stream of on-chain data, including large transactions and significant fund movements - Address labels (i.e. project labels, contract labels, risk labels, black address labels, etc.) ## Routescan [Routescan](https://routescan.io/) superchain explorer allows you to search for transactions, addresses, tokens, prices and other activities taking place across all Superchain blockchains, including Base. ## Tenderly Explorer With the [Tenderly](https://tenderly.co/) developer explorer you can get unparalleled visibility into your smart contract code. You can easily view detailed transaction information, spot bugs in your code, and optimize gas spend. Supporting Base mainnet and Base Sepolia testnet, Tenderly Explorer helps you track your smart contracts while providing visibility on a granular level. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Network Information [Skip to content](https://docs.base.org/chain/network-information#vocs-content) Menu Network Information On this page Chevron Right #### Base Mainnet | Name | Value | | --- | --- | | Network Name | Base Mainnet | | Description | The public mainnet for Base. | | RPC Endpoint | [https://mainnet.base.org](https://mainnet.base.org/)
_Rate limited and not for production systems._ | | Chain ID | 8453 | | Currency Symbol | ETH | | Block Explorer | [https://base.blockscout.com/](https://base.blockscout.com/) | #### Base Testnet (Sepolia) | Name | Value | | --- | --- | | Network Name | Base Sepolia | | Description | A public testnet for Base. | | RPC Endpoint | [https://sepolia.base.org](https://sepolia.base.org/)
_Rate limited and not for production systems._ | | Chain ID | 84532 | | Currency Symbol | ETH | | Block Explorer | [https://sepolia-explorer.base.org](https://sepolia-explorer.base.org/) | We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Blockchain Data Indexers [Skip to content](https://docs.base.org/chain/data-indexers#vocs-content) Menu Data Indexers On this page Chevron Right ## Allium [Allium](https://www.allium.so/) is an Enterprise Data Platform that serves accurate, fast, and simple blockchain data. Currently serving 15 blockchains and over 100+ schemas, Allium offers near real-time Base data for infrastructure needs and enriched Base data (NFT, DEX, Decoded, Wallet360) for research and analytics. Allium supports data delivery to multiple [destinations](https://docs.allium.so/integrations/overview), including Snowflake, Bigquery, Databricks, and AWS S3. Documentation: - [Real-time](https://docs.allium.so/real-time-data/base) - [Batch-enriched](https://docs.allium.so/data-tables/base) To get started, contact Allium [here](https://www.allium.so/contact). ## Arkham [Arkham](https://platform.arkhamintelligence.com/) is a crypto intelligence platform that systematically analyzes blockchain transactions, showing users the people and companies behind blockchain activity, with a suite of advanced tools for analyzing their activity. References: - [Platform guide](https://www.arkhamintelligence.com/guide) - [Whitepaper](https://www.arkhamintelligence.com/whitepaper) - [Codex](https://codex.arkhamintelligence.com/) - [Demos](https://www.youtube.com/@arkhamintel) ## Covalent [Covalent](https://www.covalenthq.com/?utm_source=base&utm_medium=partner-docs) is a hosted blockchain data solution providing access to historical and current on-chain data for [100+ supported blockchains](https://www.covalenthq.com/docs/networks/?utm_source=base&utm_medium=partner-docs), including [Base](https://www.covalenthq.com/docs/networks/base/?utm_source=base&utm_medium=partner-docs). Covalent maintains a full archival copy of every supported blockchain, meaning every balance, transaction, log event, and NFT asset data is available from the genesis block. This data is available via: 1. [Unified API](https://www.covalenthq.com/docs/unified-api/?utm_source=base&utm_medium=partner-docs) \- Incorporate blockchain data into your app with a familiar REST API 2. [Increment](https://www.covalenthq.com/docs/increment/?utm_source=base&utm_medium=partner-docs) \- Create and embed custom charts with no-code analytics To get started, [sign up](https://www.covalenthq.com/platform/?utm_source=base&utm_medium=partner-docs) and visit the [developer documentation](https://www.covalenthq.com/docs/?utm_source=base&utm_medium=partner-docs). #### Supported Networks - [Base Mainnet](https://www.covalenthq.com/docs/networks/base/?utm_source=base&utm_medium=partner-docs) - [Base Sepolia](https://www.covalenthq.com/docs/networks/base/?utm_source=base&utm_medium=partner-docs) (Testnet) ## DipDup [DipDup](https://dipdup.io/) is a Python framework for building smart contract indexers. It helps developers focus on business logic instead of writing a boilerplate to store and serve data. DipDup-based indexers are selective, which means only required data is requested. This approach allows to achieve faster indexing times and decreased load on underlying APIs. To get started, visit the [documentation](https://dipdup.io/docs/supported-networks/base) or follow the [quickstart](https://dipdup.io/docs/quickstart-evm) guide. ## Envio [Envio](https://envio.dev/) is a full-featured data indexing solution that provides application developers with a seamless and efficient way to index and aggregate real-time and historical blockchain data for any EVM. The indexed data is easily accessible through custom GraphQL queries, providing developers with the flexibility and power to retrieve specific information. Envio [HyperSync](https://docs.envio.dev/docs/hypersync) is an indexed layer of the Base blockchain for the hyper-speed syncing of historical data (JSON-RPC bypass). What would usually take hours to sync ~100,000 events can now be done in the order of less than a minute. Designed to optimize the user experience, Envio offers automatic code generation, flexible language support, multi-chain data aggregation, and a reliable, cost-effective hosted service. To get started, visit the [documentation](https://docs.envio.dev/docs/overview) or follow the [quickstart](https://docs.envio.dev/docs/quickstart) guide. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## GhostGraph [GhostGraph](https://ghostgraph.xyz/) makes it easy to build blazingly fast indexers (subgraphs) for smart contracts. GhostGraph is the first indexing solution that lets you write your index transformations in **Solidity**. Base dApps can query data with GraphQL using our hosted endpoints. To get started, you can [sign up for an account](https://app.ghostlogs.xyz/ghostgraph/sign-up) and follow [this quickstart](https://docs.ghostlogs.xyz/category/-getting-started-1) guide on how to create, deploy, and query a GhostGraph. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## The Indexing Company [The Indexing Company](https://www.indexing.co/) provides indexing as a service, capable of indexing any chain (EVM and non-EVM) with an RPC endpoint and integrating off-chain data within the same infrastructure. Our services include data transformations, aggregations, and streamlined data flows, allowing teams to develop their products faster while saving on developer resources, time, and money. Our solution is ideal for teams needing advanced data engineering for modular chain setups, multi-chain products, L1/L2/L3 chains and AI. To get started contact us [here](https://www.indexing.co/get-in-touch). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Moralis [Moralis](https://moralis.io/?utm_source=base-docs&utm_medium=partner-docs) offers comprehensive data APIs for crypto, offering both indexed and real-time data across 15+ chains. Moralis' APIs include portfolio and wallet balances, NFT data, token data, price data, candlestick data, net worth data, and a lot more. All of the data is enriched with things like metadata, parsed events and address labels. To get started with Moralis, you can [sign up for an account](https://moralis.io/?utm_source=base-docs&utm_medium=partner-docs), visit the Moralis [documentation](https://docs.moralis.io/?utm_source=base-docs&utm_medium=partner-docs), or check out their tutorials on [Youtube](https://www.youtube.com/c/MoralisWeb3). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Nexandria [Nexandria](https://www.nexandria.com/?utm_source=base-docs&utm_medium=partner-docs) API offers access to complete historical on-chain data at blazing speeds, arbitrary granularity (as low as block-level) and at viable unit economics (think web2 level costs). Our technology lets you generate subgraphs on the fly, unlocking unique endpoints like a statement of all the balance transfers for all the tokens, or a list of all the neighbors of an address with all the historical interaction details or a portfolio balance graph covering all the tokens across arbitrary time/block ranges. References: - [API Documentation](https://docs.nexandria.com/) - [Sign-up](https://www.nexandria.com/api) #### Supported Networks - Base Mainnet ## Shovel [Shovel](https://indexsupply.com/shovel) is an [open source](https://github.com/indexsupply/code) tool for synchronizing Ethereum data to your Postgres database. Shovel can index block data, transaction data, and decoded event data. A single Shovel can index multiple chains simultaneously. Shovel is configured via a declarative JSON config file – no custom functions to save indexed data to your database. Find out more in the [Shovel Docs](https://indexsupply.com/shovel/docs/) #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Subsquid [Subsquid](https://subsquid.io/) is a decentralized hyper-scalable data platform optimized for providing efficient, permissionless access to large volumes of data. It currently serves historical on-chain data, including event logs, transaction receipts, traces, and per-transaction state diffs. Subsquid offers a powerful toolkit for creating custom data extraction and processing pipelines, achieving an indexing speed of up to 150k blocks per second. To get started, visit the [documentation](https://docs.subsquid.io/) or see this [quickstart with examples](https://docs.subsquid.io/sdk/examples/) on how to easily create subgraphs via Subsquid. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## SubQuery [SubQuery](https://subquery.network/) is a data indexer that provides developers with fast, reliable, decentralized, and customized APIs for accessing rich indexed data from over 80+ ecosystems (including Base) within their projects. SubQuery provides the ability to aggregate this data across multiple blockchains, all within a single project. Other advantages of SubQuery includes performance with multiple RPC endpoint configurations, multi-worker capabilities and a configurable caching architecture. To get started, visit the [developer documentation](https://academy.subquery.network/) or follow [this step-by-step guide](https://academy.subquery.network/quickstart/quickstart_chains/base.html) on how to index any smart contract on Base. #### Supported Networks - [Base Mainnet](https://academy.subquery.network/quickstart/quickstart_chains/base.html) - Base Sepolia (Testnet) ## The Graph [The Graph](https://thegraph.com/) is an indexing protocol that provides an easy way to query blockchain data through APIs known as subgraphs. With The Graph, you can benefit from: - **Decentralized Indexing**: Enables indexing blockchain data through multiple indexers, thus eliminating any single point of failure - **GraphQL Queries**: Provides a powerful GraphQL interface for querying indexed data, making data retrieval super simple. - **Customization**: Define your own logic for transforming & storing blockchain data. Reuse subgraphs published by other developers on The Graph Network. Follow this [quick-start](https://thegraph.com/docs/en/quick-start/) guide to create, deploy, and query a subgraph within 5 minutes. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) See [all supported networks](https://thegraph.com/docs/en/#supported-networks) ## Flair [Flair](https://flair.dev/) is a real-time and historical custom data indexing for any EVM chain. It offers reusable **indexing primitives** (such as fault-tolerant RPC ingestors, custom processors and aggregations, re-org aware database integrations) to make it easy to receive, transform, store and access your on-chain data. To get started, visit the [documentation](https://docs.flair.dev/) or clone the [starter boilerplate](https://github.com/flair-sdk/starter-boilerplate) template and follow the instructions. #### Supported Networks - [Base Mainnet](https://docs.flair.dev/reference/manifest.yml) - [Base Sepolia](https://docs.flair.dev/reference/manifest.yml) (Testnet) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Account Abstraction Solutions [Skip to content](https://docs.base.org/chain/account-abstraction#vocs-content) Menu Account Abstraction On this page Chevron Right ## Alchemy Account Kit [Account Kit](https://www.alchemy.com/account-kit) is a complete solution for account abstraction. Using Account Kit, you can create a smart contract wallet for every user that leverages account abstraction to simplify every step of your app's onboarding experience. It also offers Gas Manager and Bundler APIs for sponsoring gas and batching transactions. ## Biconomy [Biconomy](https://www.biconomy.io/) is an Account Abstraction toolkit that enables you to provide the simplest UX for your dapp or wallet. It offers modular smart accounts, as well as paymasters and bundlers as a service for sponsoring gas and executing transactions at scale. ## Coinbase Account Abstraction Kit The Coinbase Developer Platform [Account Abstraction Kit](https://www.coinbase.com/developer-platform/solutions/account-abstraction-kit) is an account abstraction toolkit for building simple onchain user experiences. Account Abstraction Kit provides a paymaster and bundler that allows you to sponsor gas fees and bundle user transactions, improving the user experience of your application. ## 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. The platform vertically integrates the AA stack, so game developers can focus on game development without worrying about private key management, the account model or the onchain interactions with paymasters and bundlers. The Openfort platform is compatible with most EVM chains, including Base. ## Pimlico [Pimlico](https://pimlico.io/) provides an infrastructure platform that makes building smart accounts simpler. If you are developing, an ERC-4337 smart account, they provide bundlers, verifying paymasters, ERC-20 paymasters, and much more. ## Reown (prev. known as WalletConnect) **[Reown](https://reown.com/?utm_source=base&utm_medium=docs&utm_campaign=backlinks)** gives developers the tools to build user experiences that make digital ownership effortless, intuitive, and secure. One of Reown's offerings is the AppKit SDK. **AppKit** is a powerful, free, and fully open-source SDK for developers looking to integrate wallet connections and other Web3 functionalities into their apps on any EVM and non-EVM chain. In just a few simple steps, you can provide your users with seamless wallet access, one-click authentication, social logins, and notifications—streamlining their experience while enabling advanced features like on-ramp functionality, in-app token swaps and smart accounts. Check out the [docs](https://docs.reown.com/appkit/overview?utm_source=base&utm_medium=docs&utm_campaign=backlinks) to get started. ## Safe [Safe](https://docs.safe.global/getting-started/readme) provides modular smart account infrastructure and account abstraction stack via their Safe{Core} [Account Abstraction SDK](https://docs.safe.global/safe-core-aa-sdk/safe-core-sdk), [API](https://docs.safe.global/safe-core-api/supported-networks), and [Protocol](https://docs.safe.global/safe-core-protocol/safe-core-protocol). ## Stackup [Stackup](https://www.stackup.sh/) provides smart account tooling for building account abstraction within your apps. They offer Paymaster and Bundler APIs for sponsoring gas and sending account abstraction transactions. ## thirdweb [thirdweb](https://portal.thirdweb.com/typescript/v5/account-abstraction/get-started) offers the complete toolkit to leverage account abstraction technology to enable seamless user experiences for your users. This includes Account Factory contracts that let your users spin up Smart Accounts, Bundler for UserOps support, and Paymaster to enable gas sponsorships. ## WalletKit [WalletKit](https://walletkit.com/) is an all-in-one platform for adding smart, gasless wallets to your app. It has integrated support for ERC 4337 and comes with a paymaster and bundler included, requiring no extra setup. WalletKit also offers pre-built components for onboarding users with email and social logins, which can be integrated in under 15 minutes using their React SDK or the wagmi connector. Alternatively, build completely bespoke experiences for your users using WalletKit's Wallets API. WalletKit is compatible with most EVM chains, including Base. You can check out the [WalletKit documentation here](https://docs.walletkit.com/). Start building for free on the Base testnet today. ## ZeroDev [ZeroDev](https://zerodev.app/) is an embedded wallet powered by account abstraction. It offers you the ability to create self-custody wallets for your users, sponsor gas, and simplify user flows by batching and automating transactions. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Testnet ETH Faucets [Skip to content](https://docs.base.org/chain/network-faucets#vocs-content) Menu Network Faucets On this page Chevron Right ## Coinbase Developer Platform The [Coinbase Developer Platform Faucet](https://portal.cdp.coinbase.com/products/faucet) provides free testnet ETH on Base Sepolia - one claim per 24 hours. ## thirdweb Faucet The [thirdweb Faucet](https://thirdweb.com/base-sepolia-testnet) provides free testnet ETH on Base Sepolia - one claim per 24 hours. ## Superchain Faucet The [Superchain Faucet](https://app.optimism.io/faucet) provides testnet ETH for all OP Chains, including Base. ## Alchemy Faucet The [Alchemy Faucet](https://basefaucet.com/) is a fast and reliable network faucet that allows users with a free Alchemy account to request testnet ETH on Base Sepolia. ## Bware Labs Faucet [Bware Labs Faucet](https://bwarelabs.com/faucets) is an easy to use faucet with no registration required. You can use Bware Labs Faucet to claim Base Sepolia testnet ETH for free - one claim per 24 hours. ## QuickNode Faucet [QuickNode Faucet](https://faucet.quicknode.com/drip) is an easy to use Multi-Chain Faucet. You can use QuickNode Faucet to claim Base Sepolia testnet ETH for free - one drip per network every 12 hours. ## LearnWeb3 Faucet [LearnWeb3 Faucet](https://learnweb3.io/faucets/base_sepolia) is a multi-chain faucet by LearnWeb3. You can use the LearnWeb3 faucet to claim Base Sepolia testnet ETH for free - one claim every 24 hours. ## Ethereum Ecosystem Faucet The [Base Sepolia Faucet](https://www.ethereum-ecosystem.com/faucets/base-sepolia) is a free & easy to use testnet faucet for Base Sepolia with very generous drips that doesn't require users to log in. It's run by [Ethereum Ecosystem](https://www.ethereum-ecosystem.com/). We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Using Base Wallets [Skip to content](https://docs.base.org/chain/using-base#vocs-content) Menu Using Base On this page Chevron Right ## Coinbase Wallet The [Coinbase Wallet](https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en) browser extension provides support for Base by default. To use Base with Coinbase Wallet: 1. Open the Coinbase Wallet browser extension and log in to your account. 2. Connect to an app using Coinbase Wallet. 3. Open the network selection menu by clicking the network icon in the upper right-hand corner. 4. Select **Base**. Your active network should now be switched to Base. ## Other wallets Base can be added as a custom network to any EVM-compatible wallet (i.e. [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn)). ### MetaMask To add Base as a custom network to 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. 3. Click the **Add network** button. 4. Click **Add a network manually**. 5. In the **Add a network manually** dialog that appears, enter the following information for Base mainnet: | Name | Value | | --- | --- | | Network Name | Base Mainnet | | Description | The public mainnet for Base. | | RPC Endpoint | [https://mainnet.base.org](https://mainnet.base.org/) | | Chain ID | 8453 | | Currency Symbol | ETH | | Block Explorer | [https://base.blockscout.com/](https://base.blockscout.com/) | 6. Tap the Save button to save Base as a network. You should now be able to connect to the Base by selecting it from the network selection dropdown menu. ## Testnet #### Coinbase Wallet browser extension provides support for Base Sepolia testnet by default. To use Base Sepolia with Coinbase Wallet: 1. Open the Coinbase Wallet browser extension and log in to your account. 2. Connect to an app using Coinbase Wallet. 3. Open the network selection menu by clicking the network icon in the upper right-hand corner. 4. Click the **More networks** button. 5. Navigate to the **Testnets** tab. 6. Select **Base Sepolia**. 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 (e.g., [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn)). #### 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. 3. Click the **Add network** button. 4. Click **Add a network manually**. 5. In the **Add a network manually** dialog that appears, enter the following information for the Base Sepolia testnet: | Name | Sepolia | | --- | --- | | Network Name | Base Sepolia | | RPC Endpoint | [https://sepolia.base.org](https://sepolia.base.org/) | | Chain ID | 84532 | | Currency Symbol | ETH | | Block Explorer | [https://sepolia-explorer.base.org](https://sepolia-explorer.base.org/) | 6. Tap the Save button to save Base Sepolia as a network. You should now be able to connect to the Base testnet by selecting it from the network selection dropdown menu. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Node Providers [Skip to content](https://docs.base.org/chain/node-providers#vocs-content) Menu Node Providers On this page Chevron Right ## Coinbase Developer Platform (CDP) [CDP](https://portal.cdp.coinbase.com/) provides an RPC endpoint that runs on the same node infrastructure that powers Coinbase's retail exchange, meaning you get the rock solid reliability of our retail exchange as a developer. CDP gives you a free, rate limited RPC endpoint to begin building on Base. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## 1RPC [1RPC](https://1rpc.io/) is the first and only on-chain attested privacy preserving RPC that eradicates metadata exposure and leakage when interacting with blockchains. 1RPC offers free and [paid plans](https://www.1rpc.io/#pricing) with additional features and increased request limits. #### Supported Networks - Base Mainnet ## Alchemy [Alchemy](https://www.alchemy.com/base) is a popular API provider and developer platform. Its robust, free tier offers access to enhanced features like SDKs, [JSON-RPC APIs](https://docs.alchemy.com/reference/base-api-quickstart), and hosted mainnet and testnet nodes for Base. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## All That Node [All That Node](https://www.allthatnode.com/base.dsrv) is a comprehensive multi-chain development suite, designed to support multiple networks from a single platform. They offer free and [paid plans](https://www.allthatnode.com/pricing.dsrv) with additional features and increased request limits. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Ankr [Ankr](https://www.ankr.com/rpc/base/) provides private and public RPC endpoints for Base, powered by a globally distributed and decentralized network of nodes. They offer free and [paid plans](https://www.ankr.com/rpc/pricing/) with increased request limits. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Blast [Blast](https://blastapi.io/public-api/base) provides fast and reliable decentralized blockchain APIs by partnering with third-party Node Providers. Blast offers users the ability to generate their own [dedicated RPC endpoint for Base](https://blastapi.io/login). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Blockdaemon [Blockdaemon](https://www.blockdaemon.com/protocols/base/) offers access to hosted Base nodes with a free plan at $0/month via the Ubiquity Data API Suite. Extra costs may be incurred depending on usage. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## BlockPI [BlockPI](https://blockpi.io/) is a high-quality, robust, and efficient RPC service network that provides access to Base nodes with [free and paid plans](https://docs.blockpi.io/documentations/pricing). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Chainstack [Chainstack](https://chainstack.com/build-better-with-base/) allows developers to run high-performing Base nodes and APIs in minutes. They offer elastic Base RPC nodes that provide personal, geographically diverse, and protected API endpoints, as well as archive nodes to query the entire history of the Base Mainnet. Get started with their [free and paid pricing plans](https://chainstack.com/pricing/). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## DRPC [DRPC](https://drpc.org/) offers access to a distributed network of independent third-party partners and public nodes for Base. They provide a free tier that allows for an unlimited amount of requests over public nodes, or a paid tier which provides access to all providers, as well as other additional features. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## GetBlock [GetBlock](https://getblock.io/nodes/base/) is a Blockchain-as-a-Service (BaaS) platform that provides instant API access to full nodes for Base. They offer free, pay per use, and unlimited pricing plans. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## NodeReal [NodeReal](https://nodereal.io/) is a blockchain infrastructure and services provider that provides instant and easy-access to Base node APIs. #### Supported Networks - Base Mainnet ## Nodies DLB [Nodies DLB](https://nodies.app/) provides highly performant RPC Services for Base, as well as all other OP-stacked chains. They offer free public endpoints, Pay-As-You-Go, and enterprise pricing plans. #### Supported Networks - Base Mainnet - Base Testnet (Available on request) ## NOWNodes [NOWNodes](https://nownodes.io/nodes/basechain-base) is a Web3 development tool that provides shared and dedicated no rate-limit access to Base RPC full nodes. #### Supported Networks - Base Mainnet ## OnFinality [OnFinality](https://onfinality.io/) provides high performance archive access to Base Mainnet and Base Sepolia, with a generous free tier and high rate limits, as well as Trace and Debug APIs, available to [paid plans](https://onfinality.io/pricing). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## QuickNode [QuickNode](https://www.quicknode.com/chains/base) offers access to hosted Base nodes as part of their free Discover Plan. You can configure add-ons, like "Trace Mode" and "Archive Mode" for an additional cost by upgrading to one of their paid plans. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## RockX [RockX](https://access.rockx.com/) offers a global blockchain node network and developer tools for onchain innovation. Start with our free [Base RPC](https://access.rockx.com/product/base-blockchain-api-for-web3-builders) to access institutional-grade solutions. #### Supported Networks - Base Mainnet ## Stackup [Stackup](https://www.stackup.sh/) is a leading ERC-4337 infrastructure platform. You can access hosted Base nodes with built-in [account abstraction tools](https://docs.stackup.sh/docs) like bundlers and paymasters. #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## SubQuery [SubQuery](https://subquery.network/rpc) is a globally distributed, decentralized network of RPC nodes, offering generous free public endpoints and higher access through Flex Plans #### Supported Networks - Base Mainnet ## Tenderly Web3 Gateway [Tenderly Web3 Gateway](https://tenderly.co/web3-gateway) provides a fast and reliable hosted node solution with a built-in suite of developer tooling and infrastructure building blocks covering your whole development lifecycle. Develop, test, deploy, and monitor your onchain app on the Base network with both [free and paid plans](https://tenderly.co/pricing). #### Supported Networks - Base Mainnet - Base Sepolia (Testnet) ## Unifra [Unifra](https://base.unifra.io/) is a Web3 developer platform that provides tools, APIs, and node infrastructure, and provides access to Base nodes that are nodes are reliable, scalable, and easy to use. #### Supported Networks - Base Mainnet ## Validation Cloud [Validation Cloud](https://app.validationcloud.io/) is the world’s fastest node provider according to Compare Nodes. With 50 million compute units available for use without a credit card and a scale tier that never has rate limits, Validation Cloud is built to support your most rigorous and low-latency workloads. #### Supported Networks - Base Mainnet We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Terms of Service [Skip to content](https://docs.base.org/terms-of-service#vocs-content) Menu Terms of Service On this page Chevron Right Last Updated: October 25, 2024 * * * We’re excited you’re interested in Base, a layer-two optimistic rollup on the Ethereum public blockchain. While we do not control Base, these Terms of Service (“Terms”) constitute a legally binding contract made between you and Coinbase Technologies, Inc. (“Coinbase,” “we,” or “us”) that governs your access to and use of the Coinbase Sequencer, Base Testnet, Basenames Interface, and Basenames Profile Pages each of which is defined below (collectively, the “Services”). By using the Services in any way, you agree to be bound by these Terms. If you do not accept the terms and conditions of these Terms, you are not permitted to access or otherwise use the Services. **BEFORE WE INCLUDE ANY OTHER DETAILS, WE WANT TO GIVE YOU NOTICE OF SOMETHING UP FRONT: BY AGREEING TO THESE TERMS, YOU AND WE AGREE TO RESOLVE ANY DISPUTES WE MAY HAVE WITH EACH OTHER VIA BINDING ARBITRATION OR IN SMALL CLAIMS COURT (INSTEAD OF A COURT OF GENERAL JURISDICTION), AND YOU AGREE TO DO SO AS AN INDIVIDUAL (INSTEAD OF, FOR EXAMPLE, AS A REPRESENTATIVE OR MEMBER OF A CLASS IN A CLASS ACTION). TO THE EXTENT THAT THE LAW ALLOWS, YOU ALSO WAIVE YOUR RIGHT TO A TRIAL BY JURY. FOR MORE INFORMATION, SEE OUR [ARBITRATION AGREEMENT](https://docs.base.org/docs/arbitration) “DISPUTE RESOLUTION, ARBITRATION AGREEMENT, CLASS ACTION WAIVER, AND JURY TRIAL WAIVER.”** ### 1\. Base and Bridging Smart Contracts The Base protocol (“Base”) is an open source, optimistic rollup protocol that operates with the Ethereum blockchain. The Base protocol includes protocol smart contracts that allow you to “bridge” (i.e., lock assets on one blockchain protocol and replicate them on another protocol) digital assets between Ethereum and/or Base (“Bridging Smart Contracts”). **Neither Base nor the Bridging Smart Contracts are part of the Services.** They are both operated through the use of certain open source software such as the OP Stack, an open sourced codebase approved by a decentralized, representative body of Optimism governance (the “Optimism Collective”), and a set of smart contracts that once deployed to the Base protocol are not controlled by Coinbase (even if Coinbase contributed to their initial development). Coinbase does not control what third parties may build on Base, the activity of such parties, any user transacting on Base, or any data stored on Base itself, and Coinbase does not take possession, custody, or control over any virtual currency or other digital asset on Base or the Bridging Smart Contracts, unless expressly stated in a written contract signed by Coinbase. You acknowledge and agree that Coinbase makes no representations or warranties with respect to Base or the Bridging Smart Contracts, and that, if you use Base or the Bridging Smart Contracts, you do so at your own risk. ### 2\. Basenames Basenames is an open source blockchain-based naming protocol that maintains a registry of all domains and subdomains on Base through a series of smart contracts deployed on Base. Basenames is not part of the Services. Users may, through interacting with the Basenames, search such registry, register domains and subdomains and manage their registered names, including by adding metadata and other information (e.g., URLs) to the corresponding text records on the Basenames smart contract (such metadata and other information, the “Basename Profile Information”). The Basenames interface located at [https://base.org/names](https://base.org/names) (the “Basenames Interface”) is one, but not the exclusive, means of accessing Basenames. You are responsible for conducting your own diligence on other interfaces enabling you to access Basenames to understand the fees and risks that they present. You understand that anyone can register and own a domain name (and its subdomains) that is not already registered on the registry maintained by Basenames. You further understand that names registered on the registry maintained by Basenames may expire and you are responsible for monitoring and renewing the registration of such names. You acknowledge that Coinbase is not able to forcibly remove, prevent or otherwise interfere with the ability of any person to register a domain name on the registry operated by Basenames and you hereby acknowledge that Coinbase will not be liable for any claims or damages whatsoever associated with your use, inability to use any domain names subject of registration, or to be registered, on the registry maintained by Basenames. You agree that Basenames is purely non-custodial, meaning you are solely responsible for the custody of the cryptographic private keys to the digital asset wallets you hold and use to access Basenames. ### 3\. Who May Use the Services You may only use the Services if you are legally capable of forming a binding contract with Coinbase in your respective jurisdiction which may require your parents consent if you’re not the legal age of majority (which in many jurisdictions is 18), and not barred from using the Services under the laws of any applicable jurisdiction, for example, that you do not appear on the U.S. Treasury Department’s list of Specially Designated Nationals and are not located or organized in a U.S. sanctioned jurisdiction. If you are using the Services on behalf of an entity or other organization, you agree to these Terms for that entity or organization and represent to Coinbase that you have the authority to bind that entity or organization to these Terms. ### 4\. Rights We Grant You As between you and us, Coinbase is the owner of the Services, including all related intellectual property rights and proprietary content, information, material, software, images, text, graphics, illustrations, logos, trademarks (including the Base logo, the Base name, the Coinbase logo, the Coinbase name, and any other Coinbase or Base marks), service marks, copyrights, photographs, audio, video, music, and the “look and feel” of the Services. We hereby permit you to use and access the Services, provided that you comply with these Terms. If any software, content or other materials owned or controlled by us are distributed to you as part of your use of the Services, we hereby grant you a non-sublicensable, non-transferable, and non-exclusive right and license to execute, access and display such software, content and materials provided to you as part of the Services, in each case for the sole purpose of enabling you to use the Services as permitted by these Terms. To use any parts of the contents of the Services other than for personal and non-commercial use, you must seek permission from Coinbase in writing. Coinbase reserves the right to refuse permission without providing any reasons. ### 5\. Accessing the Services To access the Services, Base, or the Bridging Smart Contracts you must connect a compatible cryptocurrency wallet software (“Wallet”). Your relationship with any given Wallet provider is governed by the applicable terms of that Wallet provider, not these Terms. You are responsible for maintaining the confidentiality of any private key controlled by your Wallet and are fully responsible for any and all messages or conduct signed with your private key. We accept no responsibility or liability to you in connection with your use of a Wallet, and make no representations and warranties regarding how the Services, Base, or the Bridging Smart Contracts will operate or be compatible with any specific Wallet. We reserve the right, in our sole discretion, to prohibit certain Wallet addresses from being able to use or engage in transactions via the Coinbase Sequencer or from using other aspects of the Services. As between you and Coinbase, you retain ownership and all intellectual property rights to the content and materials you submit to the Services. But, you grant us a limited, non-exclusive, worldwide, royalty free license to use your content solely for the purpose of operating the Services (i.e., the Sequencer and Base Testnet) for so long as we operate the Services. To avoid any doubt, this license does not allow us to use your intellectual property beyond operating the Services (e.g., in advertisements). ### 6\. The Services Coinbase offers the following Services that enable you to access and interact with Base and the Bridging Smart Contracts: - **The Sequencer:** The Coinbase Sequencer is a node operated by Coinbase that receives, records, and reports transactions on Base. While The Coinbase Sequencer is, initially, the only sequencer node supporting transactions on Base, additional nodes may be provided by third parties in the future and there are other mechanisms for submitting transactions through Ethereum. The Coinbase Sequencer does not store, take custody of, control, send, or receive your virtual currency, except for receiving applicable gas fees. It also does not have the ability to modify, reverse, or otherwise alter any submitted transactions, and will not have access to your private key or the ability to control value on your behalf. We reserve the right to charge and modify the fees in connection with your use of the Coinbase Sequencer. These fees may also be subject to taxes under applicable law. - **Base Testnet:** The Base Testnet is a test environment that allows you to build applications integrated with Base. You are permitted to access and use the Base Testnet only to test and improve the experience, security, and design of Base or applications built on Base, subject to these Terms. Base Testnet Tokens will not be converted into any future rewards offered by Coinbase. Coinbase may change, discontinue, or terminate, temporarily or permanently, all or any part of the Base Testnet, at any time and without notice. - **Basenames Interface:** The Basenames Interface is a web application and graphical user display operated by Coinbase and located at base.org/names. It enables you to interact with Basenames by creating blockchain messages that you can sign and broadcast to Base using your Wallet. The Basenames Interface will not have access to your private key at any point. - **Basenames Profile Pages:** Coinbase also operates a web application and graphical user display (the “Basenames Profile Pages”) that renders information about all registered Basenames domains and subdomains on Base, including any Basename Profile Information associated therewith. You understand that the information displayed on the Basenames Profile Pages, including all Basename Profile Information, is stored and publicly available on the Basenames decentralized protocol. Coinbase provides the Basenames Profile Pages only as a convenience, does not have control over any of third party content appearing therein, and does not warrant or endorse, nor bear responsibility for the availability or legitimacy of, the content on or accessible from any Basenames Profile Page (including any resources, interactive features, or links to Third-Party Services (as defined below) displayed therein). When viewing any Basenames Profile Page, you should assume that Coinbase has not verified the safety or legitimacy of, any content, resources, interactive features, or links appearing on such Basenames Profile Page (including any Farcaster Frames (or other open source products that provide substantially similar functionality) rendered thereon). It is your responsibility to ensure that you fully understand the nature of any links or other interactive features that you may be able to access on a Basenames Profile Page, including any financial risks that you may be exposed to when interacting with a Third-Party Service. ### 7\. Acceptable Use You agree that you will not use the Services in any manner or for any purpose other than as expressly permitted by these Terms. That means, among other things, you will not use the Services to do or encourage any of the following: - Infringe or violate the intellectual property rights or any other rights of anyone else (including Coinbase) or attempt to decompile, disassemble, or reverse engineer the Services; - Violate any applicable law or regulation, including without limitation, any applicable anti-money laundering laws, anti-terrorism laws, export control laws, end user restrictions, privacy laws or economic sanctions laws/regulations, including those administered by the U.S. Department of Treasury’s Office of Foreign Assets Control; - Use the Services in a way that is illegal, dangerous, harmful, fraudulent, misleading, deceptive, threatening, harassing, defamatory, obscene, or otherwise objectionable; - Violate, compromise, or interfere with the security, integrity, or availability of any computer, network, or technology associated with the Services, including using the Services in a manner that constitutes excessive or abusive usage, attempts to disrupt, attack, or interfere with other users, or otherwise impacts the stability of the Services. - Use any Coinbase brands, logos, or trademarks (or any brands, logos, or trademarks that are confusingly similar) without our express prior written approval, which we may withhold at our discretion for any reason. ### 8\. Release and Assumption of Risk ‍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 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.” ### 9\. Interactions with Other Users You are responsible for your interactions with other users on or through the Services. While we reserve the right to monitor interactions between users, we are not obligated to do so, and we cannot be held liable for your interactions with other users, or for any user’s actions or inactions. If you have a dispute with one or more users, you release us (and our affiliates and subsidiaries, and our and their respective officers, directors, employees and agents) from claims, demands and damages (actual and consequential) of every kind and nature, known and unknown, arising out of or in any way connected with such disputes. In entering into this release you expressly waive any protections (whether statutory or otherwise) that would otherwise limit the coverage of this release to include only those claims which you may know or suspect to exist in your favor at the time of agreeing to this release. ### 10\. Feedback Any questions, comments, suggestions, ideas, feedback, reviews, or other information about the Services, provided by you to Coinbase, are non-confidential and Coinbase will be entitled to the unrestricted use and dissemination of these submissions for any purpose, commercial or otherwise, without acknowledgment, attribution, or compensation to you. ### 11\. Privacy For more information regarding our collection, use, and disclosure of personal data and certain other data, please see our [Privacy Policy](http://docs.base.org/privacy-policy). The processing of personal data by Coinbase as a processor will be subject to any data processing agreement that you enter into with Coinbase. ### 12\. Third-Party Services The Services may provide access to services, sites, technology, applications and resources that are provided or otherwise made available by third parties (“Third-Party Services”). Your access and use of Third-Party Services may also be subject to additional terms and conditions, privacy policies, or other agreements with such third parties. Coinbase has no control over and is not responsible for such Third-Party Services, including for the accuracy, availability, reliability, or completeness of information or content shared by or available through Third-Party Services, or on the privacy practices of Third-Party Services. We encourage you to review the privacy policies of Third-Party Services prior to using such services. You, and not Coinbase, will be responsible for any and all costs and charges associated with your use of any Third-Party Services. The integration or inclusion of such Third-Party Services does not imply an endorsement or recommendation. Any dealings you have with third parties while using the Services — including if a Third-Party Service may have infringed your intellectual property rights — are between you and the third party. Coinbase will not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any Third-Party Services. ### 13\. Additional Services We or our affiliates may offer additional services that interact with Base, which may require you to agree to additional terms. If, while using an additional service, there is a conflict between these Terms and the additional terms covering that service, the additional terms will prevail. ### 14\. Indemnification To the fullest extent permitted by applicable laws, you will indemnify and hold the Coinbase Entities harmless from and against any claims, disputes, demands, liabilities, damages, losses, and costs and expenses, including, without limitation, reasonable legal and accounting fees arising out of or in any way connected with (a) your access to or use of the Services, (b) your violation of these Terms, or (c) your negligence or willful misconduct. If you are obligated to indemnify any Coinbase Entity hereunder, then you agree that Coinbase (or, at its discretion, the applicable Coinbase Entity) will have the right, in its sole discretion, to control any action or proceeding and to determine whether Coinbase wishes to settle, and if so, on what terms, and you agree to fully cooperate with Coinbase in the defense or settlement of such claim. ### 15\. Warranty Disclaimers TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, BASE, THE BRIDGING SMART CONTRACTS, BASENAMES, AND THE SERVICES ARE PROVIDED ON AN “AS IS” AND “AS AVAILABLE” BASIS WITHOUT ANY REPRESENTATION OR WARRANTY, WHETHER EXPRESS, IMPLIED OR STATUTORY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, COINBASE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND/OR NON-INFRINGEMENT. THE COINBASE ENTITIES DO NOT MAKE ANY REPRESENTATIONS OR WARRANTIES THAT (I) ACCESS TO THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES WILL BE CONTINUOUS, UNINTERRUPTED, OR TIMELY; (II) THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES WILL BE COMPATIBLE OR WORK WITH ANY SOFTWARE, SYSTEM OR OTHER SERVICES, INCLUDING ANY WALLETS; (III) THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES WILL BE SECURE, COMPLETE, FREE OF HARMFUL CODE, OR ERROR-FREE; (IV) THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES WILL PREVENT ANY UNAUTHORIZED ACCESS TO, ALTERATION OF, OR THE DELETION, DESTRUCTION, DAMAGE, LOSS OR FAILURE TO STORE ANY OF YOUR CONTENT OR OTHER DATA; OR (V) THAT THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES WILL PROTECT YOUR ASSETS FROM THEFT, HACKING, CYBER ATTACK, OR OTHER FORM OF LOSS OR DEVALUATION CAUSED BY THIRD-PARTY CONDUCT. ### 16\. Limitation of Liability TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER THE COINBASE ENTITIES NOR THEIR RESPECTIVE SERVICE PROVIDERS INVOLVED IN CREATING, PRODUCING, OR DELIVERING THE SERVICES WILL BE LIABLE FOR ANY INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOST PROFITS, LOST REVENUES, LOST SAVINGS, LOST BUSINESS OPPORTUNITY, LOSS OF DATA OR GOODWILL, SERVICE INTERRUPTION, COMPUTER DAMAGE OR SYSTEM FAILURE, INTELLECTUAL PROPERTY INFRINGEMENT, OR THE COST OF SUBSTITUTE SERVICES OF ANY KIND ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT THE COINBASE ENTITIES OR THEIR RESPECTIVE SERVICE PROVIDERS HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL THE COINBASE ENTITIES’ TOTAL LIABILITY ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE SERVICES, BASE, THE BRIDGING SMART CONTRACTS, OR BASENAMES EXCEED THE AMOUNTS YOU HAVE PAID OR ARE PAYABLE BY YOU TO THE COINBASE ENTITIES FOR USE OF THE SERVICES OR ONE HUNDRED DOLLARS ($100), WHICHEVER IS HIGHER. THE EXCLUSIONS AND LIMITATIONS OF DAMAGES SET FORTH ABOVE ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN COINBASE AND YOU. IF ANY PORTION OF THESE SECTIONS IS HELD TO BE INVALID UNDER THE LAWS OF YOUR STATE OF RESIDENCE, THE INVALIDITY OF SUCH PORTION WILL NOT AFFECT THE VALIDITY OF THE REMAINING PORTIONS OF THE APPLICABLE SECTIONS. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL OR CERTAIN OTHER DAMAGES, SO THE ABOVE LIMITATIONS AND EXCLUSIONS MAY NOT APPLY TO YOU. ### 17\. Changes to Terms We reserve the right, in our sole discretion, to change these Terms at any time and your continued use of the Services after the date any such changes become effective constitutes your acceptance of the new Terms. You should periodically visit this page to review the current Terms so you are aware of any revisions. If you do not agree to abide by these or any future Terms, you are not permitted to access, browse, or use (or continue to access, browse, or use) the Services. ### 18\. Notice Any notices or other communications provided by us under these Terms, including those regarding modifications to these Terms, will be posted online, in the Services, or through other electronic communication. You agree and consent to receive electronically all communications, agreements, documents, notices and disclosures that we provide in connection with your use of the Services. ### 19\. Entire Agreement. These Terms and any other documents incorporated by reference comprise the entire understanding and agreement between you and Coinbase as to the subject matter hereof, and supersedes any and all prior discussions, agreements and understandings of any kind (including without limitation any prior versions of these Terms), between you and Coinbase. Section headings in these Terms are for convenience only and shall not govern the meaning or interpretation of any provision of these Terms. ### 20\. Assignment We reserve the right to assign our rights without restriction, including without limitation to any Coinbase affiliates or subsidiaries, or to any successor in interest of any business associated with the Services. In the event that Coinbase is acquired by or merged with a third party entity, we reserve the right, in any of these circumstances, to transfer or assign the information we have collected from you as part of such merger, acquisition, sale, or other change of control. You may not assign any rights and/or licenses granted under these Terms. Any attempted transfer or assignment by you in violation hereof shall be null and void. Subject to the foregoing, these Terms will bind and inure to the benefit of the parties, their successors and permitted assigns. ### 21\. Severability If any provision of these Terms is determined to be invalid or unenforceable under any rule, law, or regulation of any local, state, or federal government agency, such provision will be changed and interpreted to accomplish the objectives of the provision to the greatest extent possible under any applicable law and the validity or enforceability of any other provision of these Terms shall not be affected. ### 22\. Termination; Survival We may suspend or terminate your access to and use of the Services at our sole discretion, at any time and without notice to you. Upon any termination, discontinuation or cancellation of the Services, Sections 7 through 27 of the Terms will survive. ### 23\. Governing Law You agree that the laws of the State of California, without regard to principles of conflict of laws, will govern these Terms and any Dispute, except to the extent governed by federal law. ### 24\. Force Majeure We shall not be liable for delays, failure in performance or interruption of service which result directly or indirectly from any cause or condition beyond our reasonable control, including but not limited to, significant market volatility, act of God, act of civil or military authorities, act of terrorists, civil disturbance, war, strike or other labor dispute, fire, interruption in telecommunications or Internet services or network provider services, failure of equipment and/or software, pandemic, other catastrophe or any other occurrence which is beyond our reasonable control and shall not affect the validity and enforceability of any remaining provisions. ### 25\. Non-Waiver of Rights These Terms shall not be construed to waive rights that cannot be waived under applicable laws, including applicable state money transmission laws in the state where you are located. In addition, our failure to insist upon or enforce strict performance by you of any provision of these Terms or to exercise any right under these Terms will not be construed as a waiver or relinquishment to any extent of our right to assert or rely upon any such provision or right in that or any other instance. ### 26\. Relationship of the Parties 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. ### 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](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. #### Disputes with Users Who Reside in the United States or Canada If you reside in the United States or Canada, and if you have a dispute with us or if we have a dispute with you, the dispute shall be resolved through binding arbitration or in small claims court pursuant to the Arbitration Agreement in Appendix 1 below. As an illustration only, the following is a summary of some of the terms of the Arbitration Agreement: - Disputes will be resolved individually (in other words, you are waiving your right to proceed against Coinbase in a class action). However, if you or we bring a coordinated group of arbitration demands with other claimants, you and we agree that the American Arbitration Association (AAA) must batch your or our arbitration demand with up to 100 other claimants to increase the efficiency and resolution of such claims. - Certain disputes must be decided before a court, including (1) any claim that the class action waiver is unenforceable, (2) any dispute about the payment of arbitration fees, (3) any dispute about whether you have completed the prerequisites to arbitration (such as exhausting the support and Formal Complaint processes), (4) any dispute about which version of the Arbitration Agreement applies, and (5) any dispute about whether a dispute is subject to the Arbitration Agreement in the first instance. - In the event that a dispute is filed with a court that does not fall into one of the above five categories, either you or Coinbase may move to compel the court to order arbitration. If the court issues an order compelling arbitration, the prevailing party on the motion to compel may recover its reasonable attorneys’ fees and costs. #### Disputes with Users Who Reside Outside the United States and Canada If you do not reside in the United States or Canada, the Arbitration Agreement in Appendix 1 does not apply to you and you may resolve any claim you have with us relating to, arising out of, or in any way in connection with our Terms, us, or our Services in a court of competent jurisdiction. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Cross-Chain Solutions [Skip to content](https://docs.base.org/chain/cross-chain#vocs-content) Menu Cross-chain On this page Chevron Right ## Axelar [Axelar](https://axelar.network/) is an interchain platform that connects blockchains to enable universal web3 transactions. By integrating with Axelar, applications built on Base can now easily send messages and assets between the 49+ blockchains connected via Axelar. To learn more about Axelar visit our [docs](https://docs.axelar.dev/). For complete end-to-end examples demonstrating various Axelar use cases please visit the available [code examples](https://github.com/axelarnetwork/axelar-examples). #### Supported Networks - [Base Mainnet](https://docs.axelar.dev/resources/mainnet) - [Base Testnet](https://docs.axelar.dev/resources/testnet) #### Axelarscan To view current transactions and live stats about the Axelar network, please visit the [Axelarscan block explorer](https://axelarscan.io/) ## Crossmint [Crossmint](https://crossmint.com/?utm_source=backlinks&utm_medium=docs&utm_campaign=base) allows you to create and deploy NFT Collections and enable cross-chain payments. This enables your users and customers to purchase an NFT from a collection deployed on Base using Ethereum or Solana tokens. Check out [Crossmint Docs](https://docs.crossmint.com/nft-checkout/introduction/?utm_source=backlinks&utm_medium=docs&utm_campaign=base) to learn more about NFT Checkout with Crossmint. To power cross-chain payments, click [here](https://docs.crossmint.com/nft-checkout/pay-button/select-payment-options/?utm_medium=docs&utm_source=backlinks&utm_campaign=base) to get started. #### Supported Networks - [Base Mainnet](https://www.crossmint.com/products/nft-checkout/?utm_source=backlinks&utm_medium=docs&utm_campaign=base) - [Base Sepolia](https://www.crossmint.com/products/nft-checkout/?utm_source=backlinks&utm_medium=docs&utm_campaign=base) ## Chainlink CCIP [Chainlink CCIP](https://chain.link/cross-chain) is a secure interoperability protocol that allows for securely sending messages, transferring tokens, and initiating actions across different blockchains. To get started with integrating Chainlink CCIP in your Base project, visit the Chainlink CCIP [documentation](https://docs.chain.link/ccip). #### Supported Networks - [Base Mainnet](https://docs.chain.link/ccip/supported-networks/v1_0_0/mainnet#base-mainnet) - [Base Sepolia](https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet) (Testnet) ## LayerZero [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://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://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) ## Wormhole [Wormhole](https://wormhole.com/) is a generic messaging protocol that provides secure communication between blockchains. By integrating Wormhole, a Base application can access users and liquidity on > 30 chains and > 7 different platforms. See [this quickstart](https://docs.wormhole.com/wormhole/quick-start/tutorials/hello-wormhole) to get started with integrating Wormhole in your Base project. For more information on integrating Wormhole, visit their [documentation](https://docs.wormhole.com/wormhole/) and the provided [GitHub examples](https://github.com/wormhole-foundation/wormhole-examples). #### Supported Networks - [Base Mainnet](https://docs.wormhole.com/wormhole/blockchain-environments/evm#base) - [Base Sepolia](https://docs.wormhole.com/wormhole/blockchain-environments/evm#base) (Testnet) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## MiniKit Overview [Skip to content](https://docs.base.org/builderkits/minikit/overview#vocs-content) Menu Overview On this page Chevron Right ![MiniKit](https://docs.base.org/images/minikit/minikit-cli.gif) MiniKit is easiest way to build Mini Apps on Base, allowing developers to easily build applications without needing to know the details of the SDK implementation. It integrates seamlessly with OnchainKit components and provides Coinbase Wallet-specific hooks. ## Why MiniKit? MiniKit streamlines mini-app development by providing a comprehensive toolkit that makes complex Frames SDK interactions intuitive: - **Simplified Development:** Build apps with minimal knowledge of the Frames SDK - **Coinbase Wallet Integration:** Access Coinbase Wallet-specific hooks - **Component Compatibility:** Use [OnchainKit](https://onchainkit.xyz/) components out of the box with MiniKit - **Automatic Setup:** CLI tool for quick project scaffolding with webhooks and notifications - **Account Association:** Simplified generation of account associations ## Use Cases - Gaming mini apps - Social mini apps - Payment mini apps - And many more possibilities! ## Quick Start The fastest way to get started with MiniKit is to use the CLI to bootstrap a new project: ```vocs_Code Copynpx create-onchain --mini ``` This command will: 1. Set up a new project with both frontend and backend components 2. Configure webhooks and notifications 3. Set up account association generation 4. Create a demo app showcasing onchain abilities using OnchainKit After running the command, follow the prompts to configure your project. ## Provider The `MiniKitProvider` wraps your application and provides global access to the SDK's context. It handles initialization, events, and automatically applies client safeAreaInsets to ensure your app doesn't overlap parent application elements. ```vocs_Code Copyimport { MiniKitProvider } from '@coinbase/onchainkit/minikit'; function App({ children }) { return ( {children} ); } ``` ### Props The `MiniKitProvider` accepts the following props: ```vocs_Code Copyexport type MiniKitProviderReact = { children: React.ReactNode; notificationProxyUrl?: string; ...OnchainKitProviderProps }; ``` - `children`: React components to be wrapped by the provider - `notificationProxyUrl`: Optional URL to override the default `/api/notification` proxy - All props from `OnchainKitProvider` are also supported The provider sets up wagmi and react-query providers automatically. It configures connectors to use the Farcaster connector if `sdk.context` is set, with a fallback to CoinbaseWallet. This allows the same application to run both in frames and as a standalone application. ## Hooks MiniKit provides several utility hooks that wrap the SDK functionality, making it easy to access different features. ### useMiniKit This hook handles initialization of the application and provides access to the SDK context. ```vocs_Code Copyconst { setFrameReady, isFrameReady, context, updateClientContext, notificationProxyUrl } = useMiniKit(); // Call setFrameReady() when your app is ready to be shown useEffect(() => { if (!isFrameReady) { setFrameReady(); } }, [isFrameReady, setFrameReady]); ``` **Returns:** ```vocs_Code Copy{ ready: () => Promise; // Removes splash screen and shows the application isReady: boolean; // Whether the app is ready to be shown context: FrameContext | null; // The current frame context updateClientContext: (params: UpdateClientContextParams) => void; // Update client context notificationProxyUrl: string; // The notification proxy URL } ``` ### useAddFrame This hook adds a frame to the user's list of frames and returns notification details. ```vocs_Code Copyconst addFrame = useAddFrame(); // Usage const handleAddFrame = async () => { const result = await addFrame(); if (result) { console.log('Frame added:', result.url, result.token); } }; ``` **Returns:** ```vocs_Code Copy() => Promise<{ url: string; token: string; } | null> ``` ### useNotification This hook allows sending notifications to users who have added your frame. It requires a token and URL, which are returned when a user adds your frame. ```vocs_Code Copyconst sendNotification = useNotification(); // Usage const handleSendNotification = () => { sendNotification({ title: 'New High Score!', body: 'Congratulations on your new high score!' }); }; ``` ### useOpenUrl This hook wraps `sdk.actions.openUrl` and falls back to `window.open` when outside a frame context. ```vocs_Code Copyconst openUrl = useOpenUrl(); // Usage ``` ### useClose This hook wraps the `sdk.actions.close` functionality. ```vocs_Code Copyconst close = useClose(); // Usage ``` ### usePrimaryButton This hook accepts primary button options and a callback which will be called on click. ```vocs_Code CopyusePrimaryButton( { text: 'Submit Score' }, () => { // Handle button click submitScore(); } ); ``` ### useViewProfile This hook wraps `sdk.actions.viewProfile`, accepting an FID but falling back to the client's FID. ```vocs_Code Copyconst viewMyProfile = useViewProfile(); // Uses client's FID const viewUserProfile = useViewProfile(123456); // Uses specified FID // Usage ``` ### useAuthenticate This hook allows users to sign in with Farcaster. It wraps the SDK's signIn message, adding a default nonce and verification. ```vocs_Code Copyconst { signIn } = useAuthenticate(); // Usage const handleSignIn = async () => { const result = await signIn({ domain: 'your-domain.com', siweUri: 'https://your-domain.com/login' }); if (result) { // Handle successful authentication console.log('Authenticated:', result); } }; ``` ## CLI The MiniKit CLI is the easiest way to get started. It automatically creates a sample application that integrates different parts of the SDK and some OnchainKit components. ```vocs_Code Copynpx create-onchain --mini ``` ### Features The CLI creates an application with: 1. **Frontend and Backend Integration** - Complete setup for adding frames, webhooks, and notifications - Uses upstash/redis for data storage (compatible with Vercel) - Requires users to sign up for an upstash/redis account and add their key and URL to the .env file 2. **Account Association Generation** - Automatically generates valid account associations - Configures the necessary environment variables 3. **.well-known/farcaster.json Configuration** - Sets up the required configuration file: ```vocs_Code Copy{ "accountAssociation": { "header": "eyJmaWQiOjgxODAyNiwidHlwZSI6ImN1c3RvZHkiLCJrZXkiOiIweDU4YjU1MTNjMzk5OTYzMjU0MjMzMmU0ZTJlRDAyOThFQzFmRjE4MzEifQ", "payload": "eyJkb21haW4iOiI4MGI2LTI2MDAtMWYxOC0yNGM5LTYxMDUtNS0wLTQtNzA2Lm5ncm9rLWZyZWUuYXBwIn0", "signature": "MHhmOGQ1YzQyMmU3ZTZlMWNhMzU1ZmNmN2ZjYzFmYjMyZWRhZmEyNWU1NjJiMzlhYzE4OWNlMmM5ODU3Y2JjZWViNzlkZTk2ZjhiNTc5NzZjMDM2NzM4Y2UwYjhhOGQxZmMyZDFhYzA2NTdiZTU5N2VhZjFhZDE1ODBmMGQyYjJhODFi" }, "frame": { "version": "next", "name": "MiniKit", "iconUrl": "https://onchainkit.xyz/favicon/48x48.png?v4-19-24", "splashImageUrl": "https://onchainkit.xyz/favicon/48x48.png?v4-19-24", "splashBackgroundColor": "#000000", "homeUrl": "https://your-domain.app/minikit" } } ``` 4. **Notification Proxy** - Automatically sets up a proxy route at `/api/notification` - Used by the `useNotification` hook when sending notifications 5. **Webhooks** - Implements webhooks using the Farcaster key registry contract for verification - Allows applications to respond to events such as `FRAME_ADDED` ### Demo Application The CLI also creates a demo snake game application that showcases: - Buttons to add the frame and connect your wallet - High score tracking with attestations using OnchainKit's `` component - Score display using OnchainKit's `` components to resolve ENS names - Notifications for high scores (rate limited to one every 30 seconds) ## Next Steps Now that you have MiniKit set up, you can: 1. Explore the demo application to understand how the hooks work 2. Customize the application to fit your needs 3. Deploy your application to a hosting provider like Vercel Enjoy building! We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Base Asset Bridges [Skip to content](https://docs.base.org/chain/bridges-mainnet#vocs-content) Menu Bridges On this page Chevron Right While the bridge on bridge.base.org has been deprecated, there are many bridges that support moving assets between Base and other chains. For questions, see our [FAQ](https://docs.base.org/chain/bridges-mainnet#faq). ## Superbridge Superbridge enables you to bridge ETH and other supported assets from Ethereum mainnet (L1) directly to Base. #### Supported Networks - [Base Mainnet](https://superbridge.app/base) - [Base Sepolia (Testnet)](https://superbridge.app/base-sepolia) ## Brid.gg Brid.gg is another option that also helps you bridge ETH and supported assets between Ethereum mainnet (L1) and Base. #### Supported Networks - [Base Mainnet](https://brid.gg/base) - [Base Sepolia (Testnet)](https://testnet.brid.gg/base-sepolia) ## Disclaimer Coinbase Technologies, Inc., provides links to these independent service providers for your convenience but assumes no responsibility for their operations. Any interactions with these providers are solely between you and the provider. ## Programmatic Bridging See the [sample code repository](https://github.com/base-org/guides/tree/main/bridge/native) to see how to bridge ETH and ERC-20s from Ethereum to Base. **Double check the token address for ERC-20s** You can use any ERC-20 that is supported on the network. You can check what assets are on Base and the corresponding contract address via [this hub](https://github.com/ethereum-optimism/ethereum-optimism.github.io/tree/master/data). Ensure there is an address for `base`, [example](https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/data/WETH/data.json#L16-L18). Always test with small amounts to ensure the system is working as expected. This implementation only can bridge assets to Base. Do not attempt to alter the code to withdraw the assets. ## FAQ **Can I still use the bridge on bridge.base.org?** No, the bridge on bridge.base.org has been deprecated. **I used bridge.base.org in the past, how do I find my deposit or withdrawal?** Navigate to one of the Superchain Bridges to look up your transaction. **Why has Base deprecated the bridge on bridge.base.org?** Base is committed to decentralization and the Superchain vision. Leveraging the community to bootstrap the Superchain bridges is a step in that direction; increasing censorship resistance and decentralization. **Who operates the Superchain Bridges like Superbridge.com and Brid.gg?** Superchain Bridges are operated by third parties, not by Coinbase Technologies, Inc. ("Coinbase"). Coinbase does not control, operate, or assume any responsibility for the performance of these external platforms. Before using any Superchain Bridge, you may be required to agree to their terms and conditions. We strongly recommend you review these terms carefully, as well as any privacy policies, to understand your rights and obligations. The integration or inclusion of the Superchain Bridges does not imply an endorsement or recommendation of any bridge by Coinbase. **What if I have a question, issue, or problem?** The [Base Discord](https://base.org/discord) community is available around the clock for general questions, assistance and support! You can create a support ticket in the #general-support channel. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Checkout Types Overview [Skip to content](https://docs.base.org/builderkits/onchainkit/checkout/types#vocs-content) Menu Checkout On this page Chevron Right ## `LifecycleStatus` ```vocs_Code Copytype LifecycleStatus = | { statusName: 'init'; statusData: LifecycleStatusDataShared; } | { statusName: 'error'; statusData: TransactionError; } | { statusName: 'fetchingData'; statusData: LifecycleStatusDataShared; } | { statusName: 'ready'; statusData: { chargeId: string; contracts: ContractFunctionParameters[]; }; } | { statusName: 'pending'; statusData: LifecycleStatusDataShared; } | { statusName: 'success'; // if the last mutation attempt was successful statusData: { transactionReceipts: TransactionReceipt[]; chargeId: string; receiptUrl: string; }; }; ``` ## `CheckoutButtonReact` ```vocs_Code Copytype CheckoutButtonReact = { className?: string; coinbaseBranded?: boolean; disabled?: boolean; icon?: React.ReactNode; text?: string; }; ``` ## `CheckoutReact` ```vocs_Code Copytype CheckoutReact = { chargeHandler?: () => Promise; children: React.ReactNode; className?: string; isSponsored?: boolean; onStatus?: (status: LifecycleStatus) => void; productId?: string; }; ``` ## `CheckoutStatusReact` ```vocs_Code Copytype CheckoutStatusReact = { className?: string }; ``` We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## OnchainKit Config Types [Skip to content](https://docs.base.org/builderkits/onchainkit/config/types#vocs-content) Menu Config On this page Chevron Right ## `AppConfig` ```vocs_Code Copytype AppConfig = { appearance?: { name?: string | null; // The name of your application logo?: string | null; // The URL of your application logo mode?: Mode | null; // Optionally determines color scheme based on OS preference or user selection theme?: ComponentTheme | null; // Optionally sets the visual style for components }; paymaster?: string | null; // Paymaster URL for gas sponsorship }; ``` ## `isBaseOptions` ```vocs_Code Copytype isBaseOptions = { chainId: number; isMainnetOnly?: boolean; // If the chainId check is only allowed on mainnet }; ``` ## `isEthereumOptions` ```vocs_Code Copytype isEthereumOptions = { chainId: number; isMainnetOnly?: boolean; // If the chainId check is only allowed on mainnet }; ``` ## `OnchainKitConfig` ```vocs_Code Copytype OnchainKitConfig = { address: Address | null; // Address is optional as we may not have an address for new users apiKey: string | null; // ApiKey for Coinbase Developer Platform APIs chain: Chain; // Chain must be provided as we need to know which chain to use config?: AppConfig; // Configuration options for the app rpcUrl: string | null; // RPC URL for onchain requests. Defaults to using CDP Node if the API Key is set schemaId: EASSchemaUid | null; // SchemaId is optional as not all apps need to use EAS projectId: string | null; // ProjectId from Coinbase Developer Platform, only required for Coinbase Onramp support }; ``` ## `OnchainKitContextType` ```vocs_Code Copytype OnchainKitContextType = OnchainKitConfig; ``` ## `OnchainKitProviderReact` ```vocs_Code Copytype OnchainKitProviderReact = { address?: Address; apiKey?: string; chain: Chain; children: ReactNode; config?: AppConfig; rpcUrl?: string; schemaId?: EASSchemaUid; projectId?: string; }; ``` ## Smart Wallet Integration [Skip to content](https://docs.base.org/builderkits/onchainkit/wallet/wallet#vocs-content) Menu Wallet On this page Chevron Right The `` components provide an interface for users to connect their Smart Wallet with their identity information like Basename and ETH balance. It features built-in polished user experiences for both web and mobile web, making it incredibly easy to enhance with drop-in components. Before using them, ensure you've completed all [Getting Started steps](https://docs.base.org/builderkits/onchainkit/getting-started). ## Quick start The `WalletDefault` component is a simplified version of the `Wallet` component, designed to streamline the integration process for developers. Instead of manually defining each subcomponent and prop, developers can use this shorthand version which renders our suggested implementation of the component. If you'd like more customization, follow the implementation guide for our `Wallet` component below. ```vocs_Code Copyimport { WalletDefault } from '@coinbase/onchainkit/wallet'; ``` Connect Wallet ## Walkthrough ### Set up your wallet connections Kick off your wallet connection setup by configuring the `wagmi` provider. And make sure to update the `appName` as that will be displayed to the user when they connect their wallet. ```vocs_Code Copyimport { ReactNode } from 'react'; import { WagmiProvider, createConfig, http } from 'wagmi'; import { baseSepolia } from 'wagmi/chains'; import { coinbaseWallet } from 'wagmi/connectors'; const wagmiConfig = createConfig({ chains: [baseSepolia], connectors: [\ coinbaseWallet({\ appName: 'onchainkit',\ }),\ ], ssr: true, transports: { [baseSepolia.id]: http(), }, }); function App({ children }: { children: ReactNode }) { return {children}; } ``` ### Drop in the `` components Experience the magic by simply dropping in the `` component and watch it seamlessly come to life. Additionally, you can see the [``](https://docs.base.org/builderkits/onchainkit/identity/identity) components like [``](https://docs.base.org/builderkits/onchainkit/identity/avatar), [``](https://docs.base.org/builderkits/onchainkit/identity/name), and [`
`](https://docs.base.org/builderkits/onchainkit/identity/address) are used in a composable way. Explore their documentation pages to discover various customization options. ```vocs_Code Copyimport { ConnectWallet, Wallet, WalletDropdown, WalletDropdownDisconnect, } from '@coinbase/onchainkit/wallet'; import { Address, Avatar, Name, Identity, } from '@coinbase/onchainkit/identity'; import { color } from '@coinbase/onchainkit/theme'; export function WalletComponents() { return (
); } ``` Connect Wallet ### Drop in pre-made wallet components Expand the user experience with pre-made components like [``](https://docs.base.org/builderkits/onchainkit/wallet/wallet-dropdown-link), [``](https://docs.base.org/builderkits/onchainkit/wallet/wallet-dropdown-basename), [``](https://docs.base.org/builderkits/onchainkit/wallet/wallet-dropdown-fund-link), or ``, to help you build a seamless wallet experience for your users. The `` is highly versatile and will likely be your go-to choice for adding more links to the dropdown, connecting your users to various pages of your onchain app. ```vocs_Code Copyimport { ConnectWallet, Wallet, WalletDropdown, WalletDropdownBasename, WalletDropdownFundLink, WalletDropdownLink, WalletDropdownDisconnect, } from '@coinbase/onchainkit/wallet'; import { Address, Avatar, Name, Identity, EthBalance, } from '@coinbase/onchainkit/identity'; // omitted for brevity
Wallet ``` Connect Wallet ## Customize Connect button text and style Each OnchainKit component offers the flexibility to customize `className` and adjust the style of the React components it represents. Customize the connect wallet text by using directly the `` component. ```vocs_Code Copy// omitted for brevity Log In
Wallet ``` Log In ## Example usage ### Usage with Sign In With Ethereum (SIWE) To use [Sign In With Ethereum (SIWE)](https://docs.login.xyz/general-information/siwe-overview) with OnchainKit, you can use the `onConnect` prop in the `` component. This will trigger the SIWE prompt when the user connects their wallet. ```vocs_Code Copyimport { ConnectWallet } from '@coinbase/onchainkit/wallet'; import { base } from 'wagmi/chains'; import { createSiweMessage } from 'viem/siwe' import { useSignMessage } from 'wagmi'; const message = createSiweMessage({ address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', chainId: base.id, domain: 'example.com', nonce: 'foobarbaz', uri: 'https://example.com/path', version: '1', }) export function WalletComponents() { const { signMessage } = useSignMessage(); return ( {signMessage({ message })}} /> ); } ``` ## Components The components are designed to work together hierarchically. For each component, ensure the following: - `` \- Serves as the main container for all wallet-related components. - `` \- Handles the wallet connection process. Place child components inside to customize the connect button appearance. - `` \- Enables a wallet aggregation experience. - `` \- Contains additional wallet information and options. Place inside the `` component. - `` \- Displays user identity information. Place inside `` for a complete profile view. - `` \- Displays the user's Basename within the dropdown. - `` \- Creates a custom link within the dropdown. Use the `icon` prop to add an icon, and `href` to specify the destination. - `` \- Provides a disconnect option within the dropdown. Additional components for customizing the wallet interface include: - `` \- Displays the user's avatar image. - `` \- Shows the user's name or ENS. - `` \- Can be used to display additional user status or information. - `
` \- Shows the user's wallet address. - `` \- Displays the user's ETH balance. The Wallet component automatically handles the wallet connection state and updates the UI accordingly. You need to wrap your application or relevant part of it with these components to provide a complete wallet interaction experience. ## Component types - [`WalletReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletreact) - [`ConnectWalletReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#connectwalletreact) - [`WalletDropdownReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownreact) - [`WalletDropdownBasenameReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownbasenamereact) - [`WalletDropdownDisconnectReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdowndisconnectreact) - [`WalletDropdownLinkReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownlinkreact) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Introduction to Providers 404 The requested path could not be found ## App Security Best Practices [Skip to content](https://docs.base.org/chain/security/app-blocklist#vocs-content) Menu How to avoid getting your app flagged as malicious On this page Chevron Right * * * Ensuring that your app is perceived as trustworthy and not flagged as malicious requires attention to best practices. Here’s a quick guide on how to build a secure and compliant app from day one ## Smart Contracts - **Verify Source Code:** Ensure that the source code of your contracts is verified and publicly available on [block explorers](https://docs.base.org/chain/block-explorers). - **Audit Your Contracts**: Having your contracts audited by a reputable firm is crucial. Publish the audit report and provide a reference link to it, so users can easily find it. Audits show that you’ve taken extra steps to secure your smart contracts. - **Limit User Funds Exposure**: Design your contracts to minimize the exposure of user funds. Use efficient design to reduce any unnecessary risk. For example, request the minimum amount needed to fulfill the transaction. * * * ## App Best Practices - **Accessibility Across Regions**: Avoid geo-blocking or access restrictions that prevent certain regions or countries from accessing your app. - **Consistent Web2 Behavior**: Avoid rapid or unexplained changes in UI that can make users feel uncertain about the app’s reliability. - **Transparent Web3 Interactions**: Make sure your app’s web3 interactions are clear and match the UI actions. For example, a “Mint” button should clearly emit a mint transaction. - **Standard Sign-in Methods**: Provide all standard connection methods for users to sign in, such as WalletConnect / Coinbase Wallet SDK or popular browser extension wallets. * * * ## Verification Request Once you’ve implemented these best practices, consider submitting a verification request through the following [form](https://report.blockaid.io/). This step helps ensure that your app is recognized as safe and verified by trusted sources in the ecosystem. By following these recommendations, you’ll significantly reduce the chances of your app being flagged as malicious and foster a secure and trustworthy environment for your users. * * * We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Smart Wallet FAQ [Skip to content](https://docs.base.org/identity/smart-wallet/FAQ#vocs-content) Menu On this page Chevron Right ## How does Smart Wallet work with Coinbase Wallet mobile app and extension? For now, Smart Wallet is separate from wallet mobile and extension. Users sign on [keys.coinbase.com](https://keys.coinbase.com/) and can view and manage assets at [wallet.coinbase.com](https://wallet.coinbase.com/). See [Getting Started](https://docs.base.org/identity/smart-wallet/sdk/getting-started#parameters) documentation for nuances based on different configurations. ## Do users have the same address across chains? Yes, a user's Smart Wallet address will be the same across all supported chains. ## How much does it cost? Smart Wallet is free to use for both developers and users. ## Is Smart Wallet more expensive to use? Smart contract wallets use more gas per transaction than EOA wallets. This means they should be avoided on networks like Ethereum mainnet, but elsewhere the cost difference is negligible. For example, some current transaction costs on Base using Smart Wallet - ETH transfer: $0.03 - ERC-20 transfer: $0.06 ## Who is holding the keys? Smart wallets are secured by passkeys stored on the user's device. Passkeys are backed up with passkey providers such as Apple, Chrome, or 1Password, or on hardware such as YubiKeys. Passkey signatures are validated directly onchain via an [open source and audited smart contract](https://github.com/base-org/webauthn-sol). Coinbase never holds keys and never has access to user funds. ## What is a passkey? Passkeys are alternatives to passwords or other encrypted methods like recovery phrases, that are extremely easy to create and highly secure. They are end-to-end encrypted and linked to your Google or iCloud account, Chrome profile, or hardware device such as a YubiKey. This means users no longer have to deal with passwords or recovery phrases. Instead they can use common methods of authorization like touch or faceID, and be more resistant to phishing attempts. ## What happens if a user loses their passkey? Every Smart Wallet supports multiple owners, and our client will soon allow users to add a backup recovery key for the unlikely case they lose their passkey. ## Are there different gas limitations when using Smart Wallet? Smart Wallet transactions have additional gas overhead and require somewhat more conservative gas estimations. This means the maximum gas that can be consumed by a Smart Wallet transaction (user operation) is currently capped at 18 million gas, much lower than the block gas limit itself. It will be possible to increase this limit as L2 throughput continues to scale. ## Implications for `tx.origin` `tx.origin` is a global onchain variable that identifies the original sender of a transaction. In the case of Smart Wallet, `tx.origin` will be the address of the bundler EOA that submits user operations to the Entrypoint contract, and not the address of the Smart Wallet itself. Contracts that rely on `tx.origin` may not work as expected if the user is interacting with the contract via Smart Wallet. We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Social Media Links [Skip to content](https://docs.base.org/builderkits/onchainkit/identity/socials#vocs-content) Menu Socials On this page Chevron Right The `Socials` component displays social media links associated with Basenames and ENS names. It automatically fetches and renders social links stored in text records. ## Features - **Name Resolution:** Resolves both Basenames and ENS names to fetch associated social links - **Multiple Platform Support:** Supports Twitter, GitHub, Discord, and other major platforms - **Customizable Display:** Flexible styling options to match your app's design - **Chain-Aware:** Works across different EVM chains that support ENS ## Usage ### Basic Usage ```vocs_Code Copyimport { Address, Avatar, Badge, Identity, Name, Socials, } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains';
``` ![paul.base.eth](https://zku9gdedgba48lmr.public.blob.vercel-storage.com/basenames/avatar/paul.base.eth/1722120524815/FWUzoZmJ_400x400-kWjr2gMvjNe9hHMs9Z9LxGVGIME3By.jpg) paul.base.eth 0x4bEf...2FDFCopy [twitter](https://x.com/PaulCramer_) [github](https://github.com/cpcramer) [farcaster](https://warpcast.com/paulcramer) [website](https://onchainkit.xyz/) ### Standalone Usage You can also use the `Socials` component independently by providing an address: ```vocs_Code Copyimport { Socials } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; export default function StandaloneSocials() { return ( ); } ``` [twitter](https://x.com/PaulCramer_) [github](https://github.com/cpcramer) [farcaster](https://warpcast.com/paulcramer) [website](https://onchainkit.xyz/) ### Custom Chain Specify a different chain for ENS resolution: ```vocs_Code Copyimport { Address, Avatar, Badge, Identity, Name, Socials, } from '@coinbase/onchainkit/identity'; import { mainnet } from 'viem/chains';
``` ![paulcramer.eth](https://euc.li/paulcramer.eth) paulcramer.eth 0x4bEf...2FDFCopy [twitter](https://x.com/PaulCramer_) [github](https://github.com/cpcramer) ## Props The `Socials` component accepts the following props: | Prop | Type | Description | | --- | --- | --- | | `address` | `Address | null` | The Ethereum address to resolve social links for | | `ensName` | `string` | Optional ENS name to resolve social links for | | `chain` | `Chain` | The chain to use for ENS resolution | | `className` | `string` | Custom CSS classes to apply to the component | ## Error Handling The component handles various edge cases: - Returns `null` if no social links are found - Shows empty state while loading - Gracefully handles ENS resolution errors - Validates social links before display We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Onchain Checkout [Skip to content](https://docs.base.org/builderkits/onchainkit/checkout/checkout#vocs-content) Menu Checkout On this page Chevron Right The `Checkout` component provides a one-click checkout experience for onchain commerce - all for free. Our all-in-one solution simplifies payment processing for onchain developers, removing complex integrations, high fees, and onboarding friction. Whether you're selling digital goods, services, or in-game items, this tool is for you. ![Checkout](https://docs.base.org/images/onchainkit/checkout.gif) ## Features - **Plug-and-Play Integration:** Add our `Checkout` button with just a few lines of code. No backend required. - **Seamless Onboarding:** Support Passkey wallets to eliminate onboarding drop-offs. - **Real-time Merchant Tooling:** Get instant payment tracking, analytics, and reporting. - **Dynamic Payment Flows:** Generate charges on the fly, handle variable pricing, and pass in custom metadata. ## Prerequisites Before using the `Checkout` component, ensure you've completed the [Getting Started](https://docs.base.org/builderkits/onchainkit/getting-started) steps. ### Starting a new project If you're starting a new project, we recommend using `create onchain` to scaffold your project. ```vocs_Code Copynpm create onchain@latest ``` ### Adding to an existing project If you're adding `Checkout` to an existing project, simply install OnchainKit. npmyarnpnpmbun Terminal npm ```vocs_Code Copynpm install @coinbase/onchainkit ``` Wrap the `` around your app, following the steps in [Getting Started](https://docs.base.org/builderkits/onchainkit/getting-started#add-providers). ## Quickstart ### Option 1: Simple Product Checkout Ideal for fixed-price items. Get started with minimal setup. ### Sign up for a Coinbase Commerce account Head to [Coinbase Commerce](https://beta.commerce.coinbase.com/) and sign up. This is where you’ll manage transactions, view reports, and configure payments. ### Create a product and copy the `productId` In the Coinbase Commerce dashboard, create a new product and copy the `productId`. ### Import the component ```vocs_Code Copyimport { Checkout, CheckoutButton, CheckoutStatus } from '@coinbase/onchainkit/checkout'; // set coinbaseBranded for branding ``` ### Option 2: Dynamic Charges For variable pricing, custom metadata, or multi-product checkouts, use backend-generated charges. ### Sign up for a Coinbase Commerce account Head to [Coinbase Commerce](https://beta.commerce.coinbase.com/) and sign up. This is where you’ll manage transactions, view reports, and configure payments. ### Create a Coinbase Commerce API Key In the [Coinbase Commerce dashboard](https://beta.commerce.coinbase.com/settings/security), create a new API Key under `Security` in `Settings`. ### Set up a backend to create charges dynamically using the Coinbase Commerce API. See [Using chargeHandler](https://docs.base.org/builderkits/onchainkit/checkout/checkout#using-chargehandler) for a code example. ### Pass the chargeID into Checkout via the chargeHandler prop. ```vocs_Code Copyconst chargeHandler = async () => { const response = await fetch('/createCharge', { method: 'POST' }); const { id } = await response.json(); return id; // Return charge ID }; ``` That's it! Start selling onchain with just a few lines of code. ## Usage ### Configuring a checkout #### Using `productId` You can create products on the Coinbase Commerce Portal and use them in the `Checkout` component through the `productId` prop. ```vocs_Code Copy ``` Pay #### Using `chargeHandler` Alternatively, you can create charges dynamically using the Coinbase Commerce API [Create Charge](https://docs.cdp.coinbase.com/commerce-onchain/reference/creates-a-charge) endpoint by passing the chargeID into Checkout via the `chargeHandler` prop. This function must have the signature `() => Promise` and must return a valid chargeId created by the create charge endpoint. backend.tsfrontend.tsx File backend.ts ```vocs_Code Copy// This backend endpoint should create a charge and return the response. app.post('/createCharge', async (req: Request, res: Response) => { const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CC-Api-Key': 'your_api_key_here' // Replace this with your Coinbase Commerce API Key }, body: JSON.stringify({ local_price: { amount: '1', currency: 'USDC' }, pricing_type: 'fixed_price', metadata: { some_field: "some_value" } // Optional: Attach metadata like order ID or customer details }), }; const response = await fetch('https://api.commerce.coinbase.com/charges', options); const data = await response.json(); res.json(data); }); ``` Note that `productId` and `chargeHandler` are mutually exclusive and only one can be provided as a prop to Checkout. ### Handling a successful checkout To handle successful checkouts, use the `onStatus` prop to listen for the `success` callback. This callback will return a [LifecycleStatusData](https://docs.base.org/builderkits/onchainkit/checkout/checkout#advanced-usage) object including the [TransactionReceipt](https://github.com/wevm/viem/blob/main/src/types/transaction.ts#L38) and `chargeId`. For idempotent actions, like rendering your own success screen, you can simply check that the `statusName` is equal to `success`. For non-idempotent actions, like order fulfillment, we recommend one of the following approaches to verify a charge has been fully paid. 1. ( **Recommended**) Check the status of the `chargeId` using the [Coinbase Commerce API](https://docs.cdp.coinbase.com/commerce-onchain/docs/web3-payments-faq#how-can-i-verify-if-a-charge-has-been-fully-paid). 2. Set up a [Coinbase Commerce Webhook](https://docs.cdp.coinbase.com/commerce-onchain/docs/webhooks) which will notify you for successful payments. ```vocs_Code Copyimport type { LifecycleStatus } from '@coinbase/onchainkit/checkout'; const statusHandler = async (status: LifecycleStatus) => { const { statusName, statusData } = status; switch (statusName) { case 'success': // handle success const { chargeId } = statusData; // use the charges api to verify the chargeId const options = { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CC-Api-Key': 'your_api_key_here' // Replace this with your Coinbase Commerce API Key } }; const response = await fetch(`https://api.commerce.coinbase.com/charges/${chargeId}`); } } ``` ### Viewing successful checkouts You can view successful checkouts on the [Coinbase Commerce Merchant Dashboard](https://beta.commerce.coinbase.com/payments). ![Viewing successful checkouts](https://docs.base.org/images/onchainkit/commerce-3.png) ## Customization ### Add name and logo To customize the name and logo of your application rendered in the popup, set the `name` and `logo` values inside [OnchainKitProvider](https://docs.base.org/builderkits/onchainkit/config/onchainkit-provider#usage). File providers.tsx ```vocs_Code Copyimport { OnchainKitProvider } from '@coinbase/onchainkit'; {children} ``` ![Add name and logo](https://docs.base.org/images/onchainkit/commerce-4.png) ### Add Coinbase branding You can add Coinbase branding to the component by using the `coinbaseBranded` prop on `CheckoutButton`. ```vocs_Code Copy ``` Pay ### Disabling the button You can disable the button using the `disabled` prop on `CheckoutButton`. ```vocs_Code Copy ``` Pay ### Customize button You can customize the button text using the `text` prop on `CheckoutButton`. ```vocs_Code Copy ``` Checkout with USDC ### Override styles We recommend style customization by setting a custom [OnchainKit theme](https://docs.base.org/builderkits/onchainkit/guides/themes#custom-theme). You can also override individual component styles using `className`. ```vocs_Code Copy ``` Pay ## Advanced Usage ### Listening to the component lifecycle You can use our Checkout [`LifecycleStatus`](https://docs.base.org/builderkits/onchainkit/checkout/types#lifecyclestatus) and the `onStatus` prop to listen to transaction states. ```vocs_Code Copyimport type { LifecycleStatus } from '@coinbase/onchainkit/checkout'; const statusHandler = (status: LifecycleStatus) => { const { statusName, statusData } = status; switch (statusName) { case 'success': // handle success case 'pending': // handle payment pending case 'error': // handle error default: // handle 'init' state } } ``` ## Example use cases - **Demand-based pricing:** Allow users to select seats or ticket types for events, and dynamically calculate charges based on availability and demand. - **Product bundles:** Provide users with the option to create custom product bundles, applying discounts or special pricing based on the selected items. - **Freelance Services:** Allow clients to specify project details such as hours, deliverables, and deadlines, and generate charges based on these custom inputs. ## Components The components are designed to work together hierarchically. For each component, ensure the following: - `` \- Sets the `productId` or `chargeHandler` prop. - `` \- Branding and customization of the payment button. - `` \- The status of the payment. ## Props - [`LifecycleStatus`](https://docs.base.org/builderkits/onchainkit/checkout/types#lifecyclestatus) - [`CheckoutReact`](https://docs.base.org/builderkits/onchainkit/checkout/types#checkoutreact) - [`CheckoutButtonReact`](https://docs.base.org/builderkits/onchainkit/checkout/types#checkoutbuttonreact) - [`CheckoutStatusReact`](https://docs.base.org/builderkits/onchainkit/checkout/types#checkoutstatusreact) ## Contributing to OnchainKit [Skip to content](https://docs.base.org/builderkits/onchainkit/guides/contribution#vocs-content) Menu How to Contribute On this page Chevron Right Welcome to OnchainKit! So you want to contribute to this project? You came to the right place. In this guide, you will learn how to: - [Set up this project](https://docs.base.org/builderkits/onchainkit/guides/contribution#setup) - [Navigate the codebase](https://docs.base.org/builderkits/onchainkit/guides/contribution#codebase) - [Accomplish various workflows](https://docs.base.org/builderkits/onchainkit/guides/contribution#workflows) - [Submit a feature request](https://docs.base.org/builderkits/onchainkit/guides/contribution#feature-request) ## Setup ### Clone this repo ```vocs_Code Copygit clone git@github.com:coinbase/onchainkit.git ``` ### Install node + yarn Use nvm, mise, n or whatever works for you. Once node is installed, run this to enable yarn: ```vocs_Code Copycorepack enable ``` ### Install dependencies ```vocs_Code Copycd onchainkit yarn install ``` ## Codebase Here is a rough layout of this codebase: ```vocs_Code Copyonchainkit ├── src │   ├── core/ - Files with zero dependencies │   ├── token/ - Token │   │   ├── components/ - React components │   │   │ ├── {Name}.tsx │   │   │ ├── {Name}.test.tsx │   │   │ └── {Name}.css │   │   ├── core/ - Utility functions │   │   ├── index.ts - Entrypoint for the folder │   │   └── types.ts - Export types │   │ │   ├── index.ts - Typescript entrypoint │   ├── index.css - CSS entrypoint │   └── OnchainKitProvider.tsx - OnchainKit provider └── site/    ├── sidebar.ts - Controls sidebar for the doc site    └── docs/pages/**/*.mdx - Documentation location ``` ## Workflows ### Docs We use [Vocs](https://vocs.dev/) to power this site. Vocs includes support for [twoslash](https://vocs.dev/docs/guides/twoslash) to display types in code blocks on an opt-in basis. To enable twoslash in any ts/tsx code block you can add twoslash after your code block declaration, i.e. \`\`\`tsx twoslash If your codeblock is not valid, you will see errors generated from twoslash. If you cannot resolve these errors in code, it is possible to suppress twoslash using the [noErrors](https://vocs.dev/docs/guides/twoslash#noerrors) syntax. ```vocs_Code Copy// @noErrors: 2304 - Cannot find name ``` ### Storybook Storybook is a frontend workshop for building UI components and pages in isolation. It helps you develop and share hard-to-reach states and edge cases without needing to run your whole app. To develop and test your components in Storybook, run the following command: ```vocs_Code Copyyarn storybook:dev # In a browser, navigate to http://localhost:6006/ ``` ### Testing Write and update existing unit tests. You can watch file changes and rerun tests automatically like this: ```vocs_Code Copyyarn test --watch ``` We expect 100% code coverage for any updates. You can get coverage information with: ```vocs_Code Copyyarn test:coverage ``` If the coverage drops below 100%, look at the coverage report generated by the above command with: ```vocs_Code Copyopen coverage/index.html ``` ### Testing UI with hot reload We use this doc site to test UI changes. Navigate to the markdown used for the given file you are updating (i.e. `site/docs/pages/identity/avatar.mdx`) and change the import using relative import path like this: ```vocs_Code Copyimport { Avatar } from '../../../../src/identity'; ``` To bring up the doc site, run: ```vocs_Code Copycd site yarn install yarn dev # In a browser, navigate to http://localhost:5173 ``` Your changes should automatically reflect in the doc site ### Updating changelog To update the change log, run: ```vocs_Code Copyyarn changeset ``` Select `minor` and use the following format for the summary: ```vocs_Code Copy- **feat**: feature update information. By @your-github-id #XX (XX is the PR number) ``` Use possible values are: - `feat` - `fix` - `docs` - `chore` ## Feature request Have a component in mind that we are not supporting yet? You can submit a feature request to our [Github](https://github.com/coinbase/onchainkit/issues). Create a **"New issue"** and label it "Feature Request: ..." ## Tailwind CSS Integration [Skip to content](https://docs.base.org/builderkits/onchainkit/guides/tailwind#vocs-content) Menu Tailwind CSS Integration On this page Chevron Right OnchainKit comes with first class support for `tailwindcss`. ### Use default OnchainKit's style You can use the default styles without any customization. Just place this at the top of your application's entry point to have the components work out of the box. ```vocs_Code Copyimport '@coinbase/onchainkit/styles.css'; ``` ### Tailwind CSS Config Depending on your dark mode setup, you may have to add `safelist: ['dark']` to your Tailwind config. ```vocs_Code Copy/** @type {import('tailwindcss').Config} */ export default { content: ['./src/**/*.{ts,tsx}'], darkMode: ['class'], safelist: ['dark'], theme: { fontFamily: { sans: ['Inter', 'sans-serif'], }, }, plugins: [], }; ``` ### Toggling light / dark mode There are many ways to handle color mode. In OnchainKit, toggling color mode works by adding / removing class name `dark` to the root html tag. ### Colorscheme override To override default colorscheme, you need to modify the following css variables: ```vocs_Code Copy@tailwind base; @layer base { :root { --ock-font-family: 'your-custom-value'; --ock-border-radius: 'your-custom-value'; --ock-border-radius-inner: 'your-custom-value'; --ock-text-inverse: 'your-custom-value'; --ock-text-foreground: 'your-custom-value'; --ock-text-foreground-muted: 'your-custom-value'; --ock-text-error: 'your-custom-value'; --ock-text-primary: 'your-custom-value'; --ock-text-success: 'your-custom-value'; --ock-text-warning: 'your-custom-value'; --ock-text-disabled: 'your-custom-value'; --ock-bg-default: 'your-custom-value'; --ock-bg-default-hover: 'your-custom-value'; --ock-bg-default-active: 'your-custom-value'; --ock-bg-alternate: 'your-custom-value'; --ock-bg-alternate-hover: 'your-custom-value'; --ock-bg-alternate-active: 'your-custom-value'; --ock-bg-inverse: 'your-custom-value'; --ock-bg-inverse-hover: 'your-custom-value'; --ock-bg-inverse-active: 'your-custom-value'; --ock-bg-primary: 'your-custom-value'; --ock-bg-primary-hover: 'your-custom-value'; --ock-bg-primary-active: 'your-custom-value'; --ock-bg-primary-washed: 'your-custom-value'; --ock-bg-primary-disabled: 'your-custom-value'; --ock-bg-secondary: 'your-custom-value'; --ock-bg-secondary-hover: 'your-custom-value'; --ock-bg-secondary-active: 'your-custom-value'; --ock-bg-error: 'your-custom-value'; --ock-bg-warning: 'your-custom-value'; --ock-bg-success: 'your-custom-value'; --ock-bg-default-reverse: 'your-custom-value'; --ock-icon-color-primary: 'your-custom-value'; --ock-icon-color-foreground: 'your-custom-value'; --ock-icon-color-foreground-muted: 'your-custom-value'; --ock-icon-color-inverse: 'your-custom-value'; --ock-icon-color-error: 'your-custom-value'; --ock-icon-color-success: 'your-custom-value'; --ock-icon-color-warning: 'your-custom-value'; --ock-line-primary: 'your-custom-value'; --ock-line-default: 'your-custom-value'; --ock-line-heavy: 'your-custom-value'; --ock-line-inverse: 'your-custom-value'; } } ``` ## Gasless Transactions Guide [Skip to content](https://docs.base.org/use-cases/go-gasless#vocs-content) Menu Go gasless On this page Chevron Right Base transaction fees are typically less than a penny, but the concept of gas can still be confusing for new users and lead to poor user experience when users don't have gas funds in their wallet. You can abstract this away and improve your UX by using the **Base Paymaster**. The Paymaster allows you to: - Batch multi-step transactions - Create custom gasless experiences - Sponsor up to $15k monthly on mainnet (unlimited on testnet) ## Objectives 1. Configure security measures to ensure safe and reliable transactions. 2. Manage and allocate resources for sponsored transactions. 3. Subsidize transaction fees for users, enhancing the user experience by making transactions free. 4. Set up and manage sponsored transactions on various schedules, including weekly, monthly, and daily cadences. ## Prerequisites This tutorial assumes you have: 1. **A Coinbase Cloud Developer Platform Account** If not, sign up on the [CDP site](https://portal.cdp.coinbase.com/). Once you have your account, you can manage projects and utilize tools like the Paymaster. 2. **Familiarity with Smart Accounts and ERC 4337** Smart Accounts are the backbone of advanced transaction patterns (e.g., bundling, sponsorship). If you’re new to ERC 4337, check out external resources like the official [EIP-4337 explainer](https://eips.ethereum.org/EIPS/eip-4337) before starting. 3. **Foundry** Foundry is a development environment, testing framework, and smart contract toolkit for Ethereum. You’ll need it installed locally for generating key pairs and interacting with smart contracts. ## Set Up a Base Paymaster & Bundler In this section, you will configure a Paymaster to sponsor payments on behalf of a specific smart contract for a specified amount. 1. **Navigate to the [Coinbase Developer Platform](https://portal.cdp.coinbase.com/).** 2. Create or select your project from the upper left corner of the screen. 3. Click on the **Paymaster** tool from the left navigation. 4. Go to the **Configuration** tab and copy the **RPC URL** to your clipboard — you’ll need this shortly in your code. ### Screenshots - **Selecting your project** ![cdp-home.png](https://docs.base.org/images/gasless-transaction-on-base/cdp-select-project.png) - **Navigating to the Paymaster tool** ![cdp-paymaster-tool.png](https://docs.base.org/images/gasless-transaction-on-base/cdp-paymaster.png) - **Configuration screen** ![cdp-paymaster-tool.png](https://docs.base.org/images/gasless-transaction-on-base/cdp-config.png) ### Allowlist a Sponsorable Contract 1. From the Configuration page, ensure **Base Mainnet** (or **Base Sepolia** if you’re testing) is selected. 2. Enable your paymaster by clicking the toggle button. 3. Click **Add** to add an allowlisted contract. 4. For this example, add [`0x83bd615eb93eE1336acA53e185b03B54fF4A17e8`](https://basescan.org/token/0x83bd615eb93ee1336aca53e185b03b54ff4a17e8), and add the function `mintTo(address)`. ![cdp-allowlist-contracts.png](https://docs.base.org/images/gasless-transaction-on-base/cdp-allowlist-contract.png) ### Global & Per User Limits Scroll down to the **Per User Limit** section. You can set: - **Dollar amount limit** or **number of UserOperations** per user - **Limit cycles** that reset daily, weekly, or monthly For example, you might set: - `max USD` to `$0.05` - `max UserOperation` to `1` This means **each user** can only have $0.05 in sponsored gas and **1** user operation before the cycle resets. Next, **set the Global Limit**. For example, set this to `$0.07` so that once the entire paymaster has sponsored $0.07 worth of gas (across all users), no more sponsorship occurs unless you raise the limit. ![cdp-global-user-limits.png](https://docs.base.org/images/gasless-transaction-on-base/cdp-global-user-limits.png) ## Test Your Paymaster Policy Now let’s verify that these policies work. We’ll: 1. Create two local key pairs (or use private keys you own). 2. Generate two Smart Accounts. 3. Attempt to sponsor multiple transactions to see your policy in action. ### Installing Foundry 1. Ensure you have **Rust** installed ```vocs_Code Copycurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` 2. Install Foundry ```vocs_Code Copycurl -L https://foundry.paradigm.xyz | bash foundryup ``` 3. Verify it works ```vocs_Code Copycast --help ``` If you see Foundry usage info, you’re good to go! ### Create Your Project & Generate Key Pairs 1. Make a new folder and install dependencies, `viem` and `permissionless`: ```vocs_Code Copymkdir sponsored_transactions cd sponsored_transactions npm init es6 npm install permissionless npm install viem touch index.js ``` 2. Generate two key pairs with Foundry: ```vocs_Code Copycast wallet new cast wallet new ``` You’ll see something like: ```vocs_Code CopySuccessfully created new keypair. Address: 0xD440D746... Private key: 0x01c9720c1dfa3c9... ``` **Store these private keys somewhere safe** ### Project Structure With Environment Variables Create a `.env` file in the `sponsored_transactions` directory. In the `.env`, you'll add the rpcURL for your paymaster and the private keys for your accounts: ```vocs_Code CopyPAYMASTER_RPC_URL=https://api.developer.coinbase.com/rpc/v1/base/ PRIVATE_KEY_1=0x01c9720c1dfa3c9... PRIVATE_KEY_2=0xbcd6fbc1dfa3c9... ``` ## Example `index.js` Below is a full example of how you might structure `index.js`. ```vocs_Code Copy// --- index.js --- // @noErrors // 1. Import modules and environment variables import 'dotenv/config'; import { http, createPublicClient, encodeFunctionData } from 'viem'; import { base } from 'viem/chains'; import { createSmartAccountClient } from 'permissionless'; import { privateKeyToSimpleSmartAccount } from 'permissionless/accounts'; import { createPimlicoPaymasterClient } from 'permissionless/clients/pimlico'; // 2. Retrieve secrets from .env // Highlight: environment variables for paymaster, private keys const rpcUrl = process.env.PAYMASTER_RPC_URL; // highlight const firstPrivateKey = process.env.PRIVATE_KEY_1; // highlight const secondPrivateKey = process.env.PRIVATE_KEY_2; // highlight // 3. Declare Base addresses (entrypoint & factory) const baseEntryPoint = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'; const baseFactoryAddress = '0x15Ba39375ee2Ab563E8873C8390be6f2E2F50232'; // 4. Create a public client for Base const publicClient = createPublicClient({ chain: base, transport: http(rpcUrl), }); // 5. Setup Paymaster client const cloudPaymaster = createPimlicoPaymasterClient({ chain: base, transport: http(rpcUrl), entryPoint: baseEntryPoint, }); // 6. Create Smart Accounts from the private keys async function initSmartAccounts() { const simpleAccount = await privateKeyToSimpleSmartAccount(publicClient, { privateKey: firstPrivateKey, factoryAddress: baseFactoryAddress, entryPoint: baseEntryPoint, }); const simpleAccount2 = await privateKeyToSimpleSmartAccount(publicClient, { privateKey: secondPrivateKey, factoryAddress: baseFactoryAddress, entryPoint: baseEntryPoint, }); // 7. Create SmartAccountClient for each const smartAccountClient = createSmartAccountClient({ account: simpleAccount, chain: base, bundlerTransport: http(rpcUrl), middleware: { sponsorUserOperation: cloudPaymaster.sponsorUserOperation, }, }); const smartAccountClient2 = createSmartAccountClient({ account: simpleAccount2, chain: base, bundlerTransport: http(rpcUrl), middleware: { sponsorUserOperation: cloudPaymaster.sponsorUserOperation, }, }); return { smartAccountClient, smartAccountClient2 }; } // 8. ABI for the NFT contract const nftAbi = [\ // ...\ // truncated for brevity\ ]; // 9. Example function to send a transaction from a given SmartAccountClient async function sendTransaction(client, recipientAddress) { try { // encode the "mintTo" function call const callData = encodeFunctionData({ abi: nftAbi, functionName: 'mintTo', args: [recipientAddress], // highlight: specify who gets the minted NFT }); const txHash = await client.sendTransaction({ account: client.account, to: '0x83bd615eb93eE1336acA53e185b03B54fF4A17e8', // address of the NFT contract data: callData, value: 0n, }); console.log(`✅ Transaction successfully sponsored for ${client.account.address}`); console.log(`🔍 View on BaseScan: https://basescan.org/tx/${txHash}`); } catch (error) { console.error('Transaction failed:', error); } } // 10. Main flow: init accounts, send transactions (async () => { const { smartAccountClient, smartAccountClient2 } = await initSmartAccounts(); // Send a transaction from the first account await sendTransaction(smartAccountClient, smartAccountClient.account.address); // Send a transaction from the second account // For variety, let’s also mint to the second account's own address await sendTransaction(smartAccountClient2, smartAccountClient2.account.address); })(); ``` Now that the code is implemented, lets run it: Run this via `node index.js` from your project root. ```vocs_Code Copynode index.js ``` You should see a "Transaction successfully sponsored" output. To confirm that your spend policies are correctly in place, try running the script again. If your Paymaster settings are strict (e.g., limit 1 transaction per user), the second time you run the script, you may get a “request denied” error, indicating the policy is working. ## Hitting Policy Limits & Troubleshooting 1. **Per-User Limit** If you see an error like: ```vocs_Code Copy{ "code": -32001, "message": "request denied - rejected due to maximum per address transaction count reached" } ``` That means you’ve hit your **UserOperation** limit for a single account. Return to the [Coinbase Developer Platform](https://portal.cdp.coinbase.com/) UI to adjust the policy. 2. **Global Limit** If you repeatedly run transactions and eventually see: ```vocs_Code Copy{ "code": -32001, "message": "request denied - rejected due to max global usd spend limit reached" } ``` You’ve hit the **global** limit of sponsored gas. Increase it in the CDP dashboard and wait a few minutes for changes to take effect. ## Verifying Token Ownership (Optional) Want to confirm the token actually minted? You can read the NFT’s `balanceOf` function: ```vocs_Code Copyimport { readContract } from 'viem'; // highlight // example function async function checkNftBalance(publicClient, contractAddress, abi, ownerAddress) { const balance = await publicClient.readContract({ address: contractAddress, abi, functionName: 'balanceOf', args: [ownerAddress], }); console.log(`NFT balance of ${ownerAddress} is now: ${balance}`); } ``` ## Conclusion In this tutorial, you: - Set up and **configured** a Base Paymaster on the Coinbase Developer Platform. - **Allowlisted** a contract and specific function ( `mintTo`) for sponsorship. - Established **per-user** and **global** sponsorship **limits** to control costs. - Demonstrated the **sponsorship flow** with Smart Accounts using `permissionless`, `viem`, and Foundry-generated private keys. This approach can greatly improve your dApp’s user experience by removing gas friction. For more complex sponsorship schemes (like daily or weekly cycles), simply tweak your per-user and global limit settings in the Coinbase Developer Platform. > **Next Steps** > > - Use a [proxy service](https://www.smartwallet.dev/guides/paymasters) for better endpoint security. > - Deploy your own contracts and allowlist them. > - Experiment with bundling multiple calls into a single sponsored transaction. ## References - [list of factory addresses](https://docs.alchemy.com/reference/factory-addresses) - [Discord](https://discord.com/invite/cdp) - [CDP site](https://portal.cdp.coinbase.com/) - [Coinbase Developer Platform](https://portal.cdp.coinbase.com/) - [UI](https://portal.cdp.coinbase.com/products/bundler-and-paymaster) - [proxy service](https://www.smartwallet.dev/guides/paymasters) - [Paymaster Tool](https://portal.cdp.coinbase.com/products/bundler-and-paymaster) - [Foundry Book installation guide](https://book.getfoundry.sh/getting-started/installation) - [simple NFT contract](https://basescan.org/token/0x83bd615eb93ee1336aca53e185b03b54ff4a17e8) **Happy Building on Base!** ## Base MiniKit Guide 404 The requested path could not be found ## Deploy Smart Contracts [Skip to content](https://docs.base.org/cookbook/smart-contract-development/foundry/deploy-with-foundry#vocs-content) Menu Deploy with Foundry On this page Chevron Right This article will provide an overview of the [Foundry](https://book.getfoundry.sh/) development toolchain, and show you how to deploy a contract to **Base Sepolia** testnet. Foundry is a powerful suite of tools to develop, test, and debug your smart contracts. It comprises several individual tools: - `forge`: the main workhorse of Foundry — for developing, testing, compiling, and deploying smart contracts - `cast`: a command-line tool for performing Ethereum RPC calls (e.g., interacting with contracts, sending transactions, and getting onchain data) - `anvil`: a local testnet node, for testing contract behavior from a frontend or over RPC - `chisel`: a Solidity [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop), for trying out Solidity snippets on a local or forked network Foundry offers extremely fast feedback loops (due to the under-the-hood Rust implementation) and less context switching — because you'll be writing your contracts, tests, and deployment scripts **All** in Solidity! ## Objectives By the end of this tutorial, you should be able to do the following: - Setup Foundry for Base - Create an NFT smart contract for Base - Compile a smart contract for Base (using `forge`) - Deploy a smart contract to Base (also with `forge`) - Interact with a smart contract deployed on Base (using `cast`) ## Prerequisites ### Foundry This tutorial requires you have Foundry installed. - From the command-line (terminal), run: `curl -L https://foundry.paradigm.xyz | bash` - Then run `foundryup`, to install the latest (nightly) build of Foundry For more information, see the Foundry Book [installation guide](https://book.getfoundry.sh/getting-started/installation). ### Coinbase Wallet In order to deploy a smart contract, you will first need a web3 wallet. You can create a wallet by downloading the Coinbase Wallet browser extension. - Download [Coinbase Wallet](https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en) ### Wallet funds Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees. For this tutorial, you will be deploying a contract to the Base Sepolia test network. You can fund your wallet with Base Sepolia ETH using one of the faucets listed on the Base [Network Faucets](https://docs.base.org/chain/network-faucets) page. ## Creating a project Before you can begin deploying smart contracts to Base, you need to set up your development environment by creating a Foundry project. To create a new Foundry project, first create a new directory: ```vocs_Code Copymkdir myproject ``` Then run: ```vocs_Code Copycd myproject forge init ``` This will create a Foundry project, which has the following basic layout: ```vocs_Code Copy. ├── foundry.toml ├── script │   └── Counter.s.sol ├── src │   └── Counter.sol └── test └── Counter.t.sol ``` ## Compiling the smart contract Below is a simple NFT smart contract ( [ERC-721](https://eips.ethereum.org/EIPS/eip-721)) written in the Solidity programming language: ```vocs_Code Copy// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol"; contract NFT is ERC721 { uint256 public currentTokenId; constructor() ERC721("NFT Name", "NFT") {} function mint(address recipient) public payable returns (uint256) { uint256 newItemId = ++currentTokenId; _safeMint(recipient, newItemId); return newItemId; } } ``` The Solidity code above defines a smart contract named `NFT`. The code uses the `ERC721` interface provided by the [OpenZeppelin Contracts library](https://docs.openzeppelin.com/contracts/5.x/) to create an NFT smart contract. OpenZeppelin allows developers to leverage battle-tested smart contract implementations that adhere to official ERC standards. To add the OpenZeppelin Contracts library to your project, run: ```vocs_Code Copyforge install openzeppelin/openzeppelin-contracts ``` In your project, delete the `src/Counter.sol` contract that was generated with the project and add the above code in a new file called `src/NFT.sol`. (You can also delete the `test/Counter.t.sol` and `script/Counter.s.sol` files, but you should add your own tests ASAP!). To compile our basic NFT contract using Foundry, run: ```vocs_Code Copyforge build ``` ## Configuring Foundry with Base Next, you will configure your Foundry project to deploy smart contracts to the Base network. First you'll store your private key in an encrypted keystore, then you'll add Base as a network. ### Storing your private key The following command will import your private key to Foundry's secure keystore. You will be prompted to enter your private key, as well as a password for signing transactions: ```vocs_Code Copycast wallet import deployer --interactive ``` For instructions on how to get your private key from Coinbase Wallet, visit the [Coinbase Wallet documentation](https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key). **It is critical that you do NOT commit this to a public repo**. Run this command to confirm that the 'deployer' account is setup in Foundry: ```vocs_Code Copycast wallet list ``` ### Adding Base as a network When verifying a contract with BaseScan, you need an API key. You can get your BaseScan API key from [here](https://basescan.org/myapikey) after you sign up for an account. Although they're made by the same folks, Etherscan API keys will **not** work on BaseScan! Now create a `.env` file in the home directory of your project to add the Base network and an API key for verifying your contract on BaseScan: ```vocs_Code CopyBASE_MAINNET_RPC="https://mainnet.base.org" BASE_SEPOLIA_RPC="https://sepolia.base.org" ETHERSCAN_API_KEY="" ``` Note that even though you're using BaseScan as your block explorer, Foundry expects the API key to be defined as `ETHERSCAN_API_KEY`. ### Loading environment variables Now that you've created the above `.env` file, run the following command to load the environment variables in the current command line session: ```vocs_Code Copysource .env ``` ## Deploying the smart contract With your contract compiled and your environment configured, you are ready to deploy to the Base Sepolia test network! Today, you'll use the `forge create` command, which is a straightforward way to deploy a single contract at a time. In the future, you may want to look into [`forge script`](https://book.getfoundry.sh/guides/scripting-with-solidity), which enables scripting onchain transactions and deploying more complex smart contract projects. You'll need testnet ETH in your wallet. See the [prerequisites](https://docs.base.org/cookbook/smart-contract-development/foundry/deploy-with-foundry#prerequisites) if you haven't done that yet. Otherwise, the deployment attempt will fail. To deploy the contract to the Base Sepolia test network, run the following command. You will be prompted to enter the password that you set earlier, when you imported your private key: ```vocs_Code Copyforge create ./src/NFT.sol:NFT --rpc-url $BASE_SEPOLIA_RPC --account deployer ``` The contract will be deployed on the Base Sepolia test network. You can view the deployment status and contract by using a [block explorer](https://docs.base.org/chain/block-explorers) and searching for the address returned by your deploy script. If you've deployed an exact copy of the NFT contract above, it will already be verified and you'll be able to read and write to the contract using the web interface. Regardless of the network you're deploying to, if you're deploying a new or modified contract, you'll need to verify it. ## Verifying the Smart Contract In web3, it's considered best practice to verify your contracts so that users and other developers can inspect the source code, and be sure that it matches the deployed bytecode on the blockchain. Further, if you want to allow others to interact with your contract using the block explorer, it first needs to be verified. The above contract has already been verified, so you should be able to view your version on a block explorer already, but we'll still walk through how to verify a contract on Base Sepolia testnet. Grab the deployed address and run: ```vocs_Code Copyforge verify-contract ./src/NFT.sol:NFT --chain 84532 --watch ``` You should see an output similar to: ```vocs_Code CopyStart verifying contract `0x71bfCe1172A66c1c25A50b49156FAe45EB56E009` deployed on base-sepolia Submitting verification for [src/NFT.sol:NFT] 0x71bfCe1172A66c1c25A50b49156FAe45EB56E009. Submitted contract for verification: Response: `OK` GUID: `3i9rmtmtyyzkqpfvy7pcxj1wtgqyuybvscnq8d7ywfuskss1s7` URL: https://sepolia.basescan.org/address/0x71bfce1172a66c1c25a50b49156fae45eb56e009 Contract verification status: Response: `NOTOK` Details: `Pending in queue` Contract verification status: Response: `OK` Details: `Pass - Verified` Contract successfully verified ``` Search for your contract on [BaseScan](https://sepolia.basescan.org/) to confirm it is verified. ## Interacting with the Smart Contract If you verified on BaseScan, you can use the `Read Contract` and `Write Contract` sections under the `Contract` tab to interact with the deployed contract. To use `Write Contract`, you'll need to connect your wallet first, by clicking the `Connect to Web3` button (sometimes this can be a little finicky, and you'll need to click `Connect` twice before it shows your wallet is successfully connected). To practice using the `cast` command-line tool which Foundry provides, you'll perform a call without publishing a transaction (a read), then sign and publish a transaction (a write). ### Performing a call A key component of the Foundry toolkit, `cast` enables us to interact with contracts, send transactions, and get onchain data using Ethereum RPC calls. First you will perform a call from your account, without publishing a transaction. From the command-line, run: ```vocs_Code Copycast call --rpc-url $BASE_SEPOLIA_RPC "balanceOf(address)" ``` You should receive `0x0000000000000000000000000000000000000000000000000000000000000000` in response, which equals `0` in hexadecimal. And that makes sense — while you've deployed the NFT contract, no NFTs have been minted yet and therefore your account's balance is zero. ### Signing and publishing a transaction Now, sign and publish a transaction, calling the `mint(address)` function on the NFT contract you just deployed. Run the following command: ```vocs_Code Copycast send --rpc-url=$BASE_SEPOLIA_RPC "mint(address)" --account deployer ``` If successful, Foundry will respond with information about the transaction, including the `blockNumber`, `gasUsed`, and `transactionHash`. Finally, let's confirm that you did indeed mint yourself one NFT. If you run the first `cast call` command again, you should see that your balance increased from 0 to 1: ```vocs_Code Copycast call --rpc-url $BASE_SEPOLIA_RPC "balanceOf(address)" ``` And the response: `0x0000000000000000000000000000000000000000000000000000000000000001` ( `1` in hex) — congratulations, you deployed a contract and minted an NFT with Foundry! ## Conclusion Phew, that was a lot! You learned how to setup a project, deploy to Base, and interact with our smart contract using Foundry. The process is the same for real networks, just more expensive — and of course, you'll want to invest time and effort testing your contracts, to reduce the likelihood of user-impacting bugs before deploying. For all things Foundry, check out the [Foundry book](https://book.getfoundry.sh/), or head to the official Telegram [dev chat](https://t.me/foundry_rs) or [support chat](https://t.me/foundry_support). ## Crypto Earning Interface [Skip to content](https://docs.base.org/builderkits/onchainkit/earn/earn#vocs-content) Menu Earn On this page Chevron Right The `Earn` component provides a simple interface for earning interest on your crypto via Morpho vaults on Base. ## Prerequisites Before using the `Earn` component, ensure you've completed the [Getting Started](https://docs.base.org/builderkits/onchainkit/getting-started) steps. ### Starting a new project If you're starting a new project, we recommend using `create onchain` to scaffold your project. ```vocs_Code Copynpm create onchain@latest ``` ### Adding to an existing project If you're adding `Earn` to an existing project, simply install OnchainKit. npmyarnpnpmbun Terminal npm ```vocs_Code Copynpm install @coinbase/onchainkit ``` Wrap the `` around your app, following the steps in [Getting Started](https://docs.base.org/builderkits/onchainkit/getting-started#add-providers). ## Quickstart To use `Earn`, you'll need to provide a `vaultAddress` prop. A vault address can be obtained from Morpho's [Vaults page](https://app.morpho.org/base/earn). ```vocs_Code Copyimport { Earn } from '@coinbase/onchainkit/earn'; ``` ## Customization ### Custom components and layouts `Earn` accepts a `children` prop that can be used to render `Earn` subcomponents or custom components. For instance, you can render the `EarnDeposit` component by itself within the `Earn` component, along with any other custom components you'd like to render. ```vocs_Code Copyimport { Earn, EarnDeposit } from '@coinbase/onchainkit/earn';
Custom header
Custom footer
``` For more granular control, you can also render lower level subcomponents within `EarnDeposit` and `EarnWithdraw`. These subcomponents accept `className` props to customize their styles. ```vocs_Code Copyimport { Earn, EarnDeposit, EarnDetails, DepositBalance, DepositAmountInput, DepositButton } from '@coinbase/onchainkit/earn'; ``` ### Customizing styles The `Earn` component is best styled via a [OnchainKit theme](https://docs.base.org/builderkits/onchainkit/guides/themes#custom-theme). You can also override individual component styles using `className`. ## Advanced Usage If you'd like to implement your own custom components, you can use `useEarnContext` within an `Earn` component to access context and build your own components. You can find the full interface for `EarnContextType` on the [Types page](https://docs.base.org/builderkits/onchainkit/earn/types#earncontexttype). Below, we use `useEarnContext` to implement a custom deposit interface by using `useEarnContext` to access the `depositAmount` and `setDepositAmount` context values. index.tsxcustom-deposit-buttons.tsx File index.tsx ```vocs_Code Copyimport { Earn, useEarnContext } from '@coinbase/onchainkit/earn'; import { CustomDepositButtons } from '@/custom-deposit-buttons'; ``` Taking advantage of the data and methods provided by `useEarnContext`, developers can implement fully custom deposit and withdraw interfaces, modifying everything from UI elements to input behavior. ## Examples ### Sponsoring transactions To sponsor transactions, you can use the `isSponsored` prop. ```vocs_Code Copy ``` Ensure that your `OnchainKitProvider` has a `paymaster` configured: ```vocs_Code Copy ``` ## Components The `Earn` component includes the following subcomponents: - `` \- A fully built Withdraw and Deposit component. Also includes a `children` prop to render custom components and provides `useEarnContext` to access the context values. - `` \- A headless provider that provides the `useEarnContext` hook to the `Earn` component. - `` \- A fully built deposit card. - `` \- A fully built withdraw card. - `` \- A component that displays the details of the vault. - `` \- A component that handles the deposit amount input. - `` \- A component that displays the balance underlying asset in the user's wallet. - `` \- A component that triggers the deposit transaction. - `` \- A component that handles the withdraw amount input. - `` \- A component that displays how much the user can withdraw from a vault. - `` \- A component that triggers the withdraw transaction. - `` \- A component that displays the yield details of the vault. - `` \- A component that displays the vault details. ## Hooks - [`useEarnContext`](https://docs.base.org/builderkits/onchainkit/hooks/use-earn-context) \- A hook that provides the context values of the `Earn` component. - [`useBuildDepositToMorphoTx`](https://docs.base.org/builderkits/onchainkit/hooks/use-build-deposit-to-morpho-tx) \- A hook that builds a deposit transaction to Morpho. - [`useBuildWithdrawFromMorphoTx`](https://docs.base.org/builderkits/onchainkit/hooks/use-build-withdraw-from-morpho-tx) \- A hook that builds a withdraw transaction from Morpho. - [`useMorphoVault`](https://docs.base.org/builderkits/onchainkit/hooks/use-morpho-vault) \- A hook that provides the details of a Morpho vault. ## Props - [`LifecycleStatus`](https://docs.base.org/builderkits/onchainkit/earn/types#lifecyclestatus) - [`EarnReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earnreact) - [`EarnProviderReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earnproviderreact) - [`EarnContextType`](https://docs.base.org/builderkits/onchainkit/earn/types#earncontexttype) - [`EarnAmountInputReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earnamountinputreact) - [`DepositAmountInputReact`](https://docs.base.org/builderkits/onchainkit/earn/types#depositamountinputreact) - [`WithdrawAmountInputReact`](https://docs.base.org/builderkits/onchainkit/earn/types#withdrawamountinputreact) - [`EarnBalanceReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earnbalancereact) - [`DepositBalanceReact`](https://docs.base.org/builderkits/onchainkit/earn/types#depositbalancereact) - [`WithdrawBalanceReact`](https://docs.base.org/builderkits/onchainkit/earn/types#withdrawbalancereact) - [`EarnDepositReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earndepositreact) - [`EarnWithdrawReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earnwithdrawreact) - [`EarnDetailsReact`](https://docs.base.org/builderkits/onchainkit/earn/types#earndetailsreact) - [`DepositButtonReact`](https://docs.base.org/builderkits/onchainkit/earn/types#depositbuttonreact) - [`WithdrawButtonReact`](https://docs.base.org/builderkits/onchainkit/earn/types#withdrawbuttonreact) ## Swap Types Overview [Skip to content](https://docs.base.org/builderkits/onchainkit/swap/types#vocs-content) Menu Swap On this page Chevron Right ## `Fee` ```vocs_Code Copytype Fee = { amount: string; // The amount of the fee baseAsset: Token; // The base asset for the fee percentage: string; // The percentage of the fee }; ``` ## `QuoteWarning` ```vocs_Code Copytype QuoteWarning = { description?: string; // The description of the warning message?: string; // The message of the warning type?: string; // The type of the warning }; ``` ## `LifecycleStatus` ```vocs_Code Copytype LifecycleStatusDataShared = { isMissingRequiredField: boolean; maxSlippage: number; }; type LifecycleStatus = | { statusName: 'init'; statusData: LifecycleStatusDataShared; } | { statusName: 'error'; statusData: SwapError & LifecycleStatusDataShared; } | { statusName: 'amountChange'; statusData: { amountFrom: string; amountTo: string; tokenFrom?: Token; tokenTo?: Token; } & LifecycleStatusDataShared; } | { statusName: 'slippageChange'; statusData: LifecycleStatusDataShared; } | { statusName: 'transactionPending'; statusData: LifecycleStatusDataShared; } | { statusName: 'transactionApproved'; statusData: { transactionHash: Hex; transactionType: 'ERC20' | 'Permit2'; } & LifecycleStatusDataShared; } | { statusName: 'success'; statusData: { transactionReceipt: TransactionReceipt; } & LifecycleStatusDataShared; }; ``` ## `SwapAmountInputReact` ```vocs_Code Copytype SwapAmountInputReact = { className?: string; // Optional className override for top div element. delayMs?: number; // The debounce delay in milliseconds label: string; // Descriptive label for the input field swappableTokens?: Token[]; // Swappable tokens token?: Token; // Selected token type: 'to' | 'from'; // Identifies if component is for toToken or fromToken }; ``` ## `SwapButtonReact` ```vocs_Code Copytype SwapButtonReact = { className?: string; // Optional className override for top div element. disabled?: boolean; // Disables swap button }; ``` ## `SwapError` ```vocs_Code Copytype SwapError = { code: string; // The error code representing the type of swap error. error: string; // The error message providing details about the swap error. message: string; // The error message providing details about the swap error. }; ``` ```vocs_Code Copytype SwapMessageReact = { className?: string; // Optional className override for top div element. }; ``` ## `SwapQuote` ```vocs_Code Copytype SwapQuote = { amountReference: string; // The reference amount for the quote from: Token; // The source token for the swap fromAmount: string; // The amount of the source token fromAmountUSD: string; // The USD value of the source token hasHighPriceImpact: boolean; // Whether the price impact is high priceImpact: string; // The price impact of the swap slippage: string; // The slippage of the swap to: Token; // The destination token for the swap toAmount: string; // The amount of the destination token toAmountUSD: string; // The USD value of the destination token warning?: QuoteWarning; // The warning associated with the quote }; ``` ## `SwapReact` ```vocs_Code Copytype SwapReact = { children: ReactNode; className?: string; // Optional className override for top div element. config?: { maxSlippage: number; // Maximum acceptable slippage for a swap (e.g., 3 for 3%). This is a percentage, not basis points; }; experimental?: { /** * Whether to use a DEX aggregator. * true - 0x Aggregator * false - Uniswap V3 * @default false */ useAggregator: boolean; }; isSponsored?: boolean; // An optional setting to sponsor swaps with a Paymaster. (default: false) onError?: (error: SwapError) => void; // An optional callback function that handles errors within the provider. onStatus?: (lifecycleStatus: LifecycleStatus) => void; // An optional callback function that exposes the component lifecycle state onSuccess?: (transactionReceipt: TransactionReceipt) => void; // An optional callback function that exposes the transaction receipt title?: string; // Title for the Swap component. (default: "Swap") }; ``` ## `SwapDefaultReact` ```vocs_Code Copyexport type SwapDefaultReact = { to: Token[]; // Swappable tokens (first token in array will be initial token selected) from: Token[]; // Swappable tokens (first token in array will be initial token selected) disabled?: boolean; // Disables swap button } & Omit; ``` ## `SwapSettingsReact` ```vocs_Code Copytype SwapSettingsReact = { children: ReactNode; className?: string; // Optional className override for top div element. icon?: ReactNode; // Optional icon override text?: string; // Optional text override }; ``` ## `SwapSettingsSlippageDescriptionReact` ```vocs_Code Copytype SwapSettingsSlippageDescriptionReact = { children: ReactNode; className?: string; // Optional className override for top div element. }; ``` ## `SwapSettingsSlippageInputReact` ```vocs_Code Copytype SwapSettingsSlippageInputReact = { className?: string; // Optional className override for top div element. }; ``` ## `SwapSettingsSlippageTitleReact` ```vocs_Code Copytype SwapSettingsSlippageTitleReact = { children: ReactNode; className?: string; // Optional className override for top div element. }; ``` ## `SwapToastReact` ```vocs_Code Copytype SwapToastReact = { className?: string; // An optional CSS class name for styling the toast component. durationMs?: number; // An optional value to customize time until toast disappears position?: 'top-center' | 'top-right' | 'bottom-center' | 'bottom-right'; // An optional position property to specify the toast's position on the screen. }; ``` ## `SwapToggleButtonReact` ```vocs_Code Copytype SwapToggleButtonReact = { className?: string; // Optional className override for top div element. }; ``` ## `Transaction` ```vocs_Code Copytype Transaction = { chainId: number; // The chain ID data: Hex; // The data for the transaction gas: bigint; // The gas limit maxFeePerGas?: bigint | undefined; // The maximum fee per gas maxPriorityFeePerGas?: bigint | undefined; // The maximum priority fee per gas nonce?: number; // The nonce for the transaction to: Address; // The recipient address value: bigint; // The value of the transaction }; ``` ## OnchainKit Theme Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/guides/themes#vocs-content) Menu Theme Customization On this page Chevron Right ![Themes](https://docs.base.org/images/onchainkit/onchainkit-themes.gif) ## Overview OnchainKit provides flexible appearance control through two main features: `mode` and `theme`. - **Mode**: Controls the light/dark appearance and includes an auto option that inherits the system preference. - **Theme**: Governs the overall styling across components. You can choose from built-in themes or dynamically switch modes based on user preference or system settings, allowing for a customized and responsive user interface. ## Built-in Themes OnchainKit offers multiple themes to quickly style your components. Set the theme via the `OnchainKitProvider` using `config.appearance.theme`: - `default`: Includes both light and dark modes. - `base`: Single mode only. - `cyberpunk`: Single mode only. - `hacker`: Single mode only. - `custom`: Single mode only. If no theme is selected, the **`default`** theme is applied automatically. ```vocs_Code Copy ``` ## Mode Control the color scheme by setting the `config.appearance.mode` property of the `OnchainKitProvider`: - `auto`: Automatically switches between light and dark mode based on the user’s OS preference. - `light`: Forces all components to use the light version of the theme. - `dark`: Forces all components to use the dark version of the theme. If no mode is specified, `auto` mode will be applied by default. ```vocs_Code Copy ``` ## CSS Overrides Fine-tune specific aspects of an existing theme. This is useful when you want to make adjustments to the appearance of the components without creating an entirely new theme. ```vocs_Code Copy@layer base { :root .default-light, .default-dark, .base, .cyberpunk, .hacker { /* Override specific variables as needed */ --ock-font-family: 'your-custom-value'; --ock-border-radius: 'your-custom-value'; --ock-text-primary: 'your-custom-value'; } } ``` ## Custom Theme Define an entirely new look and feel for your application. This gives you complete control over all aspects of the design, including colors, fonts, and other visual properties. #### Usage Options: ##### Automatic Light/Dark Mode Switching: - To automatically switch between light and dark versions of your custom theme: ```vocs_Code Copy ``` ##### Single Theme Version: - To use only one version of your custom theme at all times: ```vocs_Code Copy ``` ##### Defining a custom theme Use CSS variables to define your custom theme. The class name definitions must include the `-light` or `-dark` suffix. ```vocs_Code Copy@layer base { .custom-light { /* Font and Shape */ --ock-font-family: 'your-custom-value'; --ock-border-radius: 'your-custom-value'; --ock-border-radius-inner: 'your-custom-value'; /* Text Colors */ --ock-text-inverse: 'your-custom-value'; --ock-text-foreground: 'your-custom-value'; --ock-text-foreground-muted: 'your-custom-value'; --ock-text-error: 'your-custom-value'; --ock-text-primary: 'your-custom-value'; --ock-text-success: 'your-custom-value'; --ock-text-warning: 'your-custom-value'; --ock-text-disabled: 'your-custom-value'; /* Background Colors */ --ock-bg-default: 'your-custom-value'; --ock-bg-default-hover: 'your-custom-value'; --ock-bg-default-active: 'your-custom-value'; --ock-bg-alternate: 'your-custom-value'; --ock-bg-alternate-hover: 'your-custom-value'; --ock-bg-alternate-active: 'your-custom-value'; --ock-bg-inverse: 'your-custom-value'; --ock-bg-inverse-hover: 'your-custom-value'; --ock-bg-inverse-active: 'your-custom-value'; --ock-bg-primary: 'your-custom-value'; --ock-bg-primary-hover: 'your-custom-value'; --ock-bg-primary-active: 'your-custom-value'; --ock-bg-primary-washed: 'your-custom-value'; --ock-bg-primary-disabled: 'your-custom-value'; --ock-bg-secondary: 'your-custom-value'; --ock-bg-secondary-hover: 'your-custom-value'; --ock-bg-secondary-active: 'your-custom-value'; --ock-bg-error: 'your-custom-value'; --ock-bg-warning: 'your-custom-value'; --ock-bg-success: 'your-custom-value'; --ock-bg-default-reverse: 'your-custom-value'; /* Icon Colors */ --ock-icon-color-primary: 'your-custom-value'; --ock-icon-color-foreground: 'your-custom-value'; --ock-icon-color-foreground-muted: 'your-custom-value'; --ock-icon-color-inverse: 'your-custom-value'; --ock-icon-color-error: 'your-custom-value'; --ock-icon-color-success: 'your-custom-value'; --ock-icon-color-warning: 'your-custom-value'; /* Border Colors */ --ock-border-line-primary: 'your-custom-value'; --ock-border-line-default: 'your-custom-value'; --ock-border-line-heavy: 'your-custom-value'; --ock-border-line-inverse: 'your-custom-value'; } .custom-dark { /* Define dark mode custom classes here */ } } ``` ## Transaction Component Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/transaction/transaction#vocs-content) Menu Transaction On this page Chevron Right The `` components provide a high-level wrap around the entire transaction flow. It handles the transaction lifecycle, including gas estimation, fee sponsorship, and status updates. Before using them, ensure you've completed all [Getting Started steps](https://docs.base.org/builderkits/onchainkit/getting-started). ## Quick start The `Transaction` component now supports a simplified shorthand version to streamline the integration process for developers. Instead of manually defining each subcomponent and prop, you can render `Transaction` without children, and it will automatically include our suggested implementation — complete with the `TransactionButton` and `TransactionToast` components. If you'd like more customization, follow the implementation guide for our `Transaction` components below. ```vocs_Code Copyimport { Transaction } from "@coinbase/onchainkit/transaction" const calls = [...]; ``` Connect Wallet ### Props [`TransactionReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionreact) ## Walkthrough ### Add `calls` Execute one or multiple transactions using the Transaction component. You can pass transactions in either `Call` or `ContractFunctionParameters` format. The component will automatically apply batching logic if the user's wallet supports it. #### Types - [`ContractFunctionParameters`](https://github.com/wevm/viem/blob/ce1b8aff4d4523d3a324e500261c8c0867fd35e9/src/types/contract.ts#L188) - [`Call`](https://docs.base.org/builderkits/onchainkit/transaction/types#call) TransactionComponents.tsxcalls.ts File TransactionComponents.tsx ```vocs_Code Copyimport { useCallback } from 'react'; import { Avatar, Name } from '@coinbase/onchainkit/identity'; import { Transaction, TransactionButton, TransactionSponsor, TransactionStatus, TransactionStatusAction, TransactionStatusLabel, } from '@coinbase/onchainkit/transaction'; import type { LifecycleStatus } from '@coinbase/onchainkit/transaction'; import { Wallet, ConnectWallet } from '@coinbase/onchainkit/wallet'; import { useAccount } from 'wagmi'; import { calls } from '@/calls'; export default function TransactionComponents() { const { address } = useAccount(); const handleOnStatus = useCallback((status: LifecycleStatus) => { console.log('LifecycleStatus', status); }, []); return address ? ( ) : ( ); }; ``` Connect Wallet ### Listen to `LifecycleStatus` Take full control of your transactions data with the `LifecycleStatus` object via the `onStatus` prop. This TypeScript object provides `statusName` and `statusData` to keep you informed. ```vocs_Code Copy import type { LifecycleStatus } from '@coinbase/onchainkit/transaction'; // omitted for brevity const handleOnStatus = useCallback((status: LifecycleStatus) => { console.log('Transaction status:', status); }, []); // omitted for brevity // Usage in component ``` The Lifecycle Status features seven states for the transaction experience. ```vocs_Code Copytype LifecycleStatus = | { statusName: 'init'; statusData: null; } | { statusName: 'error'; statusData: TransactionError; } | { statusName: 'transactionIdle'; // initial status prior to the mutation function executing statusData: null; } | { statusName: 'buildingTransaction'; // resolving calls or contracts promise statusData: null; } | { statusName: 'transactionPending'; // if the mutation is currently executing statusData: null; } | { statusName: 'transactionLegacyExecuted'; statusData: { transactionHashList: string[]; }; } | { statusName: 'success'; // if the last mutation attempt was successful statusData: { transactionReceipts: TransactionReceipt[]; }; }; ``` ### Sponsor with Paymaster capabilities To sponsor your transactions with Paymaster capabilities, configure your [`OnchainKitProvider`](https://docs.base.org/builderkits/onchainkit/config/onchainkit-provider) with the appropriate `config.paymaster` URL, then pass `isSponsored={true}` to the `Transaction` component. Obtain a Paymaster and Bundler endpoint from the [Coinbase Developer Platform](https://portal.cdp.coinbase.com/products/bundler-and-paymaster). ![OnchainKit Paymaster and Bundler endpoint](https://docs.base.org/images/onchainkit/onchainkit-components-paymaster-endpoint.png) ```vocs_Code Copy ``` Next, pass `isSponsored={true}` to the `Transaction` component. ```vocs_Code Copy// omitted for brevity ``` ### Using `calls` with Promises `Calls` also accepts asynchronous functions that are resolved on each button click. This can be useful if you're calling an API to retrieve transaction data. These functions must resolve to `Call[]` or `ContractFunctionParameters[]`. In the example the calls data will be fetched from api.transaction.com when the user clicks the Transaction Button. ```vocs_Code Copy const callsCallback = async () => { const res = await fetch('api.transaction.com/createTransaction'); const callData = await res.json(); return callData; } export default function TransactionWithCalls() { return ( console.log('Transaction status:', status)} > ); } ``` ## Components ![OnchainKit transaction anatomy component diagram](https://docs.base.org/images/onchainkit/onchainkit-components-transaction-anatomy.png) The components are designed to work together hierarchically. For each component, ensure the following: - `` \- Serves as the main container for all transaction-related components. - `` \- Handles the transaction initiation process. - `` \- Displays information about the sponsorship of transaction gas fees. - `` \- Contains transaction status information and actions. - `` \- Displays the current status of the transaction. - `` \- Provides additional actions based on the transaction status. - `` \- Displays a toast notification for the transaction status. - `` \- Displays an icon in the transaction toast notification. - `` \- Displays the label text in the transaction toast notification. - `` \- Provides additional actions within the transaction toast notification. ## Component types - [`TransactionButtonReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionbuttonreact) - [`TransactionError`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionerror) - [`TransactionDefaultReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactiondefaultreact) - [`TransactionReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionreact) - [`TransactionSponsorReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionsponsorreact) - [`TransactionStatusReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionstatusreact) - [`TransactionStatusActionReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionstatusactionreact) - [`TransactionStatusLabelReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactionstatuslabelreact) - [`TransactionToastReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactiontoastreact) - [`TransactionToastActionReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactiontoastactionreact) - [`TransactionToastIconReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactiontoasticonreact) - [`TransactionToastLabelReact`](https://docs.base.org/builderkits/onchainkit/transaction/types#transactiontoastlabelreact) ## NFT Minting Types [Skip to content](https://docs.base.org/builderkits/onchainkit/mint/types#vocs-content) Menu Mint On this page Chevron Right ## `LifecycleStatus` ```vocs_Code Copyexport type LifecycleStatus = | { statusName: 'init'; statusData: null; } | { statusName: 'error'; statusData: NFTError; } | { statusName: 'mediaLoading'; statusData: { mediaType: MediaType; mediaUrl: string; }; } | { statusName: 'mediaLoaded'; statusData: null; } | { statusName: 'transactionPending'; statusData: null; } | { statusName: 'transactionLegacyExecuted'; statusData: { transactionHashList: Address[]; }; } | { // NFTCard success state represents media loaded // NFTMintCard success state represents successful Mint statusName: 'success'; statusData: { transactionReceipts?: TransactionReceipt[]; }; }; ``` ## `NFTCardReact` ```vocs_Code Copytype NFTCardReact = { children: React.ReactNode; // Optional className override for top div element. className?: string; // Contract address of the NFT contractAddress: Hex; // Required Token ID of the NFT tokenId: string; // Optional hook to override the default useNftData hook useNFTData?: UseNFTData; // An optional callback function that handles errors within the provider. onError?: (error: NFTError) => void; // An optional callback function that exposes the component lifecycle state onStatus?: (lifecycleStatus: LifecycleStatus) => void; // card will not pass transactionReceipt onSuccess?: (transactionReceipt?: TransactionReceipt) => void; }; ``` ## `NFTMintCardReact` ```vocs_Code Copytype NFTMintCardReact = { children: ReactNode; // Optional className override for top div element. className?: string; // Contract address of the NFT contractAddress: Hex; // Token ID of the NFT only required for ERC1155 tokenId?: string; // Optional boolean to determine if the mint is sponsored by paymaster isSponsored?: boolean; // Optional hook to override the default useNFTData hook useNFTData?: UseNFTData; // Optional function to override the default function that builds the mint transaction buildMintTransaction?: BuildMintTransaction; // An optional callback function that handles errors within the provider. onError?: (error: NFTError) => void; // An optional callback function that exposes the component lifecycle state onStatus?: (lifecycleStatus: LifecycleStatus) => void; // MintCard will pass transactionReceipt onSuccess?: (transactionReceipt?: TransactionReceipt) => void; }; ``` ## `NFTData` ```vocs_Code Copytype NFTData = { // card components name?: string; // required for NFTTitle and NFTCollectionTitle description?: string; // not currently used imageUrl?: string; // required for NFTMedia animationUrl?: string; // required for NFTMedia (audio and video types) /* supported mimeTypes: * image = image/* * video = video/* * audio = audio/* | application/* */ lastSoldPrice?: NFTPrice; // required for NFTLastSoldPrice mimeType?: string; // required for NFTMedia (falls back to image) // mint components ownerAddress?: `0x${string}`; // required for NFTOwner contractType?: ContractType; mintDate?: Date; // required for NFTMintDate price?: NFTPrice; // required for NFTAssetCost, NftTotalCost mintFee?: NFTPrice; // required for NFTTotalCost creatorAddress?: Hex; // required for NFTCreator maxMintsPerWallet?: number; // required for NFTMintButton isEligibleToMint?: boolean; // required for NFTMintButton totalOwners?: string; // required for NFTMinters recentOwners?: Address[]; // required for NFTMinters network?: string; // required for default BuildMintTransaction implementation }; ``` ## OnchainKit Installation Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/installation/nextjs#vocs-content) Menu Next.js On this page Chevron Right Install and configure OnchainKit with Next.js. If you are integrating OnchainKit into an existing project, skip to the [OnchainKit installation](https://docs.base.org/builderkits/onchainkit/installation/nextjs#install-onchainkit). ## Install Next.js Create a new Next.js project by using the Next.js CLI. More information about Next.js can be found [here](https://nextjs.org/docs/getting-started/installation). Terminal npm ```vocs_Code Copynpx create-next-app@14 ``` During the setup process you will encounter multiple prompts. Make sure you enable TypeScript, ESLint, and Tailwind CSS. ## Install OnchainKit Install OnchainKit in your project. npmyarnpnpmbun Terminal npm ```vocs_Code Copynpm install @coinbase/onchainkit ``` ## Get Your Client API Key Get your [Client API Key](https://portal.cdp.coinbase.com/projects/api-keys/client-key) from Coinbase Developer Platform. ![OnchainKit copy Client API Key](https://docs.base.org/images/onchainkit/copy-api-key-guide.png) Create a `.env` file in your project's root directory. ![OnchainKit define Client API Key](https://docs.base.org/images/onchainkit/getting-started-create-env-file.png) Add your Client API Key to the `.env` file: File .env ```vocs_Code CopyNEXT_PUBLIC_ONCHAINKIT_API_KEY=YOUR_CLIENT_API_KEY; ``` ## Add Providers Create a `providers.tsx` file. Add `OnchainKitProvider` with your desired config. Under the hood, OnchainKit will create our recommended Wagmi and QueryClient providers. If you wish to customize these providers, check out [Custom\\ Supplemental Providers](https://docs.base.org/builderkits/onchainkit/config/supplemental-providers). File providers.tsx ```vocs_Code Copy'use client'; import type { ReactNode } from 'react'; import { OnchainKitProvider } from '@coinbase/onchainkit'; import { base } from 'wagmi/chains'; // add baseSepolia for testing export function Providers(props: { children: ReactNode }) { return ( {props.children} ); } ``` ## Wrap your app with `` After the setup, wrap your app with the above `` component. File app.tsx ```vocs_Code Copyimport './globals.css'; import { Providers } from './providers'; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode, }>) { return ( {children} ); } ``` ## Add Styles OnchainKit components come with pre-configured styles. To include these styles in your project, add the following import statement at the top of this file: ```vocs_Code Copyimport '@coinbase/onchainkit/styles.css'; ``` For example, if you're using Next.js with the app router, your `app/layout.tsx` might look like this: File layout.tsx ```vocs_Code Copyimport '@coinbase/onchainkit/styles.css'; import './globals.css'; import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import { headers } from 'next/headers'; import { type ReactNode } from 'react'; import { cookieToInitialState } from 'wagmi'; import { getConfig } from '../wagmi'; import { Providers } from './providers'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { title: 'Create Wagmi', description: 'Generated by create-wagmi', }; export default function RootLayout(props: { children: ReactNode }) { const initialState = cookieToInitialState( getConfig(), headers().get('cookie') ); return ( {props.children} ); } ``` This ensures that the OnchainKit styles are loaded and applied to your entire application. - For Tailwind CSS users, check out our [Tailwind Integration Guide](https://docs.base.org/builderkits/onchainkit/guides/tailwind). - Update the appearance of components by using our built-in themes or crafting your own custom theme. Explore the possibilities in our [Theming Guide](https://docs.base.org/builderkits/onchainkit/guides/themes). # Start building! Explore our ready-to-use onchain components: - [**`Identity`**](https://docs.base.org/builderkits/onchainkit/identity/identity)\- Show [Basenames](https://docs.base.org/builderkits/onchainkit/identity/identity), [avatars](https://docs.base.org/builderkits/onchainkit/identity/avatar), [badges](https://docs.base.org/builderkits/onchainkit/identity/badge), and [addresses](https://docs.base.org/builderkits/onchainkit/identity/address). - [**`Wallet`**](https://docs.base.org/builderkits/onchainkit/wallet/wallet)\- Create or connect wallets with [Connect Wallet](https://docs.base.org/builderkits/onchainkit/wallet/wallet). - [**`Transaction`**](https://docs.base.org/builderkits/onchainkit/transaction/transaction)\- Handle [transactions](https://docs.base.org/builderkits/onchainkit/transaction/transaction) using EOAs or Smart Wallets. - [**`Checkout`**](https://docs.base.org/builderkits/onchainkit/checkout/checkout)\- Integrate USDC [checkout](https://docs.base.org/builderkits/onchainkit/checkout/checkout) flows with ease. - [**`Fund`**](https://docs.base.org/builderkits/onchainkit/fund/fund-button)\- Create a [funding](https://docs.base.org/builderkits/onchainkit/fund/fund-button) flow to onboard users. - [**`Tokens`**](https://docs.base.org/builderkits/onchainkit/token/token-chip)\- Search and display [tokens](https://docs.base.org/builderkits/onchainkit/token/token-chip) with various components. - [**`Swap`**](https://docs.base.org/builderkits/onchainkit/swap/swap)\- Enable [token swaps](https://docs.base.org/builderkits/onchainkit/swap/swap) in your app. - [**`Mint`**](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card)- [View](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) and [Mint](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) NFTs in your app. ## Wallet Island Overview [Skip to content](https://docs.base.org/builderkits/onchainkit/wallet/wallet-island#vocs-content) Menu WalletIsland On this page Chevron Right ![WalletIsland](https://docs.base.org/images/onchainkit/wallet-island.gif) `WalletIsland` is our flagship implementation of the new `` component, providing an advanced Wallet interface for users, including: - a QR code for receiving funds - a link to buy crypto with fiat - a swap interface - the user's token portfolio - a button that moves anywhere on the screen Designed for desktop experiences, `WalletIsland` component gives users a seamless way to interact with their wallet and manage their assets. Before using these components, ensure you've completed all [Getting Started steps](https://docs.base.org/builderkits/onchainkit/getting-started). ## Quick start `WalletAdvanced` has two default implementations: - `WalletAdvancedDefault` - `WalletIsland` `WalletAdvancedDefault` provides the user with an advanced wallet interface, anchored to the screen like our standard `Wallet` component. `WalletIsland` provides the same powerful interface, while enabling the user to drag the component around the window. If you'd like more customization, follow the implementation guide below. ```vocs_Code Copyimport { WalletAdvancedDefault } from '@coinbase/onchainkit/wallet'; import { WalletIsland } from '@coinbase/onchainkit/wallet'; <> ``` You will see two Wallet buttons below. Right below is `WalletAdvancedDefault`. This version will stay anchored to its current position. `WalletIsland` is in the bottom-right corner of the window. Feel free to drag it around. Connect Wallet Portfolio While this behavior is more noticeable with the `WalletIsland` component, you'll notice that for both components, the `WalletAdvanced` container will appear in different positions depending on the component's location in the window: - If there is sufficient space to the right, it will be left-aligned. - If there is not enough space to the right, it will be right-aligned. - If there is enough space below, it will open below. - If there is not enough space below, it will open above. ## Configuring `WalletIsland` and `WalletAdvanced` Experience the magic by simply dropping in `` and `` components, and watch your component seamlessly come to life. As with [`WalletDefault`](https://docs.base.org/builderkits/onchainkit/wallet/wallet) , `WalletAdvancedDefault` leverages several [``](https://docs.base.org/builderkits/onchainkit/identity/identity) components like [``](https://docs.base.org/builderkits/onchainkit/identity/avatar), [``](https://docs.base.org/builderkits/onchainkit/identity/name), and [`
`](https://docs.base.org/builderkits/onchainkit/identity/address). And `WalletAdvanced` introduces several advanced wallet components, including ``, ``, and ``. ```vocs_Code Copyimport { ConnectWallet, Wallet, WalletAdvanced, WalletAdvancedAddressDetails, WalletAdvancedTokenHoldings, WalletAdvancedTransactionActions, WalletAdvancedWalletActions, } from '@coinbase/onchainkit/wallet'; import { Address, Avatar, Name, Identity } from '@coinbase/onchainkit/identity'; import { color } from '@coinbase/onchainkit/theme'; export function YourWalletAdvanced() { return (
); } ``` Connect Wallet When customizing your `WalletAdvanced` implementation, use the `draggable` prop on `Wallet` to enable draggability. `draggable` defaults to `false`, but when `draggable` is set to `true`, you can also set a `draggableStartingPosition` prop to specify the initial position of your `WalletIsland`. ```vocs_Code Copyimport { ConnectWallet, Wallet, WalletAdvanced, WalletAdvancedAddressDetails, WalletAdvancedTokenHoldings, WalletAdvancedTransactionActions, WalletAdvancedWalletActions, } from '@coinbase/onchainkit/wallet'; import { Address, Avatar, Name, Identity } from '@coinbase/onchainkit/identity'; import { color } from '@coinbase/onchainkit/theme'; export function DraggableWalletAdvanced() { return (
); } ``` ## Customize Connect button text and style Each OnchainKit component offers the flexibility to customize `className` and adjust the style of the React components it represents. Explore the options for customizing the Connect button text and style [here](https://docs.base.org/builderkits/onchainkit/wallet/wallet#customize-connect-button-text-and-style). ## Using Wallet Modal ![Wallet Modal](https://docs.base.org/images/onchainkit/wallet-modal.png) Wallet modal offers users multiple wallet connection options. Explore these options [here](https://docs.base.org/builderkits/onchainkit/wallet/wallet-modal). ## Example usage ### Usage with Sign In With Ethereum (SIWE) To use [Sign In With Ethereum (SIWE)](https://docs.login.xyz/general-information/siwe-overview) with OnchainKit, check out our [SIWE example](https://docs.base.org/builderkits/onchainkit/wallet/wallet#usage-with-sign-in-with-ethereum-siwe). ## Components The components are designed to work together hierarchically. For each component, ensure the following: - `` \- Serves as the main container for all wallet-related components. - `` \- Contains additional wallet information and options. Place inside the `` component. - `` \- Provides wallet actions like View Transaction History, view QR Code, and Disconnect wallet. Place inside the `` component. - `` \- Displays user address, avatar, and portfolio balance in fiat. Place inside the `` component. - `` \- Buttons for buying crypto with fiat, transferring crypto, and swapping. Place inside the `` component. - `` \- Displays token balances and their value in fiat. Place inside the `` component. - `` \- Handles the wallet connection process. Place child components inside to customize the connect button appearance. - `` \- Enables a wallet aggregation experience. - `` \- Contains additional wallet information and options. Place inside the `` component. - `` \- Displays user identity information. Place inside `` for a complete profile view. - `` \- Displays the user's Basename within the dropdown. - `` \- Creates a custom link within the dropdown. Use the `icon` prop to add an icon, and `href` to specify the destination. - `` \- Provides a disconnect option within the dropdown. Additional components for customizing the wallet interface include: - `` \- Displays the user's avatar image. - `` \- Shows the user's name or ENS. - `` \- Can be used to display additional user status or information. - `
` \- Shows the user's wallet address. - `` \- Displays the user's ETH balance. The Wallet component automatically handles the wallet connection state and updates the UI accordingly. You need to wrap your application or relevant part of it with these components to provide a complete wallet interaction experience. ## Component types - [`WalletAdvancedReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletadvancedreact) - [`WalletAdvancedContextType`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletadvancedcontexttype) - [`WalletReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletreact) - [`ConnectWalletReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#connectwalletreact) - [`WalletDropdownReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownreact) - [`WalletDropdownBasenameReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownbasenamereact) - [`WalletDropdownDisconnectReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdowndisconnectreact) - [`WalletDropdownLinkReact`](https://docs.base.org/builderkits/onchainkit/wallet/types#walletdropdownlinkreact) We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Simulate Contract Interactions [Skip to content](https://docs.base.org/learn/writing-to-contracts/useSimulateContract#vocs-content) Menu useSimulateContract On this page Chevron Right The [`useSimulateContract`](https://wagmi.sh/react/hooks/useSimulateContract) hook simulates and validates a contract interaction without actually sending a transaction to the blockchain. Using it allows you to detect and respond to potential errors before the user tries to send a transaction. * * * ## Objectives By the end of this guide you should be able to: - 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 * * * ## Refining the Claim Component In the previous step-by-step, you used [`useWriteContract`](https://wagmi.sh/react/hooks/useWriteContract) to set up a hook you can use to call the `claim` function in your smart contract when the user clicks a button. The component works well enough, but it can take a long time for the wallet to pop up, particularly if there is network congestion. You also have no way of responding to a problem with the transaction inputs until after the user tries to initiate a transaction. ### Using `useSimulateContract` The `useSimulateContract` can be used in partnership with `useWriteContract`. To do so, you set up the transaction parameters in `useSimulateContract`, then use the `data?.request` returned by it as an argument in the call to write to the contract. Modify your `TokenInfo` component to test it: ```vocs_Code Copy// Bad code for example. See below for fix. const { data: claimData, isFetching: claimIsFetching, isError: claimIsError, } = useSimulateContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'claim', }); useEffect(() => { if (claimIsError) { alert('Unable to claim'); // TODO: Better error handling } }, [claimIsError]); // No changes to `useWriteContract` const { writeContract: claim, isPending: claimIsPending } = useWriteContract(); // Other code... // Update the call to `claim` const handleClaimClick = () => { claim(claimData?.request); }; ``` You'll also need to update your handler to use the TypeScript pre-check feature, because the claim function will be briefly `undefined`. ```vocs_Code Copyconst handleClaimClick = () => { claim(claimData!.request); }; ``` Reload the site and observe that the `alert` is triggered on load if you're signed in with an address that has already claimed tokens. You'll also see that the button is disabled, as though the user had clicked it and a transaction is loading in the wallet. ### Making Adjustments The reason for this is a subtle difference in how `useWriteContract` and `useSimulateContract` work. In the last step-by-step, you saw how viem runs a simulation of the transaction when the `write` function is called. `useSimulateContract` eagerly runs this simulation and updates it's variables. You'll need to make some modifications for it to work. The `claimIsError` variable is being triggered when the data for the call is **simulated**, not when the call has settled. As a result, it immediately generates the error, and triggers the `alert` without requiring the user to click the button. You can solve this a number of ways, including simply not rendering the button if the user has already claimed. You could also modify the code, and combine it with `isError`, to share this information to the user. ```vocs_Code Copyconst { data: claimData, isFetching: claimIsFetching, isError: claimIsError, } = useSimulateContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'claim', }); // Deleted `useEffect` for `claimIsError` const { writeContract: claim, isPending: claimIsPending } = useWriteContract(); // Other code return (

{claimIsFetching.toString()}

{'Token Balance: ' + tokenBalance}

{claimIsError ? 'Unable to claim tokens.' : 'Claim your tokens!'}

); ``` * * * ## Conclusion In this step-by-step, you updated your app to use the `useSimulateContract` hook to provide a speedier wallet interaction for your users. You've also learned how you can predict and respond to potential errors without the user needing to attempt to send a transaction. You could use this functionality to let them know a username is already taken, a bid amount is not large enough, or an item is no longer available. * * * ## Basenames Integration Tutorial [Skip to content](https://docs.base.org/identity/basenames/basenames-wagmi-tutorial#vocs-content) Menu Basenames Wagmi Tutorial On this page Chevron Right [Basenames](https://www.base.org/names/) is now live! But what exactly is it? Basenames allows users to register human-readable names for their addresses and serves as a foundational building block for onchain identity. Think of it as your favorite social media handle, but even bigger. Your Basename is multichain by default and yours forever—no platform can take it away from you (just make sure to pay your fee). Integrating Basenames into your onchain app enhances the user experience by masking complex wallet addresses. Just as domains simplify IP addresses, Basenames do the same for wallet addresses. This tutorial shows you how to display Basenames on behalf of your users. We'll walk through setting up the necessary files and configurations to interact with the Basenames ENS resolver directly. Let's begin! ## Objectives By the end of this tutorial, you should be able to: - Understand how onchain identity works on the Base network - Enable users to use their onchain identity in your app - Pull metadata from your users' Basename profile ## Steps First, create a directory to store the ABI (Application Binary Interface) for the Basenames ENS resolver. The ABI will allow your project to interact with the smart contract that handles Basenames. In your project folder, run the following commands: ```vocs_Code Copymkdir abis cd abis touch L2ResolverAbi.ts ``` This will create a new directory named `abis` and a file named L2ResolverAbi.ts within it. Next, add the following placeholder code to the `L2ResolverAbi.ts` file: ```vocs_Code Copyexport default [\ // ABI information goes here\ ] as const; ``` To interact with the Base blockchain, you will need to update the wagmi configuration. This will allow your project to connect to the Base network and use its features. Update your wagmi.ts file as follows: ```vocs_Code Copy'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactNode } from 'react'; import { http, createConfig, WagmiProvider } from 'wagmi'; import { base } from 'wagmi/chains'; export const config = createConfig({ chains: [base], transports: { [base.id]: http(), }, ssr: true, }); const queryClient = new QueryClient(); export default function EthereumProviders({ children }: { children: ReactNode }) { return ( {children} ); } ``` This code sets up your application to use the Base network, enabling the project to interact with the blockchain. Next, we'll create a new directory to house the functions that will resolve and interact with Basenames. These functions will be responsible for fetching Basename information from the blockchain. In your project folder, create the apis directory and add a basenames.tsx file: ```vocs_Code Copyimport { Address, ContractFunctionParameters, createPublicClient, encodePacked, http, keccak256, namehash, } from 'viem'; import { base, mainnet } from 'viem/chains'; import L2ResolverAbi from '@/abis/L2ResolverAbi'; // Function to resolve a Basename export async function getBasename(address: Address) { try { const addressReverseNode = convertReverseNodeToBytes(address, base.id); const basename = await baseClient.readContract({ abi: L2ResolverAbi, address: BASENAME_L2_RESOLVER_ADDRESS, functionName: 'name', args: [addressReverseNode], }); if (basename) { return basename as BaseName; } } catch (error) { // Handle the error accordingly console.error('Error resolving Basename:', error); } } ``` This code provides the foundation for resolving Basenames using the Base network. Now that the necessary functions are in place, you can implement the Basenames functionality in your app. For this example, we'll modify the `page.tsx` file to display Basename information on the server and client side. Here's how to set it up: ```vocs_Code Copyimport { BasenameTextRecordKeys, getBasename, getBasenameAvatar, getBasenameTextRecord, } from '@/apis/basenames'; import BasenameDetails from '@/components/BasenameDetails'; import EthereumProviders from '@/contexts/EthereumProviders'; import { useAccount } from 'wagmi'; // shrek.base.eth const address = '0x8c8F1a1e1bFdb15E7ed562efc84e5A588E68aD73'; // const account = useAccount(); \n address = account?.address; async function fetchData() { const basename = await getBasename(address); if (basename === undefined) throw Error('failed to resolve address to name'); const avatar = await getBasenameAvatar(basename); const description = await getBasenameTextRecord(basename, BasenameTextRecordKeys.Description); const twitter = await getBasenameTextRecord(basename, BasenameTextRecordKeys.Twitter); return { basename, avatar, description, twitter, }; } export default async function Home() { const data = await fetchData(); return (

Server-side rendered:

  • Address {address}
  • Basename {data.basename}
  • Avatar {data.basename}
  • Description {data.description}
  • Twitter {data.twitter}

Client-side rendered:

); } ``` In this example, the Home component fetches Basename data and displays it in both server-side and client-side rendered sections. This allows your app to provide a seamless user experience, showing Basename details like the avatar, description, and associated Twitter handle. ## Conclusion Congratulations! You've successfully integrated Basenames into your project. By setting up the necessary ABI, configuring your wagmi project, and implementing custom functions to resolve and display Basenames, you've enhanced your app's user experience by making wallet addresses more user-friendly. Your users can now enjoy a personalized, recognizable onchain identity across the Base network. Keep exploring and building to unlock even more possibilities with Basenames! ## Wallet Connectors Guide [Skip to content](https://docs.base.org/learn/frontend-setup/wallet-connectors#vocs-content) Menu Wallet Connectors On this page Chevron Right One of the most intimidating tasks when building an onchain app is making that initial connection between your users' wallets, and your app. Initial research often surfaces a bewildering number of wallets, each with their own SDKs, and own methods to manage the connection. Luckily, you don't actually need to manage all of this on your own. There are a number of wallet connector libraries specialized in creating a smooth and beautiful user experience to facilitate this connection. To further add to the confusion and difficulty, [Smart wallets](https://www.coinbase.com/wallet/smart-wallet) are growing in popularity. These advanced wallets allow users to create and manage wallets with [passkeys](https://safety.google/authentication/passkey/), and support, or will soon support, a growing array of features including session keys, account recovery, and more! [RainbowKit](https://www.rainbowkit.com/), the aggregator you'll use for this lesson, works with the Coinbase Smart Wallet out of the box, but you'll need to do a little bit of extra configuration to support users of both traditional wallets and smart wallets. * * * ## Objectives By the end of this guide you should be able to: - Identify the role of a wallet aggregator in an onchain app - Debate the pros and cons of using a template - Scaffold a new onchain app with RainbowKit - Support users of EOAs and the Coinbase Smart Wallet with the same app * * * ## Connecting to the Blockchain One of the many challenging tasks of building a frontend that can interface with your smart contracts is managing the user's connection between your onchain app and their \[EOA\] wallet. Not only is there an ever-growing suite of different wallets, but users can (and probably should!) use several different addresses within the same wallet app. [Rainbowkit](https://www.rainbowkit.com/) is one of several options that makes this a little bit easier by serving as an aggregator of wallets, and handling some of the details of connecting them. Alternatives include [ConnectKit](https://ethereum.org/en/developers/docs/accounts/), and [Dynamic](https://www.dynamic.xyz/), which are both excellent choices as well. Each of these include customizable UI/UX components for inviting the user to connect, displaying connection status, and selecting which wallet they wish to use. ### Using the Quick Start If you're just trying to get up and running as quickly as possible, you can use RainbowKit's [quick start](https://www.rainbowkit.com/docs/installation) script to scaffold an app from their template, with a single command. If you're using Yarn: ```vocs_Code Copyyarn create @rainbow-me/rainbowkit ``` Once it's done, simply run the app with: ```vocs_Code Copyyarn run dev ``` Using the script is fast, but it does mean less choice. In this case, it builds the app on top of [Next.js](https://nextjs.org/), which is great if you want to use it, but not helpful if you prefer to work from a different framework, such as [Create React App](https://create-react-app.dev/), or [Remix](https://remix.run/) (the React framework, not the Solidity IDE). The script also doesn't help you if you want to add an onchain integration to an existing site. ### Coinbase Smart Wallet If you have the Coinbase Wallet extension, you might be wondering where the smart wallet can be found. By default, the smart wallet will only be invoked if you click the `Coinbase Wallet` button to log in **and** you **don't** have the browser extension. To test, open a private window with extensions disabled and try to log in. Selecting `Rainbow`, `MetaMask`, or `WalletConnect` will display a QR code so that the user can log in with their phone. Picking `Coinbase Wallet` will instead invoke the smart wallet login. This flow can be improved upon, as new crypto users won't know that digging for the smart wallet is the best path forward, and existing users who are trying to migrate to the smart wallet don't have that option. See our tutorial on how to [Use the Coinbase Smart Wallet and EOAs with OnchainKit](https://docs.base.org/tutorials/smart-wallet-and-eoa-with-onchainkit) for more details! * * * ## Conclusion In this article, you've learned how libraries such as [Rainbowkit](https://www.rainbowkit.com/), [ConnectKit](https://ethereum.org/en/developers/docs/accounts/), and [Dynamic](https://www.dynamic.xyz/), aggregate wallets and make it easier for you to connect your app to your users' wallet of choice. You've also learned how you can use a template to quickly create the foundation of your app. Finally, you've learned that the cost of using a template is that it does make some choices for you. * * * ## Accept Crypto Payments [Skip to content](https://docs.base.org/use-cases/accept-crypto-payments#vocs-content) Menu Accept crypto payments On this page Chevron Right Accepting crypto payments can help you **eliminate traditional credit card fees** and **avoid costly chargebacks**, giving you a faster, more global payment experience. In this guide, you'll learn how to quickly integrate Coinbase Commerce and OnchainKit to accept crypto payments for products or services in your application. ## Objectives By following this guide, you will learn how to: - Create or configure a product in **Coinbase Commerce** - Configure your **OnchainKit** environment - Implement a checkout flow for accepting crypto payments - Deploy and test your app to confirm the payment flow ## Prerequisites ### 1\. Coinbase Commerce Account [Coinbase Commerce](https://beta.commerce.coinbase.com/sign-up) allows you to accept cryptocurrency payments globally. Sign up to get started. ### 2\. Coinbase Developer Platform (CDP) Account [Coinbase Developer Platform](https://www.coinbase.com/cloud) (CDP) provides the tools and APIs you need for integration. ### 3\. Reown (WalletConnect) Account [Reown](https://cloud.reown.com/) (formerly WalletConnect) provides a secure way to connect wallets across different devices and platforms. ## Step-by-Step Setup ### Step 1: Create a Product in Coinbase Commerce 1. **Log in** to your Coinbase Commerce account. 2. Go to the [product creation page](https://beta.commerce.coinbase.com/products). 3. **Add product details** (name, description, price). 4. Click **Create product**. 5. Once created, select **View product** and copy the **UUID** from the URL. ![Create product screenshot](https://docs.base.org/images/onchainkit-tutorials/pay-create-product-details.png) **Tip**: Store the product UUID as an environment variable in your `.env` file. This makes it easier to reference safely in your code. ### Step 2: Clone the OnchainKit App Template Use the official **OnchainKit app template** to bootstrap your project: BunnpmYarn Terminal Bun ```vocs_Code Copygit clone https://github.com/coinbase/onchainkit-app-template.git cd onchainkit-app-template bun i ``` ### Step 3: Configure Environment Variables In the project folder, open (or create) your `.env` file and add: ```vocs_Code CopyNEXT_PUBLIC_WC_PROJECT_ID= NEXT_TELEMETRY_DISABLED=1 NEXT_PUBLIC_ONCHAINKIT_API_KEY= NEXT_PUBLIC_PRODUCT_ID= ``` > **Note**: > > - `NEXT_PUBLIC_PRODUCT_ID` should be set to the **UUID** from your Coinbase Commerce product. > - `NEXT_PUBLIC_ONCHAINKIT_API_KEY` should be your **CDP** API key. > - `NEXT_PUBLIC_WC_PROJECT_ID` is your Reown (WalletConnect) project ID. ### Step 4: Configure Wagmi for Smart Wallets Open your Wagmi configuration file (e.g., `src/app/wagmi.ts` or similar) and **after** your `useMemo()` hook, add: ```vocs_Code Copy // other Wagmi config + coinbaseWallet.preference = 'smartWalletOnly'; ``` This ensures Coinbase Wallet only connects to **smart wallets**. In `src/app/components/OnchainProviders.tsx`, set up **OnchainKitProvider** to use your **CDP** API key and **Base** as the chain: ```vocs_Code Copy'use client'; import { OnchainKitProvider } from '@coinbase/onchainkit'; import { RainbowKitProvider } from '@rainbow-me/rainbowkit'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import { base } from 'viem/chains'; import { WagmiProvider } from 'wagmi'; import { useWagmiConfig } from '../wagmi'; type Props = { children: ReactNode }; const queryClient = new QueryClient(); function OnchainProviders({ children }: Props) { const wagmiConfig = useWagmiConfig(); return ( {children} ); } export default OnchainProviders; ``` Finally, update your `Config.ts` (or similar config file) to read from environment variables and match your hosted URL: ```vocs_Code Copyexport const NEXT_PUBLIC_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : 'https://based-jerseys.vercel.app'; export const NEXT_PUBLIC_CDP_API_KEY = process.env.NEXT_PUBLIC_ONCHAINKIT_API_KEY; export const NEXT_PUBLIC_WC_PROJECT_ID = process.env.NEXT_PUBLIC_WC_PROJECT_ID; ``` ### Step 5: Implement the Payment Component 1. **Open** `src/app/page.tsx` (or similar entry page). 2. **Import** the necessary components: ```vocs_Code Copyimport { Checkout, CheckoutButton, CheckoutStatus } from '@coinbase/onchainkit/checkout'; import Image from 'next/image'; const productId = process.env.NEXT_PUBLIC_PRODUCT_ID; ``` 3. **Add an image** of your product or service in the `public` folder (e.g., `/public/based-jersey-front.jpeg`). 4. **Display** that image and conditionally render the checkout UI only when a wallet is connected: ```vocs_Code Copy
jersey
{address ? ( ) : ( )}
``` ### Step 6: Test & Deploy 1. **Run** the development server: BunnpmYarn Terminal Bun ```vocs_Code Copybun run dev ``` 2. **Visit** `http://localhost:3000` to confirm that the payment button works for your product or service. 3. **Deploy** with your preferred hosting provider (e.g., Vercel). ![Final product screenshot](https://docs.base.org/images/onchainkit-tutorials/pay-final-product.png) ## Conclusion Congratulations! You've successfully **integrated Coinbase Commerce** and **OnchainKit** into your application, enabling crypto payments. By providing this option, you can: - Eliminate traditional payment fees and chargebacks - Expand your audience to crypto users worldwide - Easily scale your offerings for more products and services **Happy building** and enjoy the benefits of a global, decentralized payment system on Base! ## Basenames OnchainKit Tutorial [Skip to content](https://docs.base.org/identity/basenames/basenames-onchainkit-tutorial#vocs-content) Menu Basenames OnchainKit Tutorial On this page Chevron Right Basenames is now live! But what exactly is it? Basenames allows users to register human-readable names for their addresses and serves as a foundational building block for onchain identity. Think of it as your favorite social media handle, but even bigger. Your Basename is multichain by default and yours forever—no platform can take it away from you (just make sure to pay your fee). Integrating Basenames into your onchain app enhances the user experience by masking complex wallet addresses. Just as domains simplify IP addresses, Basenames do the same for wallet addresses. OnchainKit is a React component library designed to make building Onchain applications easier. In this tutorial, we'll use the `` component to resolve Basenames. This demo uses Coinbase Smart Wallet and Coinbase Wallet, but Basenames is supported across many \[other wallets\]. ## Objectives By the end of this tutorial, you should be able to: - Understand how onchain identity works on the Base network - Enable users to use their onchain identity in your app using \[OnchainKit\] * * * If you're starting from scratch, you'll need to create a new wagmi project. If you already have an existing wagmi project, you can skip ahead to the section on installing OnchainKit. To create a new wagmi project using TypeScript and install the required dependencies, run the following command: ```vocs_Code Copybun create wagmi ``` Next, you'll need to install OnchainKit. Run the following command: ```vocs_Code Copybun add @coinbase/onchainkit ``` After adding OnchainKit, install all dependencies and start your development server with: ```vocs_Code Copybun install && bun run dev ``` This command will install the necessary dependencies and start a development server. To follow along with the tutorial effectively, open your web browser and your IDE side by side. This setup will allow you to code and see the changes in real time. ### Update Wagmi config In this section, we will configure your wagmi project to support the Base blockchain by importing the necessary modules. Start by importing the `base` and `baseSepolia` chains into your wagmi config. Navigate to `src/wagmi.ts` and update the file as follows: ```vocs_Code Copyimport { http, cookieStorage, createConfig, createStorage } from 'wagmi'; import { base, baseSepolia } from 'wagmi/chains'; import { coinbaseWallet, injected } from 'wagmi/connectors'; export function getConfig() { return createConfig({ chains: [base, baseSepolia], connectors: [\ injected(),\ coinbaseWallet({\ appName: 'Create Wagmi',\ preference: 'smartWalletOnly',\ }),\ ], storage: createStorage({ storage: cookieStorage, }), ssr: true, transports: { [base.id]: http(), [baseSepolia.id]: http(), }, }); } declare module 'wagmi' { interface Register { config: ReturnType; } } ``` This configuration sets up the wagmi project to connect to the Base and BaseSepolia networks, utilizing Coinbase Wallet and other connectors. Now we’ll create a component to display the Basenames associated with an address. ```vocs_Code Copy'use client'; import React from 'react'; ('use client'); import React from 'react'; import { Avatar, Identity, Name, Address } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; interface DisplayBasenameProps { address: `0x${string}` ``` We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## IdentityCard Component Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/identity/identity-card#vocs-content) Menu IdentityCard On this page Chevron Right The `IdentityCard` component provides a comprehensive way to display user identity information, including ENS names, avatars, and chain-specific name resolution. ## Features - **Name Resolution:** Resolves both Basenames and ENS names automatically - **Avatar Support:** Displays ENS and chain-specific avatars - **Flexible Display:** Customizable layout and styling options - **Chain-Aware:** Works across different EVM chains that support name resolution - **Tooltip Support:** Displays attestation information on badge hover ## Usage ### Basic Usage ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; ``` paul.base.eth 0x4bEf...2FDFCopy ### Badge Tooltip You can enable a tooltip for the attestation badge to provide context about what the badge represents: ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; ``` paul.base.eth 0x4bEf...2FDFCopy You can also provide custom tooltip text: ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; ``` paul.base.eth 0x4bEf...2FDFCopy ## Customization You can override styles using `className` or by setting a custom [OnchainKit theme](https://docs.base.org/builderkits/onchainkit/guides/themes#custom-theme). You can also set the `mainnet` chain for ENS name resolution: ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { mainnet } from 'viem/chains'; ``` paulcramer.eth 0x4bEf...2FDFCopy ## Props [`IdentityCardReact`](https://docs.base.org/builderkits/onchainkit/identity/types#identitycardreact) | Prop | Type | Description | | --- | --- | --- | | `address` | `string` | The wallet address to display identity for | | `chain` | `Chain` | The chain to resolve the identity on | | `className` | `string` | Additional CSS classes to apply | | `schemaId` | `Address | null` | The schema ID for attestation | | `badgeTooltip` | `boolean | string` | When `true`, displays the attestation name in tooltip. When a string is provided, shows that custom text instead. Defaults to `false` | ## Error Handling The component handles various error states gracefully: - Invalid addresses display a shortened address format - Missing ENS names fallback to shortened addresses - Failed avatar fetches show a default avatar - Network errors maintain a degraded but functional display ## Best Practices 1. Always provide a valid chain object from viem/chains 2. Handle loading states in parent components when address might be undefined 3. Implement proper error boundaries in parent components 4. Consider mobile responsiveness when styling 5. Use `badgeTooltip` to provide context about what the verification badge represents ## Related Components - [``](https://docs.base.org/builderkits/onchainkit/identity/avatar) \- Displays user avatars - [``](https://docs.base.org/builderkits/onchainkit/identity/name) \- Displays resolved names - [``](https://docs.base.org/builderkits/onchainkit/identity/identity) \- Simplified identity display We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Function Modifiers Guide [Skip to content](https://docs.base.org/learn/advanced-functions/function-modifiers#vocs-content) Menu Modifiers Guide On this page Chevron Right Function modifiers allow you to efficiently change the behavior of functions. In some ways, it's similar to inheritance, but there are restrictions, particularly in variable scope. * * * ## Objectives By the end of this lesson you should be able to: - Use modifiers to efficiently add functionality to multiple functions * * * ## Adding a Simple OnlyOwner Modifier 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 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. For a production app, you'll want to use a more robust implementation of `onlyOwner`, such as the [one provided by OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol). ### Adding an Owner The address of the deployer of a contract is **not** included as an accessible property. To make it available, add it as a state variable and assign `msg.sender` in the `constructor`. Reveal code ```vocs_Code Copycontract Modifiers { address owner; constructor () { owner = msg.sender; } } ``` ### Creating an `onlyOwner` Modifier \[Modifiers\] are very similar to functions and are declared with the `modifier` keyword. The modifier can run any Solidity code, including functions, and is allowed to modify state. Modifiers must have a special `_` character, which serves as a placeholder for where the code contained within the modified function will run. Create a simple `onlyOwner` modifier, which returns an `error` of `NotOwner` with the sending address if the sender is not the owner. Reveal code ```vocs_Code Copyerror NotOwner(address _msgSender); ``` ```vocs_Code Copymodifier onlyOwner { if (msg.sender != owner) { revert NotOwner(msg.sender); } _; } ``` Test your `modifier` by adding a function that uses it: Reveal code ```vocs_Code Copyfunction iOwnThis() public view onlyOwner returns (string memory) { return "You own this!"; } ``` To test, deploy your contract and call the `iOwnThis` function. You should see the message "You own this!". Next, switch the _Account_, and try the function again. You should see an error in the console: ```vocs_Code Copycall to Modifiers.iOwnThis errored: VM error: revert. revert The transaction has been reverted to the initial state. Error provided by the contract: NotOwner Parameters: { "_msgSender": { "value": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db" } } Debug the transaction to get more information. ``` Always verify the output of a function call in the console. The result that appears under the button for the function is convenient, but it does **not** clear or change if a subsequent call reverts. * * * ## Modifiers and Variables Modifiers can have parameters, which essentially work the same as in functions. These parameters can be independent values, or they can overlap with the arguments provided to a function call. ### Modifiers with Parameters Modifier parameters can be the arguments provided to the functions they modify. You can perform calculations and trigger errors based on these values. ```vocs_Code Copyerror NotEven(uint number); modifier onlyEven(uint _number) { if(_number % 2 != 0) { revert NotEven(_number); } _; } function halver(uint _number) public pure onlyEven(_number) returns (uint) { return _number / 2; } ``` ### Independent Scope While `modifiers` are used to modify functions and can share inputs, they have separate scopes. The following example will **not** work: ```vocs_Code Copy// Bad code example, does not work modifier doubler(uint _number) { _number *= 2; _; } function modifierDoubler(uint _number) public pure doubler(_number) returns (uint) { return _number; // Returns the original number, NOT number * 2 } ``` * * * ## Conclusion Function `modifier` s are an efficient and reusable way to add checks, trigger errors, and control function execution. In this lesson, you've seen examples of how they can be used to abort execution under certain conditions. You've also learned that they have separate scopes and cannot be used to modify variables within the function they modify. ## Chainlink Price Feeds 404 The requested path could not be found ## Smart Wallet Tutorial 404 The requested path could not be found ## Biconomy Account Abstraction 404 The requested path could not be found ## Run a Base Node [Skip to content](https://docs.base.org/chain/run-a-base-node#vocs-content) Menu Run a Base Node On this page Chevron Right This tutorial will walk you through setting up your own [Base Node](https://github.com/base-org/node). ## Objectives By the end of this tutorial you should be able to: - Deploy and sync a Base node ## Prerequisites Running a node is time consuming, resource expensive, and potentially costly. If you don't already know why you want to run your own node, you probably don't need to. If you're just getting started and need an RPC URL, you can use our free endpoints: - **Mainnet**: `https://mainnet.base.org` - **Testnet (Sepolia)**: `https://sepolia.base.org` **Note:** Our RPCs are rate-limited, they are not suitable for production apps. If you're looking to harden your app and avoid rate-limiting for your users, please check out one of our [partners](https://docs.base.org/chain/node-providers). ### Hardware requirements We recommend you have this configuration to run a node: - 8-Core CPU - at least 16 GB RAM - a locally attached NVMe SSD drive - adequate storage capacity to accommodate both the snapshot restoration process (if restoring from snapshot) and chain data, ensuring a minimum of (2 \* current\_chain\_size) + snapshot\_size + 20%\_buffer ### Docker This tutorial assumes you are familiar with [Docker](https://www.docker.com/) and have it running on your machine. ### L1 RPC URL You'll need your own L1 RPC URL. This can be one that you run yourself, or via a third-party provider, such as our [partners](https://docs.base.org/chain/node-providers). ## Running a Node 1. Clone the [repo](https://github.com/base-org/node). 2. Ensure you have an Ethereum L1 full node RPC available (not Base), and set `OP_NODE_L1_ETH_RPC` & `OP_NODE_L1_BEACON` (in the `.env.*` file if using `docker-compose`). If running your own L1 node, it needs to be synced before Base will be able to fully sync. 3. Uncomment the line relevant to your network ( `.env.sepolia`, or `.env.mainnet`) under the 2 `env_file` keys in `docker-compose.yml`. 4. Run `docker compose up`. Confirm you get a response from: Terminal Terminal ```vocs_Code Copycurl -d '{"id":0,"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false]}' \ -H "Content-Type: application/json" http://localhost:8545 ``` Syncing your node may take **days** and will consume a vast amount of your requests quota. Be sure to monitor usage and up your plan if needed. ### Snapshots If you're a prospective or current Base Node operator and would like to restore from a snapshot to save time on the initial sync, it's possible to always get the latest available snapshot of the Base chain on mainnet and/or testnet by using the following CLI commands. The snapshots are updated every week. #### Restoring from snapshot 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. | 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 | 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 | 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). Return to the root of your Base node folder and start your node. Terminal Terminal ```vocs_Code Copycd .. docker compose up --build ``` Your node should begin syncing from the last block in the snapshot. Check the latest block to make sure you're syncing from the snapshot and that it restored correctly. If so, you can remove the snapshot archive that you downloaded. ### Syncing You can monitor the progress of your sync with: Terminal Terminal ```vocs_Code Copyecho Latest synced block behind by: $((($(date +%s)-$( \ curl -d '{"id":0,"jsonrpc":"2.0","method":"optimism_syncStatus"}' \ -H "Content-Type: application/json" http://localhost:7545 | \ jq -r .result.unsafe_l2.timestamp))/60)) minutes ``` You'll also know that the sync hasn't completed if you get `Error: nonce has already been used` if you try to deploy using your node. ## OnchainKit Providers [Skip to content](https://docs.base.org/builderkits/onchainkit/config/supplemental-providers#vocs-content) Menu Custom Supplemental Providers On this page Chevron Right Under the hood, OnchainKit will create our recommended Wagmi and QueryClient providers. If you wish to customize the providers, you can do so by creating these providers with your own configuration. For example, the following code creates custom Wagmi and QueryClient providers: wagmi.tsproviders.tsx File wagmi.ts ```vocs_Code Copyimport { http, cookieStorage, createConfig, createStorage } from 'wagmi'; import { base } from 'wagmi/chains'; // add baseSepolia for testing import { coinbaseWallet } from 'wagmi/connectors'; export function getConfig() { return createConfig({ chains: [base], // add baseSepolia for testing connectors: [\ coinbaseWallet({\ appName: 'OnchainKit',\ preference: 'smartWalletOnly',\ version: '4',\ }),\ ], storage: createStorage({ storage: cookieStorage, }), ssr: true, transports: { [base.id]: http(), // add baseSepolia for testing }, }); } declare module 'wagmi' { interface Register { config: ReturnType; } } ``` # Start building! Explore our ready-to-use onchain components: - [**`Identity`**](https://docs.base.org/builderkits/onchainkit/identity/identity)\- Show [Basenames](https://docs.base.org/builderkits/onchainkit/identity/identity), [avatars](https://docs.base.org/builderkits/onchainkit/identity/avatar), [badges](https://docs.base.org/builderkits/onchainkit/identity/badge), and [addresses](https://docs.base.org/builderkits/onchainkit/identity/address). - [**`Wallet`**](https://docs.base.org/builderkits/onchainkit/wallet/wallet)\- Create or connect wallets with [Connect Wallet](https://docs.base.org/builderkits/onchainkit/wallet/wallet). - [**`Transaction`**](https://docs.base.org/builderkits/onchainkit/transaction/transaction)\- Handle [transactions](https://docs.base.org/builderkits/onchainkit/transaction/transaction) using EOAs or Smart Wallets. - [**`Checkout`**](https://docs.base.org/builderkits/onchainkit/checkout/checkout)\- Integrate USDC [checkout](https://docs.base.org/builderkits/onchainkit/checkout/checkout) flows with ease. - [**`Fund`**](https://docs.base.org/builderkits/onchainkit/fund/fund-button)\- Create a [funding](https://docs.base.org/builderkits/onchainkit/fund/fund-button) flow to onboard users. - [**`Tokens`**](https://docs.base.org/builderkits/onchainkit/token/token-chip)\- Search and display [tokens](https://docs.base.org/builderkits/onchainkit/token/token-chip) with various components. - [**`Swap`**](https://docs.base.org/builderkits/onchainkit/swap/swap)\- Enable [token swaps](https://docs.base.org/builderkits/onchainkit/swap/swap) in your app. - [**`Mint`**](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card)- [View](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) and [Mint](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) NFTs in your app. ## Decentralize Social App [Skip to content](https://docs.base.org/use-cases/decentralize-social-app#vocs-content) Menu Decentralize your social app On this page Chevron Right Onchain social apps can use onchain identity, which allows users to carry a single, portable profile across many applications. By leveraging onchain identity, your app can instantly personalize the user experience as soon as a user connects their wallet. This creates a frictionless experience where users feel recognized immediately. This guide will walk you through how to integrate onchain identity into your social app. ## Benefits - **Seamless Onboarding:** Eliminate tedious information collection from your onboarding flow. - **Instant Personalization:** Delight users by displaying their profile information the first time they open your app. - **Global Profiles:** Leverage the user's global profile instead of building your own profile management. If the user updates their Avatar anywhere, it automatically updates everywhere. Onchain profiles are built with Basenames and ENS, services which wrap wallet addresses with profile information like names and avatars. Using the IdentityCard component from OnchainKit we can easily display a user’s Basename or ENS profile in our app. `` will display the user's: - Name - Avatar - Socials - Verification Badge ## Integrating `` ### Install and Configure OnchainKit Creating a new OnchainKit app is the easiest way to get started. Terminal Terminal ```vocs_Code Copynpm create onchain@latest ``` Or you can integrate OnchainKit into an existing app by following the [installation guide](https://docs.base.org/builderkits/onchainkit/getting-started#manual-installation). ### Add the IdentityCard component File App.tsx ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; ``` Just like that, you've added onchain identity into your app! Once a user connects a wallet with a Basename or ENS name, the IdentityCard component will display the user's profile information like you see below. The IdentityCard component comes with helpful defaults, such as a plain avatar image, for users who don't have a Basename or ENS name. ## Customization Since every app is different, OnchainKit's components are designed to be easily customized. You can override styles using `className` or by setting a custom [OnchainKit theme](https://docs.base.org/builderkits/onchainkit/guides/themes#custom-theme). You can also set the `mainnet` chain for ENS name resolution: ```vocs_Code Copyimport { IdentityCard } from '@coinbase/onchainkit/identity'; import { mainnet } from 'viem/chains'; ``` In the above customization we updated the theme to the `cyberpunk` theme and defined the chain as `mainnet` to trigger ENS name resolution. ## Next Steps By using ``, you've essentially given your app a “user profile” feature powered by onchain data. Users will have the magical experience of being welcomed by their profile as soon as they jump into your app without getting stuck in a laborious onboarding flow. ### Keep Building If you're building a social app, there are additional features you may want to explore: - [``](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) \- Allow users to mint NFTs directly from your app. - Social feed integration with [Farcaster](https://docs.farcaster.xyz/developers/) \- Bring the farcaster feed directly into your app. - [``](https://docs.base.org/builderkits/onchainkit/checkout/checkout) \- Allow users to checkout with onchain payments if your app offers products or services. ## FundCard Integration Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/fund/fund-card#vocs-content) Menu FundCard On this page Chevron Right ![FundCard](https://docs.base.org/images/onchainkit/fund-card.gif) The `` component provides a complete fiat onramp experience within your app. It includes: - Amount input with fiat/crypto switching - Payment method selection (Coinbase, Apple Pay, Debit Card) - Automatic exchange rate updates - Smart handling of payment method restrictions (based on country and subdivision) ## Prerequisites Before using the `FundCard` component, ensure you've completed the [Getting Started](https://docs.base.org/builderkits/onchainkit/installation/nextjs#get-your-client-api-key) steps. ## Usage ### Drop in the `` component ```vocs_Code Copyimport { FundCard } from '@coinbase/onchainkit/fund'; ; ``` ## Customization ### Custom Header and Button Text You can customize the header and button text: ```vocs_Code Copy ``` ### Custom Currency You can specify which fiat currency to use: ```vocs_Code Copy ``` ### Preset Amount Inputs You can specify preset amount buttons: ```vocs_Code Copyconst presetAmountInputs = ['10', '20', '50'] as const; ; ``` ### Custom Content You can provide custom children to completely customize the card content while keeping the fund button functionality: ```vocs_Code Copy

Custom Header

``` You can also reuse the existing children from the default implementation and add your own custom content. ```vocs_Code Copyimport { FundCardHeader, FundCardAmountInput, FundCardAmountInputTypeSwitch, FundCardPresetAmountInputList, FundCardPaymentMethodDropdown, FundCardSubmitButton, } from '@coinbase/onchainkit/fund';

Custom Header instead of the default "FundCardHeader"

Any custom content
Any custom content
``` ```vocs_Code Copyconst { asset, currency, selectedPaymentMethod, setSelectedPaymentMethod, fundAmountFiat, setFundAmountFiat, fundAmountCrypto, setFundAmountCrypto, selectedInputType, setSelectedInputType, exchangeRate, setExchangeRate, exchangeRateLoading, setExchangeRateLoading, submitButtonState, setSubmitButtonState, paymentMethods, setPaymentMethods, paymentMethodsLoading, setPaymentMethodsLoading, headerText, buttonText, country, subdivision, lifecycleStatus, updateLifecycleStatus, presetAmountInputs, } = useFundContext(); ``` ## Props - [`FundCardPropsReact`](https://docs.base.org/builderkits/onchainkit/fund/types#fundcardpropsreact) ## Related Components - [``](https://docs.base.org/builderkits/onchainkit/fund/fund-button) ## Wallet Funding Button [Skip to content](https://docs.base.org/builderkits/onchainkit/fund/fund-button#vocs-content) Menu FundButton On this page Chevron Right The `` component provides a way for users to fund their wallet without leaving your app. It automatically detects the user's wallet type (EOA vs Smart Wallet) and directs them to the appropriate funding URL. If your user connects a Coinbase Smart Wallet, it provides an easy way to access the Coinbase Smart Wallet [Fund](https://keys.coinbase.com/fund) flow. Users will be able to buy and receive crypto, or use their Coinbase balances onchain with [Magic Spend](https://www.smartwallet.dev/guides/magic-spend). If your user connects any other EOA wallet, it provides an easy way to access [Coinbase Onramp](https://docs.cdp.coinbase.com/onramp/docs/welcome/) where your users will also be able to buy crypto using a fiat payment method, or transfer existing crypto from their Coinbase account. Before using it, ensure you've completed all [Getting Started steps](https://docs.base.org/builderkits/onchainkit/getting-started). ## Walkthrough ### Get your Project ID 1. Get your Project ID from the [Coinbase Developer Platform Dashboard](https://portal.cdp.coinbase.com/). ![OnchainKit copy Project Id](https://docs.base.org/images/onchainkit/copy-project-id.png) 2. Add your Project ID to your `.env` file. File .env ```vocs_Code CopyNEXT_PUBLIC_ONCHAINKIT_API_KEY=YOUR_PUBLIC_API_KEY NEXT_PUBLIC_CDP_PROJECT_ID=YOUR_CDP_PROJECT_ID ``` ### Add Project ID to OnchainKitProvider ```vocs_Code Copy {props.children} ``` ### Drop in the `` component ```vocs_Code Copyimport { FundButton } from '@coinbase/onchainkit/fund'; ``` Connect Wallet ## Customizing the funding experience You can customize the Coinbase Onramp experience by bringing your own Onramp URL and passing it to the `` component. We provide the [`getOnrampBuyUrl`](https://docs.base.org/builderkits/onchainkit/fund/get-onramp-buy-url) utility to help you generate a Coinbase Onramp URL tailored to your use case. ```vocs_Code Copyimport { FundButton, getOnrampBuyUrl } from '@coinbase/onchainkit/fund'; import { useAccount } from 'wagmi'; const projectId = 'YOUR_CDP_PROJECT_ID'; const { address } = useAccount(); const onrampBuyUrl = getOnrampBuyUrl({ projectId, addresses: { [address]: ['base'] }, assets: ['USDC'], presetFiatAmount: 20, fiatCurrency: 'USD' }); ``` Connect Wallet You can choose to have the funding URL open in a popup or a new tab using the `openIn` prop. ```vocs_Code Copy ``` Connect Wallet ## Customizing the fund button You can override the text on the fund button using the `text` prop, and hide the icon with the `hideIcon` prop. ```vocs_Code Copy ``` Connect Wallet You can hide the text with the `hideText` prop. ```vocs_Code Copy ``` Connect Wallet See [`FundButtonReact`](https://docs.base.org/builderkits/onchainkit/fund/types#fundbuttonreact) for the full list of customization options. ## Props - [`FundButtonReact`](https://docs.base.org/builderkits/onchainkit/fund/types#fundbuttonreact) ## Swap Settings [Skip to content](https://docs.base.org/builderkits/onchainkit/swap/swap-settings#vocs-content) Menu SwapSettings On this page Chevron Right The `SwapSettings` component enables customizable slippage configuration in the `Swap` component. ## Usage ```vocs_Code Copy// omitted for brevity import { Swap, SwapSettings, SwapSettingsSlippageDescription, SwapSettingsSlippageInput, SwapSettingsSlippageTitle, } from '@coinbase/onchainkit/swap'; Max. slippage Your swap will revert if the prices change by more than the selected percentage. ``` Connect Wallet ### Override styles You can override component styles using `className`. ```vocs_Code Copy// omitted for brevity Max. slippage Your swap will revert if the prices change by more than the selected percentage. ``` Connect Wallet ### Override icon You can override the icon using the icon prop. ```vocs_Code Copy// omitted for brevity ``` Connect Wallet ### Add text You can add text next to the `SwapSettings` component using text. ```vocs_Code Copy// omitted for brevity ``` Connect Wallet ### Override text You can override component text by providing children text. ```vocs_Code Copy// omitted for brevity Slippage Settings Set a max slippage you are willing to accept. ``` Connect Wallet ## Components - `` \- Container component for swap slippage settings. - `` \- Displays description text explaining the slippage setting. - `` \- Input field for users to enter their desired max slippage percentage - `` \- Displays the title for the slippage settings section ## Props - [`SwapSettingsReact`](https://docs.base.org/builderkits/onchainkit/swap/types#swapsettingsreact) - [`SwapSettingsSlippageDescriptionReact`](https://docs.base.org/builderkits/onchainkit/swap/types#swapsettingsslippagedescriptionreact) - [`SwapSettingsSlippageInputReact`](https://docs.base.org/builderkits/onchainkit/swap/types#swapsettingsslippageinputreact) - [`SwapSettingsSlippageTitleReact`](https://docs.base.org/builderkits/onchainkit/swap/types#swapsettingsslippagetitlereact) ## Passkeys for Smart Wallet [Skip to content](https://docs.base.org/identity/smart-wallet/features/passkeys#vocs-content) Menu Passkeys On this page Chevron Right ## Passkeys Passkeys enable instant account creation and seamless authentication for Smart Wallet users, dramatically simplifying onboarding. By leveraging FIDO2-compliant authentication, passkeys eliminate seed phrases while providing enterprise-grade security for both wallet access and onchain ownership. During account creation, a cryptographic key pair is generated and the private key is securely stored on the user's device, while the public key is registered onchain as an owner of the user's Smart Wallet. The passkey serves two core functions: 1. **Authentication**: Replaces passwords for wallet access. 2. **Transaction Signing**: Functions as the signing key for onchain transactions, replacing private keys and seed phrases. ### Cross-Device Support Passkeys leverage platform authenticator APIs for cross-device synchronization through: - iCloud Keychain (Apple devices) - Google Password Manager - 1Password - Any WebAuthn-compatible password manager This enables seamless multi-device support without exposing the underlying cryptographic material. ## Launch AI Agents [Skip to content](https://docs.base.org/use-cases/launch-ai-agents#vocs-content) Menu Launch AI Agents On this page Chevron Right AI Agents are even better when they're onchain! Onchain agents have access to stablecoins, tokens, NFTs, and more. This significantly increases their autonomy and the universe of tasks they can perform. In this guide, you can select your preferred framework and setup to learn how to launch an AI Agent on Base with CDP Wallet API. ### Agent Framework LangChainEliza ### Setup ReplitLocal * * * ## LangChain Replit Setup ### Set Up Your Development Environment 1. Fork the template from our [NodeJS](https://replit.com/@lincolnmurr/AgentKitjs-Quickstart-010?v=1) or [Python](https://replit.com/@lincolnmurr/AgentKitpy-01?v=1) Replit templates. 2. Modify your forked project as needed. ### Configure Environment Variables 1. Click on "Tools" in the left sidebar and select "Secrets". 2. Add the following secrets: ```vocs_Code CopyCDP_API_KEY_NAME=your_cdp_key_name CDP_API_KEY_PRIVATE_KEY=your_cdp_private_key OPENAI_API_KEY=your_openai_key # Or XAI_API_KEY if using NodeJS NETWORK_ID="base-sepolia" # Optional, defaults to base-sepolia MNEMONIC_PHRASE=your_mnemonic_phrase # Optional ``` ### Run the Agent 1. Click the "Run" button to start the chatbot. ## Run a Base Node [Skip to content](https://docs.base.org/chain/run-a-base-node#vocs-content) Menu Run a Base Node On this page Chevron Right This tutorial will walk you through setting up your own [Base Node](https://github.com/base-org/node). ## Objectives By the end of this tutorial you should be able to: - Deploy and sync a Base node ## Prerequisites Running a node is time consuming, resource expensive, and potentially costly. If you don't already know why you want to run your own node, you probably don't need to. If you're just getting started and need an RPC URL, you can use our free endpoints: - **Mainnet**: `https://mainnet.base.org` - **Testnet (Sepolia)**: `https://sepolia.base.org` **Note:** Our RPCs are rate-limited, they are not suitable for production apps. If you're looking to harden your app and avoid rate-limiting for your users, please check out one of our [partners](https://docs.base.org/chain/node-providers). ### Hardware requirements We recommend you have this configuration to run a node: - 8-Core CPU - at least 16 GB RAM - a locally attached NVMe SSD drive - adequate storage capacity to accommodate both the snapshot restoration process (if restoring from snapshot) and chain data, ensuring a minimum of (2 \* current\_chain\_size) + snapshot\_size + 20%\_buffer ### Docker This tutorial assumes you are familiar with [Docker](https://www.docker.com/) and have it running on your machine. ### L1 RPC URL You'll need your own L1 RPC URL. This can be one that you run yourself, or via a third-party provider, such as our [partners](https://docs.base.org/chain/node-providers). ## Running a Node 1. Clone the [repo](https://github.com/base-org/node). 2. Ensure you have an Ethereum L1 full node RPC available (not Base), and set `OP_NODE_L1_ETH_RPC` & `OP_NODE_L1_BEACON` (in the `.env.*` file if using `docker-compose`). If running your own L1 node, it needs to be synced before Base will be able to fully sync. 3. Uncomment the line relevant to your network ( `.env.sepolia`, or `.env.mainnet`) under the 2 `env_file` keys in `docker-compose.yml`. 4. Run `docker compose up`. Confirm you get a response from: Terminal Terminal ```vocs_Code Copycurl -d '{"id":0,"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false]}' \ -H "Content-Type: application/json" http://localhost:8545 ``` Syncing your node may take **days** and will consume a vast amount of your requests quota. Be sure to monitor usage and up your plan if needed. ### Snapshots If you're a prospective or current Base Node operator and would like to restore from a snapshot to save time on the initial sync, it's possible to always get the latest available snapshot of the Base chain on mainnet and/or testnet by using the following CLI commands. The snapshots are updated every week. #### Restoring from snapshot 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. | 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 | 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 | 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). Return to the root of your Base node folder and start your node. Terminal Terminal ```vocs_Code Copycd .. docker compose up --build ``` Your node should begin syncing from the last block in the snapshot. Check the latest block to make sure you're syncing from the snapshot and that it restored correctly. If so, you can remove the snapshot archive that you downloaded. ### Syncing You can monitor the progress of your sync with: Terminal Terminal ```vocs_Code Copyecho Latest synced block behind by: $((($(date +%s)-$( \ curl -d '{"id":0,"jsonrpc":"2.0","method":"optimism_syncStatus"}' \ -H "Content-Type: application/json" http://localhost:7545 | \ jq -r .result.unsafe_l2.timestamp))/60)) minutes ``` You'll also know that the sync hasn't completed if you get `Error: nonce has already been used` if you try to deploy using your node. ## Base.org Tags Guide 404 The requested path could not be found ## Farcaster Frames Tutorial 404 The requested path could not be found ## Ethereum Virtual Machine Overview [Skip to content](https://docs.base.org/learn/introduction-to-ethereum/evm-diagram#vocs-content) Menu EVM Diagram On this page Chevron Right In this article, we'll examine the inner workings of the EVM, its components, and its role within the Ethereum network. * * * ## Objectives By the end of this lesson you should be able to: - Diagram the EVM * * * ## What is the EVM? The Ethereum Virtual Machine (EVM) is the core engine of Ethereum. It is a Turing-complete, sandboxed virtual machine designed to execute smart contracts on the network. The term "sandboxed" means that the EVM operates in an isolated environment, ensuring that each smart contract's execution does not interfere with others or the underlying blockchain. As we've learned, the EVM's Turing-complete nature allows developers to write complex programs that can perform any computationally feasible task. The EVM employs a sophisticated resource management system using gas to regulate computation costs and prevent network abuse. It also supports a rich ecosystem of onchain apps by providing a versatile set of opcodes for smart contract logic, and fostering interoperability with various programming languages, tools, and technologies. This adaptability has made the EVM a fundamental component in the advancement and growth of the Ethereum network. * * * ## EVM Components The EVM has several key components that enable it to process and manage smart contracts. Let's define them: - **World State:** Represents the entire Ethereum network, including all accounts and their associated storage. - **Accounts:** Entities that interact with the Ethereum network, including Externally Owned Accounts (EOAs) and Contract Accounts. - **Storage:** A key-value store associated with each contract account, containing the contract's state and data. - **Gas:** A mechanism for measuring the cost of executing operations in the EVM, which protects the network from spam and abuse. - **Opcodes:** Low-level instructions that the EVM executes during smart contract processing. - **Execution Stack:** A last-in, first-out (LIFO) data structure for temporarily storing values during opcode execution. - **Memory:** A runtime memory used by smart contracts during execution. - **Program Counter:** A register that keeps track of the position of the next opcode to be executed. - **Logs:** Events emitted by smart contracts during execution, which can be used by external systems for monitoring or reacting to specific events. * * * ## EVM Execution Model In simple terms, when a transaction is submitted to the network, the EVM first verifies its validity. If the transaction is deemed valid, the EVM establishes an execution context that incorporates the current state of the network and processes the smart contract's bytecode using opcodes. As the EVM runs the smart contract, it modifies the blockchain's world state and consumes gas accordingly. However, if the transaction is found to be invalid, it will be dismissed by the network without further processing. Throughout the smart contract's execution, logs are generated that provide insights into the contract's performance and any emitted events. These logs can be utilized by external systems for monitoring purposes or to respond to specific events. ![EVM Execution Model](https://docs.base.org/images/learn/ethereum-virtual-machine/evm-execution-basic.png) * * * ## Gas and Opcode Execution While we have already delved into the concept of gas in a previous lesson, it is worth reiterating its critical role within the EVM and as a fundamental component of Ethereum. Gas functions as a metric for quantifying the computational effort needed to carry out operations in the EVM. Every opcode in a smart contract carries a specific gas cost, which reflects the computational resources necessary for its execution. Opcodes are the low-level instructions executed by the EVM. They represent elementary operations that allow the EVM to process and manage smart contracts. ![Opcode Execution](https://docs.base.org/images/learn/ethereum-virtual-machine/opcode-execution.png) During execution, the EVM reads opcodes from the smart contract, and depending on the opcode, it may update the world state, consume gas, or revert the state if an error occurs. Some common opcodes include: - **ADD:** Adds two values from the stack. - **SUB:** Subtracts two values from the stack. - **MSTORE:** Stores a value in memory. - **SSTORE:** Stores a value in contract storage. - **CALL:** Calls another contract or sends ether. * * * ## Stack and Memory The EVM stack and memory are critical components of the EVM architecture, as they enable smart contracts to manage temporary data during opcode execution. The stack is a last-in, first-out (LIFO) data structure that is used for temporarily storing values during opcode execution. It is managed by the EVM and is separate from the contract's storage. The stack supports two primary operations: push and pop. The push operation adds a value to the top of the stack, while the pop operation removes the top value from the stack. These operations are used to manage temporary data during opcode execution. For example, an opcode that performs an addition operation might push the two operands onto the stack, perform the addition, and then pop the result off the top of the stack. During contract execution, memory serves as a collection of bytes, organized in an array, for the purpose of temporarily storing data. It can be read from and written to by opcodes. Memory is often used to store temporary data during opcode execution, such as when working with dynamically sized data like strings or arrays that are being manipulated or computed within the smart contract before being stored in the contract's storage. When a smart contract needs to store temporary data during opcode execution, it can use the memory to store that data. ![EVM Stack and Memory](https://docs.base.org/images/learn/ethereum-virtual-machine/evm-stack-memory.png) * * * ## EVM Architecture and Execution Context To understand the inner workings of the EVM, the following diagram offers a streamlined visualization of its transaction execution process. It begins with the transaction initiation, and progresses to the gas computations for each operation. Integral to the process are the EVM's stack, memory, and storage, which are engaged to manage and persist data throughout the lifecycle of a transaction. Checks and validations at each step ensure the validity of operations, safeguarding the network's integrity. This systemized sequence of actions forms the bedrock of transaction and smart contract execution, ensuring Ethereum's consistent and secure operation. ![EVM architecture and execution context](https://docs.base.org/images/learn/ethereum-virtual-machine/evm-architecture-execution.png) * * * ## Conclusion The EVM plays a vital role within the Ethereum network. By examining the EVM's key components as well as its architecture and execution model, we've gained insight into the engine of Ethereum and how it enables the smooth execution of smart contracts on the platform. * * * ## See Also - [The Ethereum Virtual Machine (Mastering Ethereum)](https://cypherpunks-core.github.io/ethereumbook/13evm.html#evm_architecture) - [Ethereum Virtual Machine (Ethereum docs)](https://ethereum.org/en/developers/docs/evm/) ## Smart Contract Deployment Guide [Skip to content](https://docs.base.org/learn/hardhat-deploy/hardhat-deploy-sbs#vocs-content) Menu Step by Step Guide On this page Chevron Right In this article, you'll learn how to deploy smart contracts to multiple Blockchain networks using Hardhat and Hardhat deploy. * * * ## Objectives By the end of this lesson, you should be able to: - Deploy a smart contract to the Base Sepolia Testnet with hardhat-deploy - Deploy a smart contract to the Sepolia Testnet with hardhat-deploy - Use BaseScan to view a deployed smart contract * * * ## Overview Hardhat capabilities enable developers to deploy smart contracts easily to any Blockchain by simply creating `tasks` or `scripts`. However, due to the Hardhat architecture that enables its extension by creating plugins, you can rely on existing solutions developed by the community. [Hardhat deploy](https://github.com/wighawag/hardhat-deploy) is a community-developed plugin that enables the deployment of your smart contracts in a simple way. ## Setting up Hardhat deploy To install: 1. Run `npm install -D hardhat-deploy`. Then, import hardhat-deploy in `hardhat.config.ts`: ```vocs_Code Copyimport 'hardhat-deploy'; ``` 2. Create a folder called deploy and inside it create a new file called `001_deploy_lock.ts`. 3. Include the following: ```vocs_Code Copyimport { HardhatRuntimeEnvironment } from 'hardhat/types'; import { DeployFunction } from 'hardhat-deploy/types'; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // code here }; export default func; ``` 4. Modify the `tsconfig.json` file to look like: ```vocs_Code Copy{ "compilerOptions": { "target": "es2020", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "resolveJsonModule": true }, "include": ["./hardhat.config.ts", "./scripts", "./deploy", "./test"] } ``` 5. Before implementing the deploy functionality, configure a deployer account in the `hardhat.config.ts` file. Hardhat deployment includes a way to name accounts in the config file. 6. Run the following, which adds an alias to the account 0 of your environment: ```vocs_Code Copyconst config: HardhatUserConfig = { solidity: '0.8.23', namedAccounts: { deployer: 0, }, }; ``` 7. Implement the deploy function by including the following in the `001_deploy_lock.ts` file: ```vocs_Code Copyimport { HardhatRuntimeEnvironment } from 'hardhat/types'; import { DeployFunction } from 'hardhat-deploy/types'; import { ethers } from 'hardhat'; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deploy } = hre.deployments; // We can now use deployer const { deployer } = await hre.getNamedAccounts(); // The value we want to lock const VALUE_LOCKED = hre.ethers.parseEther('0.01'); // The unlock time after deployment const UNLOCK_TIME = 10000; // We use ethers to get the current time stamp const blockNumber = await ethers.provider.getBlockNumber(); const lastBlockTimeStamp = (await ethers.provider.getBlock(blockNumber))?.timestamp as number; // We say we want to deploy our Lock contract using the deployer // account and passing the value and arguments. await deploy('Lock', { from: deployer, args: [lastBlockTimeStamp + UNLOCK_TIME], value: VALUE_LOCKED.toString(), }); }; export default func; // This tag will help us in the next section to trigger this deployment file programmatically func.tags = ['DeployAll']; ``` ## Testing your deployment The easiest way to test your deployment is by modifying the test. Go to `Lock.ts` and include in the imports the following: ```vocs_Code Copyimport { ethers, deployments } from 'hardhat'; ``` `deployments` will allow you to execute the deployment files from your test. Change the `before` function to look like the following: ```vocs_Code Copybefore(async () => { lastBlockTimeStamp = await time.latest(); const signers = await ethers.getSigners(); ownerSigner = signers[0]; otherUserSigner = signers[1]; await deployments.fixture(['DeployAll']); const lockDeployment = await deployments.get('Lock'); lockInstance = Lock__factory.connect(lockDeployment.address, ownerSigner); }); ``` Notice how you execute `deployments.fixture` and pass a tag that matches the one you specified in the deployment file ( `001_deploy_lock.ts`). The deployment file is then executed and you can then reuse that functionality and simply consume the address of the newly-deployed contract by using: ```vocs_Code Copyconst lockDeployment = await deployments.get('Lock'); ``` Reuse `Lock__factory` but use the connect function and pass the address of the newly-created contract plus a signer. Then, run `npx hardhat test` and you should get the same result: ```vocs_Code Copy Lock ✔ 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 an owner 6 passing (2s) ``` ## Deploying to a test network 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 account you want to use - Real test ether or the native Blockchain token for gas costs Include the following in the `hardhat.config.ts` file: ```vocs_Code Copyconst config: HardhatUserConfig = { solidity: '0.8.18', namedAccounts: { deployer: 0, }, networks: { base_sepolia: { url: 'https://sepolia.base.org', accounts: { mnemonic: process.env.MNEMONIC ?? '', }, }, sepolia: { url: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_SEPOLIA_KEY ?? ''}`, accounts: { mnemonic: process.env.MNEMONIC ?? '', }, }, }, }; ``` You've configured 2 networks: - base\_sepolia - sepolia You also need to create a `.env` file with the following variables: ```vocs_Code CopyMNEMONIC="" ALCHEMY_SEPOLIA_KEY= ``` In order to ensure the environment variables are loaded, you need to install another package called `dotenv`: ```vocs_Code Copynpm install -D dotenv ``` Then, include the following in the `hardhat.config.ts` file: ```vocs_Code Copyimport dotenv from 'dotenv'; dotenv.config(); ``` Deploy to base with the following command: ```vocs_Code Copynpx hardhat deploy --network base_sepolia ``` After you run the command, a deployments folder appears with a newly-created deployment for `base_sepolia`: ![New deployment](https://docs.base.org/images/hardhat-deploying/new-deploy.png) If you want to deploy to another network, change the network name as follows: ```vocs_Code Copynpx hardhat deploy --network sepolia ``` ## Conclusion In this lesson, you've learned how to deploy smart contracts using Hardhat and Hardhat-deploy. You have configured hardhat to easily deploy to multiple networks and you created deployment files to abstract this task. * * * ## See also [Solidity Docs](https://docs.soliditylang.org/en/v0.8.17/) \[Remix Project\]: [https://remix-project.org/](https://remix-project.org/) \[Hardhat\]: [https://hardhat.org/](https://hardhat.org/) \[Hardhat Deploy\]: [https://github.com/wighawag/hardhat-deploy](https://github.com/wighawag/hardhat-deploy) ## Minimal Token Guide [Skip to content](https://docs.base.org/learn/minimal-tokens/minimal-token-sbs#vocs-content) Menu Step by Step Guide On this page Chevron Right At their core, tokens are very simple. The technology powering famous NFT collections and fungible tokens worth vast amounts of money simply uses the EVM to keep track of who owns what, and provides a permissionless way for the owner to transfer what they own to someone new. * * * ## Objectives By the end of this lesson you should be able to: - Construct a minimal token and deploy to testnet - Identify the properties that make a token a token * * * ## Implementing a Token The minimal elements needed for a token are pretty basic. Start by creating a contract called `MinimalToken`. Add a `mapping` to relate user addresses to the number of tokens they possess. Finally, add a variable to track `totalSupply`: Reveal code ```vocs_Code Copycontract MinimalToken { mapping (address => uint) public balances; uint public totalSupply; } ``` Add a `constructor` that initializes the `totalSupply` at 3000 and assigns ownership to the contract creator: Reveal code ```vocs_Code Copyconstructor() { totalSupply = 3000; balances[msg.sender] = totalSupply; } ``` Deploy and test to confirm that the total supply is 3000, and the balance of the first account is as well. ![Balance](https://docs.base.org/images/learn/minimal-tokens/balance.png) Update the constructor and hardcode a distribution of the tokens to be evenly split between the first three test accounts: Reveal code ```vocs_Code Copyconstructor() { totalSupply = 3000; balances[msg.sender] = totalSupply / 3; balances[0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2] = totalSupply / 3; balances[0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db] = totalSupply / 3; } ``` Redeploy and test again. Now, each of the first three accounts should have 1000 tokens. ![Balance](https://docs.base.org/images/learn/minimal-tokens/split-balances.png) * * * ## Transferring Tokens We can set an initial distribution of tokens and we can see balances, but we're still missing a way to allow the owners of these tokens to share them or spend them. To remediate this, all we need to do is add a function that can update the balances of each party in the transfer. Add a `function` called `transfer` that accepts an `address` of `_to` and a `uint` for the `_amount`. You don't need to add anything for `_from`, because that should only be `msg.sender`. The function should subtract the `_amount` from the `msg.sender` and add it to `_to`: Reveal code ```vocs_Code Copyfunction transfer(address _to, uint _amount) public { balances[msg.sender] -= _amount; balances[_to] += _amount; } ``` Double-check that you've switched back to the first address and redeploy. Then, try sending 500 tokens to the second address. ![Balance](https://docs.base.org/images/learn/minimal-tokens/transferred.png) What happens if you try to transfer more tokens than an account has? Give it a try! ```vocs_Code Copytransact to MinimalToken.transfer pending ... transact to MinimalToken.transfer errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information. ``` You won't be able to do it, though the `Note:` here is **misleading**. In the EVM, `payable` **only** refers to transfers of the primary token used to pay gas fees: ETH, Base ETH, Sepolia ETH, Matic, etc. It does **not** refer to the balance of our simple token. Instead, the transaction is reverting because of the built-in overflow/underflow protection. It's not a great programming practice to depend on this, so add an error for `InsufficientTokens` that returns the `newSenderBalance`. ```Solidity vocs_Code Copyfunction transfer(address _to, uint _amount) public { int newSenderBalance = int(balances[msg.sender] - _amount); if (newSenderBalance < 0) { revert InsufficientTokens(newSenderBalance); } balances[msg.sender] = uint(newSenderBalance); balances[_to] += _amount; } ``` Try spending too much again. You'll get the same error in Remix: ```vocs_Code Copytransact to MinimalToken.transfer pending ... transact to MinimalToken.transfer errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information. ``` However, you can use the debug tool to review the error in memory to see that it now matches your custom `error`. ## Destroying Tokens Tokens can be effectively destroyed by accident, or on purpose. Accidental destruction happens when someone sends a token to an unowned wallet address. While it's possible that some day, some lucky person will create a new wallet and find a pleasant surprise, the most likely outcome is that any given randomly chosen address will never be used, thus no one will ever have the ability to use or transfer those tokens. Luckily, there are some protections here. Similar to credit card numbers, addresses have a built-in checksum that helps protect against typos. Try it out by trying to transfer tokens to the second Remix address, but change the first character in the address from `A` to `B`. You'll get an error: ```vocs_Code Copytransact to MinimalToken.transfer errored: Error encoding arguments: Error: bad address checksum (argument="address", value="0xBb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", code=INVALID_ARGUMENT, version=address/5.5.0) (argument=null, value="0xBb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", code=INVALID_ARGUMENT, version=abi/5.5.0) ``` A more guaranteed way to destroy, or _burn_ a token, is to transfer it to the default address `0x0000000000000000000000000000000000000000`. This address is unowned and unownable, making it mathematically impossible to retrieve any tokens that are sent to it. Redeploy and try it out by sending 1000 tokens to the zero address. The `totalSupply` remains unchanged, and the balance of the zero address is visible, but those tokens are stuck there forever. * * * ## Conclusion In this lesson, you've learned to implement a simple token, which is really just a system to store the balance of each address, and a mechanism to transfer them from one wallet to another. You've also learned how to permanently destroy tokens, whether by accident, or on purpose. * * * ## Inheritance Exercises 404 The requested path could not be found ## Using useReadContract Hook [Skip to content](https://docs.base.org/learn/reading-and-displaying-data/useReadContract#vocs-content) Menu useReadContract On this page Chevron Right The `useReadContract` hook is [wagmi](https://wagmi.sh/)'s method of calling `pure` and `view` functions from your smart contracts. As with `useAccount`, `useReadContract` contains a number of helpful properties to enable you to manage displaying information to your users. * * * ## Objectives By the end of this guide you should be able to: - Implement wagmi's `useReadContract` hook to fetch data from a smart contract - Convert data fetched from a smart contract to information displayed to the user - Identify the caveats of reading data from automatically-generated getters * * * ## Contract Setup For this guide, you'll be continuing from the project you started for the [`useAccount` hook](https://docs.base.org/learn/reading-and-displaying-data/useReadContract/useAccount). You'll work with an upgrade to the contract that you may have created if you completed the [ERC 20 Tokens Exercise](https://docs.base.org/base-learn/docs/erc-20-token/erc-20-exercise). See below for an example you can use if you don't already have your own! The contract creates a very simple DAO, in which users can create issues and vote for them, against them, or abstain. Anyone can `claim` 100 tokens. This is an insecure system for demonstration purposes, since it would be trivial to claim a large number of tokens with multiple wallets, then transfer them to a single address and use that to dominate voting. But it makes it much easier to test! If you're using your own contract, please redeploy it with the following `view` functions: ```vocs_Code Copyfunction numberOfIssues() public view returns(uint) { return issues.length; } function getAllIssues() public view returns(ReturnableIssue[] memory) { ReturnableIssue[] memory allIssues = new ReturnableIssue[](issues.length); for(uint i = 0; i < issues.length; i++) { allIssues[i] = getIssue(i); } return allIssues; } ``` **You also need to make the `getIssue` function `public`. The original spec called for it to be `external`.** ### Create Demo Issues To start, you'll need to put some data into your contract so that you can read it from your frontend. Open [Sepolia BaseScan](https://sepolia.basescan.org/), find your contract, connect with your wallet, and call the `claim` function. Add the following two issues: ```vocs_Code Copy_issueDesc: We should enable light mode by default. _quorum: 2 ``` ```vocs_Code Copy_issueDesc: We should make inverted mouse controls the default selection. _quorum: 2 ``` Switch to a **different wallet address**. Claim your tokens with the new address, and add one more issue: ```vocs_Code Copy_issueDesc: Two spaces, not four, not tabs! _quorum: 2 ``` Call the `getAllIssues` function under the `Read Contract` tab to make sure all three are there. * * * ## Reading from your Smart Contract To be able to read from your deployed smart contract, you'll need two pieces of information: the address and [ABI](https://docs.soliditylang.org/en/latest/abi-spec.html). These are used as parameters in the `useReadContract` hook. If you're using [Hardhat](https://hardhat.org/), both of these can be conveniently found in a json file in the `deployments/` folder, named after your contract. For example, our contract is called `FEWeightedVoting`, so the file is `deployments/base-sepolia/FEWeightedVoting.json`. If you're using something else, it should produce a similar artifact, or separate artifacts with the [ABI](https://docs.soliditylang.org/en/latest/abi-spec.html) and address. If this is the case, make the adjustments you need when you import this data. Either way, add a folder called `deployments` and place a copy of the artifact file(s) inside. ### Using the `useReadContract` Hook Add a file for a new component called `IssueList.tsx`. You can start with: ```vocs_Code Copyimport { useReadContract } from 'wagmi'; export function IssueList() { return (

All Issues

{/* TODO: List each issue */}
); } ``` You'll need to do some prepwork to enable Typescript to more easily interpret the data returned from your contract. Add an `interface` called `Issue` that matches with the `ReturnableIssue` type: ```vocs_Code Copyinterface Issue { voters: string[]; issueDesc: string; votesFor: bigint; votesAgainst: bigint; votesAbstain: bigint; totalVotes: bigint; quorum: bigint; passed: boolean; closed: boolean; } ``` Now, import `useState` and add a state variable to hold your list of `Issue` s. ```vocs_Code Copyconst [issues, setIssues] = useState([]); ``` You'll also need to import your contract artifact: ```vocs_Code Copyimport contractData from '../deployments/FEWeightedVoting.json'; ``` Finally, the moment you've been waiting for: Time to read from your contract! Add an instance of the [`useReadContract`](https://wagmi.sh/react/hooks/useReadContract) hook. It works similarly to the [`useAccount`](https://wagmi.sh/react/hooks/useAccount) hook. Configure it with: ```vocs_Code Copyconst { data: issuesData, isError: issuesIsError, isPending: issuesIsPending, } = useReadContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'getAllIssues', }); ``` You can use `useEffect` to do something when the call completes and the data. For now, just log it to the console: ```vocs_Code CopyuseEffect(() => { if (issuesData) { const issuesList = issuesData as Issue[]; console.log('issuesList', issuesList); setIssues(issuesList); } }, [issuesData]); ``` Add in instance of your new component to `index.tsx`: ```vocs_Code Copy
``` Run your app, and you should see your list of issues fetched from the blockchain and displayed in the console! ![Issues Console Log](https://docs.base.org/images/learn/reading-and-displaying-data/issues-console-log.png) Breaking down the hook, you've: - Renamed the properties decomposed from `useReadContract` to be specific for our function. Doing so is helpful if you're going to read from more than one function in a file - Configured the hook with the address and ABI for your contract - Made use of `useEffect` to wait for the data to be returned from the blockchain, log it to the console, and set the list of `Issue` s in state. ### Displaying the Data Now that you've got the data in state, you can display it via your component. One strategy to display a list of items is to compile a `ReactNode` array in a render function. ```vocs_Code Copyfunction renderIssues() { return issues.map((issue) => (

{issue.issueDesc}

{'Voters: ' + issue.voters.toString()}

{'Votes For: ' + issue.votesFor.toString()}

{'Votes Against: ' + issue.votesAgainst.toString()}

{'Votes Abstain: ' + issue.votesAbstain.toString()}

{'Quorum: ' + issue.quorum.toString()}

{'Passed: ' + issue.passed}

{'Closed: ' + issue.closed}

)); } ``` Then, call the render function in the return for your component: ```vocs_Code Copyreturn (

All Issues

{renderIssues()}
); ``` You'll now see your list of issues rendered in the browser! Congrats, you've finally made a meaningful connection between your smart contract and your frontend! ### A Caveat with Automatic Getters Remember how the Solidity compiler creates automatic getters for all of your public state variables? This feature is very helpful, but it can create bewildering results when you use it for `struct` s that contain `mapping` s. Remember, nesting mappings **cannot** be returned outside the blockchain. The `enumerableSet` protects you from this problem, because it has private variables inside it, which prevents setting `issues` as `public`. Had we instead used a mapping, we'd lose this protection: ```vocs_Code Copy // Code for demo only struct Issue { mapping(address => bool) voters; string issueDesc; uint votesFor; uint votesAgainst; uint votesAbstain; uint totalVotes; uint quorum; bool passed; bool closed; } ``` Redeploy with the above change, and add a second `useReadContract` to fetch an individual issue using the getter: ```vocs_Code Copy// Bad code for example, do not use const { data: getOneData, isError: getOneIsError, isPending: getOneIsPending, } = useReadContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'issues', args: [1], }); useEffect(() => { if (getOneData) { console.log('getOneData', getOneData); const issueOne = getOneData as Issue; console.log('Issue One', issueOne); } }, [getOneData]); ``` Everything appears to be working just fine, but how is `issueOne.desc` undefined? You can see it right there in the log! ![Missing Data](https://docs.base.org/images/learn/reading-and-displaying-data/missing-data.png) If you look closely, you'll see that `voters` is missing from the data in the logs. What's happening is that because the nested `mapping` cannot be returned outside the blockchain, it simply isn't. TypeScript then gets the `data` and does the best it can to cast it `as` an `Issue`. Since `voters` is missing, this will fail and it instead does the JavaScript trick of simply tacking on the extra properties onto the object. Take a look at the working example above where you retrieved the list. Notice that the keys in your `Issue` type are in that log, but are missing here. The assignment has failed, and all of the `Issue` properties are `null`. * * * ## Conclusion In this guide, you've learned how to use the `useReadContract` hook to call `pure` and `view` functions from your smart contracts. You then converted this data into React state and displayed it to the user. Finally, you explored a tricky edge case in which the presence of a nested `mapping` can cause a confusing bug when using the automatically-generated getter. * * * ## Simple DAO Contract Example Use this contract if you don't have your own from the [ERC 20 Tokens Exercise](https://docs.base.org/base-learn/docs/erc-20-token/erc-20-exercise). You can also use this if you want to cheat to get that badge. Doing so would be silly though! If you use your own contract, redeploy it with the `numberOfIssues` and `getAllIssues` functions from the bottom of the contract below. We'll need this for our first pass solution for getting all the `Issues` in the contract. **You also need to make the `getIssue` function `public`. The original spec called for it to be `external`.** ```Solidity vocs_Code Copy// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; contract FEWeightedVoting is ERC20 { using EnumerableSet for EnumerableSet.AddressSet; mapping(address => bool) claimed; uint public maxSupply = 1000000; uint totalClaimed; uint constant claimAmount = 100; error TokensClaimed(); error AllTokensClaimed(); error NoTokensHeld(); error QuorumTooHigh(uint); error AlreadyVoted(); error VotingClosed(); enum Vote { AGAINST, FOR, ABSTAIN } struct Issue { EnumerableSet.AddressSet voters; string issueDesc; uint votesFor; uint votesAgainst; uint votesAbstain; uint totalVotes; uint quorum; bool passed; bool closed; } // EnumerableSets are mappings and cannot be returned outside a contract struct ReturnableIssue { address[] voters; string issueDesc; uint votesFor; uint votesAgainst; uint votesAbstain; uint totalVotes; uint quorum; bool passed; bool closed; } Issue[] issues; constructor( string memory _name, string memory _symbol ) ERC20(_name, _symbol) { // Burn Issue 0 issues.push(); } function claim() public { if (claimed[msg.sender] == true) { revert TokensClaimed(); } if (totalSupply() >= maxSupply) { revert AllTokensClaimed(); } _mint(msg.sender, claimAmount); claimed[msg.sender] = true; } function createIssue( string memory _issueDesc, uint _quorum ) public returns (uint) { if (balanceOf(msg.sender) == 0) { revert NoTokensHeld(); } if (_quorum > totalSupply()) { revert QuorumTooHigh(_quorum); } Issue storage newIssue = issues.push(); newIssue.issueDesc = _issueDesc; newIssue.quorum = _quorum; return issues.length - 1; } function getIssue(uint _id) public view returns (ReturnableIssue memory) { Issue storage issue = issues[_id]; return ReturnableIssue( issue.voters.values(), issue.issueDesc, issue.votesFor, issue.votesAgainst, issue.votesAbstain, issue.totalVotes, issue.quorum, issue.closed, issue.passed ); } function vote(uint _issueId, Vote _vote) public { Issue storage issue = issues[_issueId]; if (issue.voters.contains(msg.sender)) { revert AlreadyVoted(); } if (issue.closed) { revert VotingClosed(); } issue.voters.add(msg.sender); if (_vote == Vote.FOR) { issue.votesFor += balanceOf(msg.sender); } else if (_vote == Vote.AGAINST) { issue.votesAgainst += balanceOf(msg.sender); } else if (_vote == Vote.ABSTAIN) { issue.votesAbstain += balanceOf(msg.sender); } else { revert("Error..."); } issue.totalVotes += balanceOf(msg.sender); if (issue.totalVotes >= issue.quorum) { issue.closed = true; if (issue.votesFor > issue.votesAgainst) { issue.passed = true; } } } function numberOfIssues() public view returns(uint) { return issues.length; } function getAllIssues() public view returns(ReturnableIssue[] memory) { ReturnableIssue[] memory allIssues = new ReturnableIssue[](issues.length); for(uint i = 0; i < issues.length; i++) { allIssues[i] = getIssue(i); } return allIssues; } } ``` * * * ## Data Import Guide 404 The requested path could not be found ## Ethereum vs Base Differences [Skip to content](https://docs.base.org/chain/differences-between-ethereum-and-base#vocs-content) Menu Differences Between Ethereum and Base On this page Chevron Right Base is built on the [Bedrock](https://stack.optimism.io/docs/releases/bedrock/explainer/) release of the [OP Stack](https://stack.optimism.io/), which is designed from the ground up to be as close to Ethereum as possible. Because of this, there are very few differences when it comes to building on Base and Ethereum. However, there are still some minor discrepancies between the behavior of Base and Ethereum that you should be aware of when building apps on top of Base. These minor differences include: - [Opcodes](https://stack.optimism.io/docs/releases/bedrock/differences/#opcode-differences) - [Blocks](https://stack.optimism.io/docs/releases/bedrock/differences/#blocks) - [Network specifications](https://stack.optimism.io/docs/releases/bedrock/differences/#network-specifications) - [Transaction costs](https://stack.optimism.io/docs/releases/bedrock/differences/#transaction-costs) ## Smart Contract Testing [Skip to content](https://docs.base.org/learn/hardhat-testing/hardhat-testing-sbs#vocs-content) Menu Testing Step by Step On this page Chevron Right In this article, you'll learn how to test smart contracts with Hardhat and Typechain. * * * ## Objectives By the end of this lesson, you should be able to: - Set up TypeChain to enable testing - Write unit tests for smart contracts using Mocha, Chai, and the Hardhat Toolkit - Set up multiple signers and call smart contract functions with different signers * * * ## Overview Testing is an important aspect of software development and developing smart contracts is no different. In fact, you need to be more careful because smart contracts usually manage money and live in an adversarial environment, where anyone can see the code and interact with your smart contract. This means you can expect bad actors to try to exploit your smart contracts. ## Setup Typechain In the previous guide, you created a new project using the `init` command that by default installs `@nomicfoundation/hardhat-toolbox`. This package already contains Typechain, which is a plugin that generates static types for your smart contracts. This means you can interact with your contracts and get immediate feedback about the parameters received by a particular function and the functions of a smart contract. The best way to see its true potential is to start writing tests. After compiling the hardhat project in the previous lesson, a new folder called `typechain-types` was created, which Typechain is already installed and running. ### Writing your first unit test with Typechain Hardhat includes a sample smart contract named `Lock.sol` and a sample test inside the test folder named `Lock.ts`. In the following, you reuse this smart contract but rewrite the test using Typechain. To remove the body of the `Lock.ts` file: ```vocs_Code Copyimport { expect } from 'chai'; import { ethers } from 'hardhat'; describe('Lock', function () {}); ``` Then, import two files from `typechain-types`, `Lock`, and `Lock__Factory`. Typechain always creates two files per contract. The first one `Lock` refers to the type and functions of a particular contract. `Lock__Factory` is used to deploy the Lock contract or to create instances of a particular contract. The `Lock.sol` contract allows the creator to lock Ether until an unlock time has passed. Notice the constructor has a payable keyword: ```vocs_Code Copyconstructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } ``` This means the contract is expecting to receive an amount of ether. Next, test the following: - The unlock time value - The value locked during creation - The owner address - The withdraw function Reveal code Start with the value locked, however you must set up a `before` function, which will run before each test case. Then, include some new imports and variables: ```vocs_Code Copyimport { expect } from 'chai'; import { ethers } from 'hardhat'; // A helper utility to get the timestamp. import { time } from '@nomicfoundation/hardhat-network-helpers'; // We import this type to have our signers typed. import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; // Types from typechain import { Lock__factory, Lock } from '../typechain-types'; describe('Lock', function () { // This represents the time in the future we expect to release the funds locked. const UNLOCK_TIME = 10000; // The amount of ether we plan to lock. const VALUE_LOCKED = ethers.parseEther('0.01'); // This variable will store the last block timestamp. let lastBlockTimeStamp: number; // Typechain allow us to type an instance of the Lock contract. let lockInstance: Lock; // This is the Signer of the owner. let ownerSigner: SignerWithAddress; // A non owner signed is useful to test non owner transactions. let otherUserSigner: SignerWithAddress; before(async () => { // We get the latest block.timestamp using the latest function of time. lastBlockTimeStamp = await time.latest(); // Hardhat provide us with some sample signers that simulate Ethereum accounts. const signers = await ethers.getSigners(); // We simply assign the first signer to ownerSigner ownerSigner = signers[0]; // We assign the second signer to otherUserSigner otherUserSigner = signers[1]; // We estimate unlockTime to be the last time stamp plus UNLOCK_TIME const unlockTime = lastBlockTimeStamp + UNLOCK_TIME; // Notice how we use the Lock__factory and pass a signer. Then we deploy by passing the unlockTime and the amount of ether we will lock. lockInstance = await new Lock__factory(ownerSigner).deploy(unlockTime, { value: VALUE_LOCKED, }); }); }); ``` ### Testing `unlockTime` Next, you include test cases after the `before` function. The first test case should verify that the `unlockTime` variable is correct. Reveal code ```vocs_Code Copyit('should get the unlockTime value', async () => { // we get the value from the contract const unlockTime = await lockInstance.unlockTime(); // We assert against the expect(unlockTime).to.equal(lastBlockTimeStamp + UNLOCK_TIME); }); ``` Notice how autocomplete appears after entering `lockInstance`: ![Auto complete](https://docs.base.org/images/learn/hardhat-testing/autocomplete-unlockTime.png) You can simply run `npx hardhat test` and then get: ```vocs_Code Copy Lock ✔ should get the unlockTime value 1 passing (1s) ``` ### Testing Ether balance In order to get the balance of your `Lock` contract, you simply call `ethers.provider.getBalance`. Create a new test case: Reveal code ```vocs_Code Copyit('should have the right ether balance', async () => { // Get the Lock contract address const lockInstanceAddress = await lockInstance.getAddress(); // Get the balance using ethers.provider.getBalance const contractBalance = await ethers.provider.getBalance(lockInstanceAddress); // We assert the balance against the VALUE_LOCKED we initially sent expect(contractBalance).to.equal(VALUE_LOCKED); }); ``` Then, run `npx hardhat test` and you should get: ```vocs_Code Copy Lock ✔ should get the unlockTime value ✔ should have the right ether balance 2 passing (1s) ``` ### Testing `owner` Similar to the previous test cases, you can verify that the owner is correct. Reveal code ```vocs_Code Copyit('should have the right owner', async () => { // Notice ownerSigned has an address property expect(await lockInstance.owner()).to.equal(ownerSigner.address); }); ``` Then, run `npx hardhat test` and you should get: ```vocs_Code Copy Lock ✔ should get the unlockTime value ✔ should have the right ether balance ✔ should have the right owner 3 passing (1s) ``` ### Testing withdraw Testing withdrawal is more complex because you need to assert certain conditions, such as: - The owner cannot withdraw before the unlock time. - Only the owner can withdraw. - The withdraw function works as expected. Hardhat allow you to test reverts with a set of custom matchers. For example, the following code checks that an attempt to call the function `withdraw` reverts with a particular message: ```vocs_Code Copyit('shouldn"t allow to withdraw before unlock time', async () => { await expect(lockInstance.withdraw()).to.be.revertedWith("You can't withdraw yet"); }); ``` In addition, Hardhat also allows you to manipulate the time of the environment where the tests are executed. You can think of it as a Blockchain that is running before the tests and then the tests are executed against it. You can modify `the block.timestamp` by using the time helper: ```vocs_Code Copyit('shouldn"t allow to withdraw a non owner', async () => { const newLastBlockTimeStamp = await time.latest(); // We set the next block time stamp using this helper. // We assign a value further in the future. await time.setNextBlockTimestamp(newLastBlockTimeStamp + UNLOCK_TIME); // Then we try to withdraw using other user signer. Notice the .connect function that is useful // to create and instance but have the msg.sender as the new signer. const newInstanceUsingAnotherSigner = lockInstance.connect(otherUserSigner); // We attempt to withdraw, but since the sender is not the owner, it will revert. await expect(newInstanceUsingAnotherSigner.withdraw()).to.be.revertedWith("You aren't the owner"); }); ``` Finally, test that the owner can withdraw. You can manipulate the time similarly to the previous test case but you won't change the signer and will assert the new balances. Reveal code ```vocs_Code Copyit('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. expect(balanceBefore).to.equal(VALUE_LOCKED); const newLastBlockTimeStamp = await time.latest(); // We increase time await time.setNextBlockTimestamp(newLastBlockTimeStamp + UNLOCK_TIME); // Attempt to withdraw await lockInstance.withdraw(); // Get new balance and assert that is 0 const balanceAfter = await ethers.provider.getBalance(await lockInstance.getAddress()); expect(balanceAfter).to.equal(0); }); ``` You can then run `npx hardhat test` and you should get: ```vocs_Code Copy Lock ✔ 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 an owner 6 passing (2s) ``` ## Conclusion In this lesson, you've learned how to test smart contracts using Hardhat and Typechain. * * * ## See also [Solidity Docs](https://docs.soliditylang.org/en/v0.8.17/) \[Remix Project\]: [https://remix-project.org/](https://remix-project.org/) \[Hardhat\]: [https://hardhat.org/](https://hardhat.org/) ## Base Mappings Exercise 404 The requested path could not be found ## Decommissioning Geth Snapshots 404 The requested path could not be found ## Sub Accounts Overview [Skip to content](https://docs.base.org/identity/smart-wallet/guides/sub-accounts/overview#vocs-content) Menu Overview On this page Chevron Right ## Overview Coinbase Smart Wallet's self-custodial design requires a user passkey prompt for each wallet interaction that the user is presented with, such as a transaction or message signing. While this helps ensure the user is aware and required to approve of every interaction with their wallet, this also impacts user experience when using applications that may require frequent wallet interactions. To support using Coinbase Smart Wallet with user experiences that require more developer control over the wallet interactions, we've built Sub Accounts in conjunction with [ERC-7895](https://eip.tools/eip/7895), a new wallet RPC for creating hierarchical relationships between wallet accounts. Sub Accounts allow you to provision wallet accounts that are directly embedded in your application for your users. You can control when a Sub Account is created for your user, and can interact with them just as you would with another wallet via the wallet provider, or other popular web3 libraries like OnchainKit, wagmi, viem, etc. These Sub Accounts are linked to the end user's Coinbase Smart wallet through an onchain relationship. When combined with our [Spend Permission feature](https://docs.base.org/identity/smart-wallet/guides/spend-permissions/overview), this creates a powerful foundation for provisioning and funding app accounts, securely, while giving you, the developer, ample control over building the user experience that makes the most sense for your application. If you would like to see a live demo of Sub Accounts in action, check out our [Sub Accounts Demo](https://sub-account-demo.com/). ## What You'll Build In this guide, we'll set up a basic React app using NextJS that: - Lets users log in with their Coinbase Smart Wallet - Creates a Sub Account scoped to the app - Requests a Spend Permission for the Sub Account to have a daily allowance - Uses the Sub Account to perform popup-less transactions ### Skip ahead Note: if you want to skip ahead and just get the final code, you can find it [here](https://github.com/montycheese/sub-account-starter-template). ```vocs_Code Copygit clone https://github.com/montycheese/sub-account-starter-template.git ``` ## Guide Sections 1. [Project Setup](https://docs.base.org/identity/smart-wallet/guides/sub-accounts/setup) 2. [Creating Sub Accounts](https://docs.base.org/identity/smart-wallet/guides/sub-accounts/creating-sub-accounts) 3. [Using Sub Accounts](https://docs.base.org/identity/smart-wallet/guides/sub-accounts/using-sub-accounts) 4. [Incorporating Spend Permissions](https://docs.base.org/identity/smart-wallet/guides/sub-accounts/incorporate-spend-permissions) ## Configuring useReadContract [Skip to content](https://docs.base.org/learn/reading-and-displaying-data/configuring-useReadContract#vocs-content) Menu Configuring useReadContract On this page Chevron Right The [`useReadContract`](https://wagmi.sh/react/hooks/useReadContract) hook has a number of configurable properties that will allow you to adapt it to your needs. You can combine the functionality of TanStack queries with [`useBlockNumber`](https://wagmi.sh/react/api/hooks/useBlockNumber) to watch the blockchain for changes, although doing so will consume a number of API calls. * * * ## Objectives By the end of this guide you should be able to: - Use `useBlockNumber` and the `queryClient` to automatically fetch updates from the blockchain - Describe the costs of using the above, and methods to reduce those costs - Configure arguments to be passed with a call to a `pure` or `view` smart contract function - Call an instance of `useReadContract` on demand - Utilize `isLoading` and `isFetching` to improve user experience * * * ## Fetching Updates from the Blockchain You'll continue with the project you've been building and last updated while learning about the [`useReadContract` hook](https://docs.base.org/learn/reading-and-displaying-data/configuring-useReadContract/useReadContract). Once the excitement of your accomplishment of finally reading from your own contract subsides, try using BaseScan to add another issue, or vote on an existing issue. You'll notice that your frontend does **not** update. There are a few ways to handle this. ### The Watch Feature The easiest is to use `useBlockNumber` with the `watch` feature to automatically keep track of the block number, then use the `queryClient` to update when that changes. **Make sure** you decompose the `queryKey` from the return of `useReadContract`. ```vocs_Code Copyimport { useEffect, useState } from 'react'; import { useReadContract, useBlockNumber } from 'wagmi'; import { useQueryClient } from '@tanstack/react-query'; // Other Code export function IssueList() { // Other Code const queryClient = useQueryClient(); const { data: blockNumber } = useBlockNumber({ watch: true }); const { data: issuesData, isError: issuesIsError, isPending: issuesIsPending, queryKey: issuesQueryKey, } = useReadContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'getAllIssues', }); // Note that this is a separate `useEffect` from the one that handles the // update after the list of issues is returned useEffect(() => { queryClient.invalidateQueries({ queryKey: issuesQueryKey }); }, [blockNumber, queryClient, issuesQueryKey]); // Return code } ``` Try adding a new issue and it will automatically appear on the list, although it may take more time than you are used to. Blockchain is still slower than the web. It works! Unfortunately, you can't really stop here, unless you're working on a hackathon prototype or a very early stage demo. The catch is that `wagmi` has a default [`pollingInterval`](https://wagmi.sh/react/api/createConfig#pollinginterval) of 4 seconds, so having this `watch` causes it to call `eth_blocknumber` constantly, which then triggers an `eth_call`, both of which use api credits. If you were to take the obvious approach of adding a `useReadContract` for every function you wanted data from, and set it to `watch`, things would quickly get out of hand. A single open web page with 15 functions watched in this way will hit rate-limiting in as short as an hour. Luckily, you have options to control these calls a little better. ### Pausing On Blur One quick improvement is to simply stop watching the blockchain if the website doesn't have focus. To see this in action, add a state variable to count how many times the function has settled, and one for if the page is focused. You'll also need to set up event listeners to set the state of the latter when the page is focused or blurred. ```vocs_Code Copyconst [timesCalled, setTimesCalled] = useState(0); const [pageIsFocused, setPageIsFocused] = useState(true); useEffect(() => { const onFocus = () => setPageIsFocused(true); const onBlur = () => setPageIsFocused(false); window.addEventListener('focus', onFocus); window.addEventListener('blur', onBlur); return () => { window.removeEventListener('focus', onFocus); window.removeEventListener('blur', onBlur); }; }, []); ``` Then, update the `watch` for `useBlockNumber` so that it only does so if `pageIsFocused`. ```vocs_Code Copyconst { data: blockNumber } = useBlockNumber({ watch: pageIsFocused }); ``` Add a line to the `useEffect` for `blockNumber` and increment your counter as well. ```vocs_Code CopyuseEffect(() => { setTimesCalled((prev) => prev + 1); queryClient.invalidateQueries({ queryKey: issuesQueryKey }); }, [blockNumber, queryClient]); ``` Finally, surface your counter in the component. ```vocs_Code Copyreturn (

Number of times called

{timesCalled.toString()}

{'Has focus: ' + pageIsFocused}

All Issues

{renderIssues()}
); ``` Now, when you watch the page, the count will go up every four seconds. When you switch to another tab or window, the counter will pause until you switch back. ### Adjusting the Polling Rate You likely need to share timely updates with your users, but how timely do those updates need to be to meet the requirements of your app? If you're doing instant messaging, 4 seconds may even be too long (though any faster is running into the speed blocks are added in most L2s). A more robust DAO is going to have a voting period of at least a day or two, so those users probably don't need to see that there is a new issue within 4 seconds of it hitting the chain. Adjust your [`pollingInterval`](https://wagmi.sh/react/api/createConfig#pollinginterval) by setting it in `getDefaultConfig` in `_app.tsx`: ```vocs_Code Copyconst config = getDefaultConfig({ appName: 'RainbowKit App', projectId: 'YOUR_PROJECT_ID', chains: [baseSepolia], ssr: true, pollingInterval: 30_000, }); ``` Setting it to 30 seconds, or 30,000 milliseconds, will reduce your API calls dramatically, without negatively impacting members of the DAO. You can also set `pollingInterval` if you're using `createConfig` instead of the default. ### Updating on Demand You can use a similar system to call your update function on demand. First, add a button, a handler for that button, and a state variable for it to set: ```vocs_Code Copyconst [triggerRead, setTriggerRead] = useState(false); const handleTriggerRead = () => { setTriggerRead(true); }; ``` ```vocs_Code Copyreturn (

Number of times called

{timesCalled.toString()}

{'Has focus: ' + pageIsFocused}

All Issues

{renderIssues()}
); ``` Finally, set `watch` to equal `triggerRead`, instead of `pageIsFocused`, and reset `triggerRead` in the `useEffect`. ```vocs_Code Copyconst { data: blockNumber } = useBlockNumber({ watch: triggerRead }); // Other code... useEffect(() => { setTriggerRead(false); queryClient.invalidateQueries({ queryKey: issuesQueryKey }); }, [blockNumber, queryClient]); ``` Now, when the user clicks the button, the hook will call the read function a single time, then set `watch` back to false. * * * ## Setting UI Elements You can use the "is" return values to set UI elements depending on the status of the hook as it attempts to call a function on the blockchain. Try to modify your button to provide feedback to the user that the function has been called. ```vocs_Code Copy// Bad code example, do not use ``` The above code won't break anything, but nothing will appear to happen. This happens because `isLoading` is only `true` in circumstances where data is loading for the first time, but no data is present. You could use this to show a spinning wheel in place of the list of issues. Instead, try decomposing `isFetching` in your `useReadContract`. This property is true while data is being fetched, even if data has already been loaded once. ```vocs_Code Copy// Imperfect code example, do not use ``` You'll probably see the button flicker very quickly since the call doesn't take very long. For a production app, you'd need to add additional handling to smooth out the experience. * * * ## Passing Arguments Arguments are passed into a `useReadContract` hook by adding an array of arguments, in order, to the `args` property. Common practice is to use React state variables set by UI elements to enable the arguments to be set and modified. For example, you might create a drop-down to set `issueNumber`, then fetch that issue with: ```vocs_Code Copy// Incomplete code stub const [issueNumber, setIssueNumber] = useState(0); const { isLoading: getIssueIsLoading } = useReadContract({ address: contractData.address as `0x${string}`, abi: contractData.abi, functionName: 'getIssue', args: [issueNumber], }); ``` Depending on your design needs, you can use the techniques above to either watch constantly for updates, or fetch them on user action. * * * ## Conclusion In this guide, you've learned how to use the `watch` feature of `useBlockNumber` combined with `useEffect` and `queryClient.invalidateQueries` to enable your frontend to see updates to your smart contract. You've also learned the costs of doing so, and some strategies for mitigation. You've learned how to pass arguments to your functions. Finally, you've learned how to use the properties returned by `useReadContract` to adjust your UI to improve the experience for your users. * * * ## Farcaster to Open Frame 404 The requested path could not be found ## ERC-721 Token Guide [Skip to content](https://docs.base.org/learn/erc-721-token/erc-721-sbs#vocs-content) Menu Step by Step Guide On this page Chevron Right Punks, Apes, and birds of all kinds. You've heard about them, seen them, and may even be lucky enough to own a famous NFT. Or maybe you've just bought into a random collection and aren't sure what to do with your NFT. NFTs aren't really pictures, or anything else specific. They're a method of proving ownership of a digital asset. Anyone can right-click on a picture of a monkey and set it as their profile picture, but only the owner can use it with apps that utilize web3 ownership. The ERC-721 token standard is the underlying technical specification that not only makes digital ownership possible, it provides a standardized way for marketplaces, galleries, and other sites to know how to interact with these digital items. * * * ## Objectives By the end of this lesson you should be able to: - Analyze the anatomy of an ERC-721 token - Compare and contrast the technical specifications of ERC-20 and ERC-721 - Review the formal specification for ERC-721 - Build and deploy an ERC-721 compliant token - Use an ERC-721 token to control ownership of another data structure * * * ## Implementing the OpenZeppelin ERC-721 Token JPGs may be all the rage right now but in the future, the selfie you post on social media, a text message you send to your mother, and the +4 battleaxe you wield in your favorite MMO might all be NFTs. ### Import and Setup Start by opening the [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) ERC-721 in Github. Copy the link and use it to import the ERC-721 contract. Create your own contract, called `MyERC721`, that inherits from `ERC721Token`. Add a constructor that initializes the `_name` and `_symbol`. Reveal code ```vocs_Code Copy// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol"; contract MyERC721Token is ERC721 { constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) { } } ``` ### Minting NFTs The minting function that is provided by OpenZeppelin, `_safeMint`, is `internal`. To use it to let your customers mint NFTs, you'll need to implement a function in your contract that calls the one in the imported contract. Before you can do that, you need a way to supply the two parameters needed for `_safeMint`: - `address to` \- the owner of the new NFT - `uint256 tokenId` \- the ID number for the new NFT The owner is easy, you can simply use `msg.sender` to grant ownership to the wallet doing the minting. ID is slightly more challenging. A common practice is to simply assign the total number of NFTs, including the one being minted, as the `tokenId`. Doing so is straightforward, makes it easier to find all of the NFTs within a collection, and helps lean in to the common community perception that lower-number NFTs are better, just like other limited-edition collectibles. Obfuscating certain information, such as customer IDs, is often considered a best practice. Doing so might make it harder for an attacker who has circumvented other security functions from getting access to more data. If `134` is a valid `customer_id`, it is likely that `135` is too. The same can't be said for `bfcb51bd-c04f-42d5-8116-3def754e8c32`. This practice is not as useful on the blockchain, because all information is public. To implement ID generation, simply add a `uint` called `counter` to storage and initialize it as 1, either at declaration or in the constructor. Now, you can add a function called `redeemNFT` that calls `safeMint` using the `msg.sender` and `counter`, and then increments the `counter`: Reveal code ```vocs_Code Copyfunction redeemNFT() external { _safeMint(msg.sender, counter); counter++; } ``` Deploy and test. Be sure to: - Mint several NFTs - Transfer an NFT from one Remix account to another - Try to transfer an NFT to `0x0000000000000000000000000000000000000000` * * * ## ERC-721 URIs The ERC-721 standard includes the option to define a [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) associated with each NFT. These are intended to point to a `json` file following the _ERC721 Metadata JSON Schema_ ```vocs_Code Copy{ "title": "Asset Metadata", "type": "object", "properties": { "name": { "type": "string", "description": "Identifies the asset to which this NFT represents" }, "description": { "type": "string", "description": "Describes the asset to which this NFT represents" }, "image": { "type": "string", "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." } } } ``` Note that they don't have to. In the OpenZeppelin implementation, the function that returns the `_baseURI` is `virtual` and must be overridden by an inheriting contract. ```vocs_Code Copy// OpenZeppelin ERC-721 /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } ``` The owner of the contract can therefore choose what the value is and when, how, or if it is changeable. For example, the \[Bored Ape Yacht Club\] contract has a function allowing the owner to set or change the \_baseURI, changing where the metadata is stored, and potentially what is in it. ```vocs_Code Copy// From boredapeyachtclub.sol function setBaseURI(string memory baseURI) public onlyOwner { _setBaseURI(baseURI); } ``` The metadata for [BAYC](https://nft.coinbase.com/collection/ethereum/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d) is [stored on IPFS](https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/), but some projects even use centralized, web2 storage options! ### NFT Switcheroo [Doodles](https://nft.coinbase.com/collection/ethereum/0x8a90cab2b38dba80c64b7734e58ee1db38b8992e) is another NFT collection that [uses IPFS](https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/) to store metadata. Let's modify our contract to swap metadata back and forth from one collection to the other. Start by saving the IPFS metadata bases as constants, at the contract level. Add an enum to enable selection between these two choices, and an instance of that enum. Reveal code ```vocs_Code Copy string constant BAYC = "https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/"; string constant DOODLES = "https://ipfs.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/"; enum NFTMetadata { BAYC, DOODLES } NFTMetadata nftMetadata = NFTMetadata.BAYC; ``` Finally, add an override of `_baseURI` that returns the appropriate selection based on which collection is active, and a function to swap the URI. Reveal code ```vocs_Code Copyfunction _baseURI() internal override view returns(string memory) { if (nftMetadata == NFTMetadata.BAYC) { return BAYC; } else if (nftMetadata == NFTMetadata.DOODLES){ return DOODLES; } else { revert("Error..."); } } function switchURI() public { // TODO: Limit to contract owner nftMetadata = nftMetadata == NFTMetadata.BAYC ? NFTMetadata.DOODLES : NFTMetadata.BAYC; } ``` Deploy, mint some NFTs, and call `tokenURI` to find the information for token number 1. You should get: ```vocs_Code Copyhttps://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/1 ``` This links to the metadata json file for the first Bored Ape: ```vocs_Code Copy{ "image": "ipfs://QmPbxeGcXhYQQNgsC6a36dDyYUcHgMLnGKnF8pVFmGsvqi", "attributes": [\ {\ "trait_type": "Mouth",\ "value": "Grin"\ },\ {\ "trait_type": "Clothes",\ "value": "Vietnam Jacket"\ },\ {\ "trait_type": "Background",\ "value": "Orange"\ },\ {\ "trait_type": "Eyes",\ "value": "Blue Beams"\ },\ {\ "trait_type": "Fur",\ "value": "Robot"\ }\ ] } ``` IPFS links don't work natively directly in the browser, but you can see the image here: [https://ipfs.io/ipfs/QmPbxeGcXhYQQNgsC6a36dDyYUcHgMLnGKnF8pVFmGsvqi/](https://ipfs.io/ipfs/QmPbxeGcXhYQQNgsC6a36dDyYUcHgMLnGKnF8pVFmGsvqi/) Now, call your `switchURI` function and then call `tokenURI` again for token 1. Now, you'll get a new link for metadata: ```vocs_Code Copyhttps://ipfs.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/1 ``` Which contains the metadata for Doodle 1 instead of BAYC 1: ```vocs_Code Copy{ "image": "ipfs://QmTDxnzcvj2p3xBrKcGv1wxoyhAn2yzCQnZZ9LmFjReuH9", "name": "Doodle #1", "description": "A community-driven collectibles project featuring art by Burnt Toast. Doodles come in a joyful range of colors, traits and sizes with a collection size of 10,000. Each Doodle allows its owner to vote for experiences and activations paid for by the Doodles Community Treasury. Burnt Toast is the working alias for Scott Martin, a Canadian\u2013based illustrator, designer, animator and muralist.", "attributes": [\ {\ "trait_type": "face",\ "value": "holographic beard"\ },\ {\ "trait_type": "hair",\ "value": "white bucket cap"\ },\ {\ "trait_type": "body",\ "value": "purple sweater with satchel"\ },\ {\ "trait_type": "background",\ "value": "grey"\ },\ {\ "trait_type": "head",\ "value": "gradient 2"\ }\ ] } ``` Your robot ape is now a person with a rainbow beard! [https://ipfs.io/ipfs/QmTDxnzcvj2p3xBrKcGv1wxoyhAn2yzCQnZZ9LmFjReuH9](https://ipfs.io/ipfs/QmTDxnzcvj2p3xBrKcGv1wxoyhAn2yzCQnZZ9LmFjReuH9) * * * ## Conclusion In this lesson, you've learned how to use OpenZeppelin's ERC-721 implementation to create your own NFT contract. You've also learned how NFT metadata is stored, and that it is not necessarily immutable. * * * ## ERC-20 Token Standard [Skip to content](https://docs.base.org/learn/erc-20-token/erc-20-standard#vocs-content) Menu ERC-20 Standard On this page Chevron Right In this article, we'll delve into the structure and specifications of ERC-20 tokens, uncovering the key elements that contribute to their widespread adoption and diverse use cases. * * * ## Objectives: By the end of this lesson you should be able to: - Analyze the anatomy of an ERC-20 token - Review the formal specification for ERC-20 * * * ## Introduction The emergence of the ERC-20 token standard marked a significant milestone in the evolution of the Ethereum ecosystem, providing a unified and adaptable framework for creating and managing fungible tokens. As the backbone for a vast array of applications in decentralized finance and beyond, ERC-20 tokens facilitate seamless collaboration and interoperability within the Ethereum ecosystem. Their adaptable nature and standardized structure have made them the go-to choice for developers and users alike, laying the groundwork for continued innovation and growth in the Ethereum space. The ERC-20 token standard has not only streamlined the creation of new tokens but also bolstered the overall user experience by establishing a consistent set of rules and functions. As a result, it has garnered widespread adoption and solidified its position as the de facto standard for fungible tokens on Ethereum, driving the expansion of the decentralized economy and fostering the development of novel applications and services. ![The Evolution of the Ethereum Ecosystem](https://docs.base.org/images/learn/erc-20/evolution-eth-erc20.png) * * * ## ERC-20 Specification EIP-20 (Ethereum Improvement Proposal 20) is the formal specification for ERC-20, defining the requirements to create compliant tokens on the Ethereum blockchain. EIP-20 prescribes the mandatory functions, optional functions, and events a token must implement to achieve ERC-20 compliance. Adherence to EIP-20 allows developers to create tokens compatible with existing Ethereum applications and services, streamlining integration. * * * ## Anatomy of an ERC-20 Token An ERC-20 token consists of a smart contract that implements the standardized interface, which comprises a set of six mandatory functions: - **totalSupply():** Returns the total supply of the token. - **balanceOf(address):** Provides the balance of tokens held by a specific address. - **transfer(address, uint256):** Transfers a specified amount of tokens from the sender's address to the specified recipient's address. - **transferFrom(address, address, uint256):** Enables a third party to transfer tokens on behalf of the token owner, given that the owner has approved the transaction. - **approve(address, uint256):** Allows the token owner to grant permission to a third party to spend a specified amount of tokens on their behalf. - **allowance(address, address):** Returns the amount of tokens the token owner has allowed a third party to spend on their behalf. Additionally, ERC-20 tokens can include optional functions that provide descriptive information about the token: - **name():** Returns the name of the token, for example, "Uniswap." - **symbol():** Provides the token's symbol, like "UNI." - **decimals():** Indicates the number of decimal places the token can be divided into, typically 18 for most tokens. * * * ## Benefits of ERC-20 Standardization The standardization of ERC-20 tokens provides several benefits for both developers and users. For developers, it simplifies the process of creating new tokens by providing a consistent set of functions and conventions. This reduces the likelihood of errors and ensures a smooth integration with existing applications and services in the Ethereum ecosystem. ![ERC-20 Standardization Developer's Perspective](https://docs.base.org/images/learn/erc-20/erc20-dev-perspective.png) For users, the standardized interface makes it easier to interact with a wide variety of tokens, regardless of their specific purpose or implementation. This means that users can effortlessly check their token balance, transfer tokens, or approve transactions using the same set of functions, whether they are interacting with a governance token like UNI or a stablecoin like USDC. ![ERC-20 Standardization User's Perspective](https://docs.base.org/images/learn/erc-20/erc20-user-perspective.png) * * * ## Applications ERC-20 tokens find wide-ranging applications in various categories, each with its unique purpose and functionality: - **Utility tokens:** These tokens can be used to access specific services or features within a platform. Examples include Filecoin (FIL) for decentralized storage, Basic Attention Token (BAT) for digital advertising, and Decentraland's MANA for purchasing virtual land and assets. - **Governance tokens:** These tokens grant voting rights and influence over the development of a project, allowing holders to participate in decision-making processes. Examples include Uniswap (UNI), Aave (AAVE), and Compound (COMP). - **Stablecoins:** These tokens maintain a relatively stable value pegged to a reserve of assets or fiat currency, providing a less volatile option for transactions and trading. Examples include USD Coin (USDC), Tether (USDT), and MakerDAO's DAI. - **Liquidity tokens:** Liquidity providers on DeFi platforms often receive ERC-20 tokens as a representation of their share in a liquidity pool. These tokens can be staked or traded, and they enable users to earn rewards for providing liquidity. Examples include Uniswap LP tokens and Curve LP tokens. - **Rewards tokens:** Some platforms issue ERC-20 tokens as incentives for users to participate in their ecosystem, such as staking, lending, or providing liquidity. These tokens can be earned as passive income or used to access additional platform features. Examples include Synthetix (SNX) and SushiSwap (SUSHI). Each of these use cases demonstrates the adaptability of ERC-20 tokens to serve different needs within the blockchain ecosystem. * * * ## Conclusion By providing a consistent framework for fungible tokens and adhering to the formal EIP-20 specification, ERC-20 has enabled the development of countless projects and applications that have revolutionized how value is exchanged and managed on Ethereum. Analyzing the anatomy of an ERC-20 token and reviewing its formal specification reveal the versatility and importance of this token standard. * * * ## See Also - [Introduction to Ethereum Improvement Proposals (EIPs)](https://ethereum.org/en/eips/) - [EIP-20: ERC-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20) - [ERC-20 Token Standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) ## Introduction to Remix [Skip to content](https://docs.base.org/learn/introduction-to-solidity/introduction-to-remix#vocs-content) Menu Remix Guide On this page Chevron Right In this lesson, you'll be introduced to an online Solidity IDE called Remix. You'll tour the workspace and explore a sample smart contract. * * * ## Objectives By the end of this lesson you should be able to: - List the features, pros, and cons of using Remix as an IDE - Deploy and test the Storage.sol demo contract in Remix * * * ## Remix Window Overview Begin by opening a browser window and navigating to [remix.ethereum.org](https://remix.ethereum.org/). Open the project you created and cleaned up at the end of the last reading, and open `1_Storage.sol`. The editor should be organized in a way that is familiar to you. It is divided into three areas: - Editor Pane - Terminal/Output - Left Panel ### Editor Pane The editor pane loads with the Remix home screen, which contains news, helpful links, and warnings about common scams. Double-click on `1_Storage.sol` to open it in the editor. You can close the home tab if you'd like. ![Remix Editor](https://docs.base.org/images/learn/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 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. ### Terminal/Output Below the editor pane, you'll find the terminal: ![Remix Terminal](https://docs.base.org/images/learn/introduction-to-solidity/remix-terminal.png) You'll primarily use this panel to observe transaction logs from your smart contracts. It's also one way to access Remix's very powerful debugging tools. ### Left Panel As with many other editors, the left panel in Remix has a number of vertical tabs that allow you to switch between different tools and functions. You can explore the files in your current workspace, create and switch between workspaces, search your code, and access a number of plugins. * * * ## Plugins Most of the features in Remix are plugins and the ones you'll use the most are active by default. You can view and manage plugins by clicking the plug button in the lower-left corner, right above the settings gear. You can turn them off and on by clicking activate/deactivate, and some, such as the _Debug_ plugin will be automatically activated through other parts of the editor. ### Solidity Compiler The first default plugin (after the search function) is the _Solidity Compiler_. Be sure to check the `Auto compile` option. Smart contracts are almost always very small files, so this shouldn't ever cause a performance problem while editing code. The `Compile and Run script` button in this plugin is a little misleading. This is **not** how you will usually run your contract through testing. You can click the `I` button for more information on this feature. Finally, if you have errors in your contracts, the complete text for each error will appear at the bottom of the pane. Try it out by introducing some typos to `1_Storage.sol`. ### Deploy & Run Transactions The _Deploy & Run Transactions_ plugin is what you'll use to deploy your contracts and then interact with them. At the top are controls to select which virtual machine to use, mock user wallets with test Ether, and a drop-down menu to select the contract you wish to deploy and test. Fix any errors you introduced to `1_Storage.sol` and then click the orange `Deploy` button. You'll see your contract appear below as _STORAGE AT
_. There are two common gotchas that can be very confusing when deploying contracts in Remix. 1. Each time you hit the Deploy button, a new copy of your contract is deployed but the previous deployments remain. Unless you are comparing or debugging between different versions of a contract, or deploying multiple contracts at once, you should click the `Trash` button to erase old deployments before deploying again. 2. If your code will not compile, **clicking the deploy button will not generate an error!** Instead, the last compiled version will be deployed. Visually check and confirm that there are no errors indicated by a number in a red circle on top of the Compiler plugin. * * * ## Conclusion Remix is a robust editor with many features and one or two gotchas. It is an excellent tool to use at the beginning of your journey because you can jump right in and start writing code for smart contracts. ## See also [Remix](https://remix.ethereum.org/) ## ERC-721 Token Standard [Skip to content](https://docs.base.org/learn/erc-721-token/erc-721-standard#vocs-content) Menu Standard Overview On this page Chevron Right In this article, we'll delve into the ERC-721 token standard, exploring its technical specs, applications, and how it differs from the ERC-20 standard. * * * ## Objectives: By the end of this lesson you should be able to: - Analyze the anatomy of an ERC-721 token - Compare and contrast the technical specifications of ERC-20 and ERC-721 - Review the formal specification for ERC-721 * * * ## Introduction The development of the Ethereum ecosystem has been marked by key milestones, two of which are the inception of the ERC-20 and ERC-721 token standards. While ERC-20 provided a foundational framework for fungible tokens, ERC-721 established a flexible and adaptable infrastructure for non-fungible tokens (NFTs). The ERC-721 token standard is pivotal in the Ethereum ecosystem for creating and managing unique digital assets. With its consistent rules and functions, it has greatly enhanced the user experience, solidifying its position as the go-to standard for non-fungible tokens. ERC-721 has been instrumental in expanding the digital collectibles market and spurring the development of new applications and services. ![The Evolution of the Ethereum Ecosystem](https://docs.base.org/images/learn/erc-721/evolution-eth-erc721.png) * * * ## ERC-721 Specification EIP-721 (Ethereum Improvement Proposal 721) is the formal specification for ERC-721, defining the requirements for creating compliant non-fungible tokens on Ethereum. EIP-721 prescribes mandatory functions and events that a token must implement to achieve ERC-721 compliance. Adherence to EIP-721 ensures compatibility of unique tokens with existing Ethereum applications and services, simplifying integration. * * * ## Anatomy of an ERC-721 Token An ERC-721 token comprises a smart contract implementing the standardized interface, which includes six primary functions: - **balanceOf(address)** Returns the number of tokens held by a specific address. - **ownerOf(uint256):** Provides the owner of a specified token. - **safeTransferFrom(address, address, uint256):** Transfers a specific token's ownership from one address to another. - **transferFrom(address, address, uint256):** Allows a third party to transfer tokens on the token owner's behalf, given the owner's approval. - **approve(address, uint256):** Enables the token owner to permit a third party to transfer a specific token on their behalf. - **getApproved(uint256):** Shows the approved address for a specific token. These functions ensure each ERC-721 token has a unique identifier and can be owned and transferred individually. * * * ## ERC-721 Vs ERC-20 The ERC-721 and ERC-20 token standards share a common goal of providing a set of standards for tokens on the Ethereum network but diverge in terms of functionality and use cases. ERC-20 tokens are fungible, meaning each token is identical to every other token; they are interchangeable like currency. On the other hand, ERC-721 tokens are non-fungible, meaning each token is unique and not interchangeable with any other token. This uniqueness is made possible through the ownerOf() and getApproved() functions, which provide information about the ownership of each unique token. The ERC-20 standard has primarily found use in creating cryptocurrencies for apps, governance tokens, utility tokens, stablecoins, and more. The ERC-721 standard, conversely, has been adopted largely for creating unique digital assets like collectibles, digital art, and tokenized virtual real estate, among other applications. * * * ## Benefits of ERC-721 Standardization Standardizing non-fungible tokens via the ERC-721 token standard presents substantial benefits to developers and users in the Ethereum ecosystem. Developers have access to a standardized set of functions, leading to less code ambiguity, fewer errors, and a streamlined development process. This uniformity also ensures smooth integration with existing apps and platforms on Ethereum. For users, the ERC-721 standard offers an intuitive, consistent interface for interacting with a wide array of unique tokens. Regardless of the token's specific use or design, users can reliably check their ownership of tokens, transfer tokens to other addresses, and approve transactions. This consistency enhances usability across the Ethereum platform, from digital art marketplaces to tokenized real estate and gaming applications. ![The Benefits of ERC-721 Standardization](https://docs.base.org/images/learn/erc-721/erc-721-standard.png) * * * ## Applications ERC-721 tokens find wide-ranging applications in various categories: - **Digital Art:** Artists can create unique digital artworks as ERC-721 tokens. These tokens can be sold or traded on platforms like OpenSea, Rarible, and Coinbase NFT. Examples include work by the digital artist Beeple. - **Gaming:** Game assets such as characters, items, and land can be tokenized as ERC-721 tokens, providing players with true ownership of their in-game assets. Examples include Axie Infinity and Decentraland. - **Collectibles:** ERC-721 tokens can represent unique collectible items in a digital space. Examples include NBA Top Shot moments and CryptoPunks. - **Virtual Real Estate:** Virtual real estate can be tokenized as ERC-721 tokens, providing proof of ownership and facilitating trade on virtual platforms. Examples include parcels of land in Cryptovoxels and Decentraland. * * * ## Conclusion ERC-721, with its consistent framework for non-fungible tokens, has revolutionized the unique digital asset space on Ethereum. This standard, when contrasted with ERC-20, highlights Ethereum's capacity for both fungible and unique asset types. Adhering to the EIP-721 specification, ERC-721 tokens have significantly influenced the Ethereum-based digital economy. From digital art to gaming, these tokens underscore their importance and role as catalysts in the burgeoning NFT revolution. * * * ## See Also - [EIP-721: ERC-721 Token Standard](https://eips.ethereum.org/EIPS/eip-721) - [ERC-721 Token Standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-721/) ## AI-Powered IDEs Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/guides/using-ai-powered-ides#vocs-content) Menu Use AI-powered IDEs On this page Chevron Right ## Use AI-powered IDEs You can also directly download the [context](https://github.com/fakepixels/md-generator/blob/master/combined-ock-docs-0.35.8.mdx) and import it into AI-powered IDE such as Cursor or Replit. In addition, you can import a `.cursorrules` file in the root of your project via [Cursor Directory](https://cursor.directory/onchainkit). Cursor also has an array of resources [here](https://cursor.directory/learn) on how to use AI-powered IDEs. ![Cursor](https://docs.base.org/images/onchainkit/cursor-dir.gif) ## AI Tooling ### Replit [Replit](https://replit.com/) is a cloud-based coding platform that streamlines the process of setting up, building, sharing, and deploying projects. It allows developers to code in a Google Docs-like environment, and pre-built templates provide a great starting point for building a website, app, or game. Its new AI Agent can assist with the code development process and work with several files at once, making the programming process feel like a one-on-one conversation. ### Cursor [Cursor](https://cursor.com/) is an AI-powered code editor that makes the programming experience feel like magic. Built as a fork of VS Code, it boasts powerful features like AI code completion, natural language editing, and codebase understanding. Cursor Pro is free for the first two weeks after signup, and offers more powerful models. ### Using OnchainKit with CDP SDK You can use OnchainKit with [CDP SDK](https://docs.cdp.coinbase.com/get-started/docs/overview) to access additional capabilities such as [AgentKit](https://docs.cdp.coinbase.com/agentkit/docs/welcome). ## VRF Tags Tutorial 404 The requested path could not be found ## Tokens Overview 404 The requested path could not be found ## Introduction to Interfaces 404 The requested path could not be found ## New Keyword Guide 404 The requested path could not be found ## Using Basenames in Onchain Apps [Skip to content](https://docs.base.org/builderkits/onchainkit/guides/use-basename-in-onchain-app#vocs-content) Menu Use Basenames On this page Chevron Right Basenames are an essential onchain building block that empowers builders to establish their identity on Base by registering human-readable names for their wallet addresses. They operate entirely onchain, utilizing the same technology as ENS names, and are deployed on Base. You can integrate [Basenames](https://www.base.org/names) into your app with these few steps. ### New to OnchainKit? Follow the [Getting Started](https://docs.base.org/builderkits/onchainkit/getting-started) guide to install the package. ### Already using OnchainKit? Update to the latest version and choose from the following steps: a React component approach, a React hook, or a pure TypeScript utility function. ## React components with `` and `` Use the [``](https://docs.base.org/builderkits/onchainkit/identity/avatar) and [``](https://docs.base.org/builderkits/onchainkit/identity/name) components to display Basenames associated with Ethereum addresses. The `chain` prop is optional and setting to Base, it's what makes the components switch from ENS to Basenames. ```vocs_Code Copyimport { Avatar, Name } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; const address = '0x02feeb0AdE57b6adEEdE5A4EEea6Cf8c21BeB6B1'; // omitted component code for brevity ``` ## React hooks with `useAvatar` and `useName` Use the [`useAvatar`](https://docs.base.org/builderkits/onchainkit/identity/use-avatar) and [`useName`](https://docs.base.org/builderkits/onchainkit/identity/use-name) hooks to get Basenames associated with Ethereum addresses. The hooks are incredibly useful for building custom components while leveraging OnchainKit for efficient data fetching. codereturn value code ```vocs_Code Copyimport { useAvatar, useName } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; const address = '0x02feeb0AdE57b6adEEdE5A4EEea6Cf8c21BeB6B1'; const basename = 'zizzamia.base.eth'; const { data: avatar, isLoading: avatarIsLoading } = await useAvatar({ ensName: basename, chain: base }); const { data: name, isLoading: nameIsLoading } = await useName({ address, chain: base }); ``` ## Typescript utility with `getAvatar` and `getName` Use the [`getAvatar`](https://docs.base.org/builderkits/onchainkit/identity/get-avatar) and [`getName`](https://docs.base.org/builderkits/onchainkit/identity/get-name) functions to get Basenames associated with Ethereum addresses. Being pure functions, it seamlessly integrates into any TypeScript project, including Vue, Angular, Svelte, or Node.js. codereturn value code ```vocs_Code Copyimport { getAvatar, getName } from '@coinbase/onchainkit/identity'; import { base } from 'viem/chains'; const address = '0x02feeb0AdE57b6adEEdE5A4EEea6Cf8c21BeB6B1'; const basename = 'zizzamia.base.eth'; const avatar = await getAvatar({ ensName: basename, chain: base }); const name = await getName({ address, chain: base }); ``` We use cookies and similar technologies on our websites to enhance and tailor your experience, analyze our traffic, and for security and marketing. You can choose not to allow some type of cookies by clicking Manage Settings. For more information see our [Cookie Policy](https://docs.base.org/cookie-policy). Manage settings Accept all ## Testing Smart Contracts [Skip to content](https://docs.base.org/cookbook/smart-contract-development/foundry/testing-smart-contracts#vocs-content) Menu Testing Smart Contracts On this page Chevron Right In this tutorial, you'll learn how to test your smart contracts using [Foundry](https://book.getfoundry.sh/), the toolchain for smart contract development. ## Objectives By the end of this tutorial, you should be able to: - Understand the increased importance of testing in smart contract development - Write and execute tests written in Solidity using the Forge Standard Library with Foundry - Use the `cheatcodes` that Foundry provides to test your smart contracts ## Overview Testing is a crucial aspect of smart contract development, ensuring the reliability and security of your code. Because it is impossible to patch a smart contract after deployment, you must thoroughly and completely test your code. Foundry provides a robust testing framework that allows developers to create comprehensive test suites for their projects using Solidity. ## My First Test with Foundry Consider the default test that the `forge init hello_foundry_in_base` command provides in the seed Foundry project. ```vocs_Code Copy// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; import "forge-std/Test.sol"; import "../src/Counter.sol"; contract CounterTest is Test { Counter public counter; function setUp() public { counter = new Counter(); counter.setNumber(0); } function testIncrement() public { counter.increment(); assertEq(counter.number(), 1); } function testSetNumber(uint256 x) public { counter.setNumber(x); assertEq(counter.number(), x); } } ``` Take note of the following: - Foundry test files are named following the pattern: `.t.sol` - Smart contract test files are named following the pattern: `Test` - All tests inherit from `forge-std/Test.sol`. - All tests contain a public function called `setUp`, which is executed before each test. This is similar to the `beforeEach` hook in the Mocha/Typescript world. - Test cases start with the `test` keyword, for instance `testIncrement`. - Test cases functions are public. For more information about writing tests in Foundry, you can follow the official guide for [Writing tests](https://book.getfoundry.sh/forge/writing-tests) In order to run the test in Foundry, run: ```vocs_Code Copy$ forge test ``` You should see in the terminal: ```vocs_Code CopyRunning 2 tests for test/Counter.t.sol:CounterTest [PASS] testIncrement() (gas: 28334) [PASS] testSetNumber(uint256) (runs: 256, μ: 27565, ~: 28343) Test result: ok. 2 passed; 0 failed; finished in 13.57ms ``` ## Using Cheatcodes Foundry includes a set of [cheatcodes](https://book.getfoundry.sh/forge/cheatcodes), which are special instructions that are accessible using the `vm` instance in your tests. Cheatcodes allow you to perform various tasks, including: - Manipulate the state of the blockchain - Test reverts - Test events - Change block number - Change identity - And more! To start, use a cheatcode to modify the `msg.sender` of your tests, and add some console logs via importing the `forge-std/console.sol` contract. The `Counter` contract should look as follows: ```vocs_Code Copy// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; import "forge-std/console.sol"; contract Counter { uint256 public number; function setNumber(uint256 newNumber) public { console.log("The sender is %s", msg.sender); number = newNumber; } function increment() public { console.log("The sender is %s", msg.sender); number++; } } ``` If you run the tests using `forge test`, you will see the following: ```vocs_Code CopyRunning 2 tests for test/Counter.t.sol:CounterTest [PASS] testIncrement() (gas: 31531) [PASS] testSetNumber(uint256) (runs: 256, μ: 30684, ~: 31540) Test result: ok. 2 passed; 0 failed; finished in 19.64ms ``` It seems the logs are not being shown. The reason is because the `forge test` command includes a flag that enable you to include more details of the logs emitted during the execution of the tests. You can control that by including different levels of the verbose flag -- `-vv` up to `-vvvvv`. For more details about the level of verbosity you can refer to the [Logs and Traces](https://book.getfoundry.sh/forge/tests?highlight=vvv#logs-and-traces) section of the Foundry documentation. Run the `foundry test -vv`. You should see: ```vocs_Code CopyRunning 2 tests for test/Counter.t.sol:CounterTest [PASS] testIncrement() (gas: 31531) Logs: The sender is 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 The sender is 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 [PASS] testSetNumber(uint256) (runs: 256, μ: 30607, ~: 31540) Logs: The sender is 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 Test result: ok. 2 passed; 0 failed; finished in 17.89ms ``` Now, modify the test file using `prank` cheatcode, which allow you to modify the `msg.sender` of the next transaction. You will also use the `addr` cheatcode, which allow you to generate an address using any private key, which can simply be a hex number. Include some `console.log` statements to understand better the execution flow. The code should look like: ```vocs_Code Copy// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; import "forge-std/Test.sol"; import "../src/Counter.sol"; contract CounterTest is Test { Counter public counter; function setUp() public { counter = new Counter(); console.log("Calling on Setup"); counter.setNumber(0); } function testIncrement() public { console.log("Calling on testIncrement"); vm.prank(vm.addr(0x01)); counter.increment(); assertEq(counter.number(), 1); } function testSetNumber(uint256 x) public { console.log("Calling on testSetNumber"); vm.prank(vm.addr(0x02)); counter.setNumber(x); assertEq(counter.number(), x); } } ``` Then if you run the `forge test -vv` command, you should see: ```vocs_Code CopyRunning 2 tests for test/Counter.t.sol:CounterTest [PASS] testIncrement() (gas: 35500) Logs: Calling on Setup The sender is 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 Calling on testIncrement The sender is 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf [PASS] testSetNumber(uint256) (runs: 256, μ: 34961, ~: 35506) Logs: Calling on Setup The sender is 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 Test result: ok. 2 passed; 0 failed; finished in 48.75ms ``` Notice how you call the cheatcode `vm.prank` before the call to the `counter.increment()` and `counter.setNumber(x)` functions. This allows you to specify a particular address to become the `msg.sender` in the contract. Since the `vm.prank` accepts an address, you simply generate an address using the cheatcode `vm.addr`, where you pass a simple hexadecimal number, which is a valid private key. ## Conclusion Congratulations! You've successfully completed your first step in your journey of testing smart contracts using Foundry. As you move forward, keep exploring its rich features and functionalities. The ability to write comprehensive tests and leverage cheatcodes ensures the reliability and security of your smart contracts. Happy coding and testing with Foundry! ## OnchainKit Installation Guide [Skip to content](https://docs.base.org/builderkits/onchainkit/installation/astro#vocs-content) Menu Astro On this page Chevron Right Install and configure OnchainKit with Astro. If you are integrating OnchainKit into an existing project, skip to the [OnchainKit installation](https://docs.base.org/builderkits/onchainkit/installation/astro#install-onchainkit). ## Install Astro Create a new Astro project by using the Astro CLI. More information about Astro can be found [here](https://docs.astro.build/en/install-and-setup/#start-a-new-project). npmyarnpnpm Terminal npm ```vocs_Code Copynpm create astro@latest ``` ## Install React Astro does not come with React by default, so if you are not already using React in your application, you will need to install it. Terminal Terminal ```vocs_Code Copynpx astro add react ``` ## Install OnchainKit Add OnchainKit to your project by installing the `@coinbase/onchainkit` package. npmyarnpnpmbun Terminal npm ```vocs_Code Copynpm install @coinbase/onchainkit ``` ## Get A Client API Key Get your [Client API Key](https://portal.cdp.coinbase.com/projects/api-keys/client-key) from Coinbase Developer Platform. ![OnchainKit copy Client API Key](https://docs.base.org/images/onchainkit/copy-api-key-guide.png) Create a `.env` file in your project's root directory. ![OnchainKit define Client API Key](https://docs.base.org/images/onchainkit/getting-started-create-env-file.png) Add your Client API Key to the `.env` file: File .env ```vocs_Code CopyPUBLIC_ONCHAINKIT_API_KEY=YOUR_CLIENT_API_KEY ``` ## Add Providers Create a `providers.tsx` file. Add `OnchainKitProvider` with your desired config. Under the hood, OnchainKit will create our recommended Wagmi and QueryClient providers. If you wish to customize these providers, check out [Custom\\ Supplemental Providers](https://docs.base.org/builderkits/onchainkit/config/supplemental-providers). File providers.tsx ```vocs_Code Copy'use client'; import type { ReactNode } from 'react'; import { OnchainKitProvider } from '@coinbase/onchainkit'; import { base } from 'wagmi/chains'; // add baseSepolia for testing export function Providers(props: { children: ReactNode }) { return ( {props.children} ); } ``` ## Wrap your OnchainKit components with `` After configuring the providers in step 4, you will need to wrap your OnchainKit components with the `` component. There are two options for this: 1. Create a component, eg. `` that contains all OnchainKit components. 2. Wrap every OnchainKit component individually. ReactIslandOnchainKit Wrappers ReactIsland ```vocs_Code Copyimport { AppProviders } from '../AppProviders'; export default function ReactIsland() { return ( ); } ``` The advantage of ReactIsland is that you will only have a single provider at any time. The drawback is that your OnchainKit components will all need to live in the same Island. The advantage of individual wrappers is that you can use OnchainKit components anywhere in your app. The drawback is that you will have multiple providers if you use more than one OnchainKit component. ## Add OnchainKit Components to your App You can add OnchainKit components to your app by using the component(s) you created above into your `.astro` files. For example, if you created a ReactIsland, you can add it to your `src/pages/index.astro` file: File src/pages/index.astro ```vocs_Code Copy--- import Layout from '../layouts/Layout.astro'; import ReactIsland from '../components/ReactIsland'; ---
... ...
``` Don't forget to add the `client:only="react"` directive to your OnchainKit component, as this is required for Astro to render React components. ## Import OnchainKit Styles OnchainKit components come with pre-configured styles. To include these styles in your project, add the following import statement at the top of the `Layout.astro` file: ```vocs_Code Copyimport '@coinbase/onchainkit/styles.css'; ``` This ensures that the OnchainKit styles are loaded and applied to your entire application. - For Tailwind CSS users, check out our [Tailwind Integration Guide](https://docs.base.org/builderkits/onchainkit/guides/tailwind). - Update the appearance of components by using our built-in themes or crafting your own custom theme. Explore the possibilities in our [Theming Guide](https://docs.base.org/builderkits/onchainkit/guides/themes). # Start building! Explore our ready-to-use onchain components: - [**`Identity`**](https://docs.base.org/builderkits/onchainkit/identity/identity)\- Show [Basenames](https://docs.base.org/builderkits/onchainkit/identity/identity), [avatars](https://docs.base.org/builderkits/onchainkit/identity/avatar), [badges](https://docs.base.org/builderkits/onchainkit/identity/badge), and [addresses](https://docs.base.org/builderkits/onchainkit/identity/address). - [**`Wallet`**](https://docs.base.org/builderkits/onchainkit/wallet/wallet)\- Create or connect wallets with [Connect Wallet](https://docs.base.org/builderkits/onchainkit/wallet/wallet). - [**`Transaction`**](https://docs.base.org/builderkits/onchainkit/transaction/transaction)\- Handle [transactions](https://docs.base.org/builderkits/onchainkit/transaction/transaction) using EOAs or Smart Wallets. - [**`Checkout`**](https://docs.base.org/builderkits/onchainkit/checkout/checkout)\- Integrate USDC [checkout](https://docs.base.org/builderkits/onchainkit/checkout/checkout) flows with ease. - [**`Fund`**](https://docs.base.org/builderkits/onchainkit/fund/fund-button)\- Create a [funding](https://docs.base.org/builderkits/onchainkit/fund/fund-button) flow to onboard users. - [**`Tokens`**](https://docs.base.org/builderkits/onchainkit/token/token-chip)\- Search and display [tokens](https://docs.base.org/builderkits/onchainkit/token/token-chip) with various components. - [**`Swap`**](https://docs.base.org/builderkits/onchainkit/swap/swap)\- Enable [token swaps](https://docs.base.org/builderkits/onchainkit/swap/swap) in your app. - [**`Mint`**](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card)- [View](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) and [Mint](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) NFTs in your app. ## Base Test Networks Guide 404 The requested path could not be found ## OnchainKit Getting Started [Skip to content](https://docs.base.org/builderkits/onchainkit/getting-started#vocs-content) Menu Getting Started On this page Chevron Right OnchainKit is your go-to SDK for building beautiful onchain applications. Ship in minutes, not weeks. Anyone can build an onchain app in 15 minutes with OnchainKit. No blockchain experience required. ## Why OnchainKit? OnchainKit streamlines app development by providing a comprehensive toolkit that combines powerful onchain features with developer-friendly design: - **Ergonomic design:** Full-stack tools that make complex onchain interactions intuitive - **Battle-tested patterns:** Industry best practices packaged into ready-to-use solutions - **Purpose-built components:** Pre-built modules for common onchain workflows - **Framework agnostic:** Compatible with any React-supporting framework - **Supercharged by Base:** Deep integration with Base's protocol features and ecosystem ## Automatic Installation ![OnchainKit Template](https://docs.base.org/images/onchainkit/quickstart.png) We recommend starting a new OnchainKit app using `create onchain`, which sets up everything automatically for you. To create a project, run: Terminal Terminal ```vocs_Code Copynpm create onchain@latest ``` After the prompts, `create onchain` will create a folder with your project name and install the required dependencies. You can also checkout our pre-built templates: - [Onchain Commerce](https://onchain-commerce-template.vercel.app/) - [NFT minting](https://ock-mint.vercel.app/) - [Funding flow](https://github.com/fakepixels/fund-component) - [Social profile](https://github.com/fakepixels/ock-identity) ## Manual Installation Add OnchainKit to your existing project manually. [Next.js\\ \\ Next.js](https://docs.base.org/builderkits/onchainkit/installation/nextjs) [Vite\\ \\ Vite](https://docs.base.org/builderkits/onchainkit/installation/vite) [Remix\\ \\ Remix](https://docs.base.org/builderkits/onchainkit/installation/remix) [Astro\\ \\ Astro](https://docs.base.org/builderkits/onchainkit/installation/astro) # Start building! Explore our ready-to-use onchain components: - [**`Identity`**](https://docs.base.org/builderkits/onchainkit/identity/identity)\- Show [Basenames](https://docs.base.org/builderkits/onchainkit/identity/identity), [avatars](https://docs.base.org/builderkits/onchainkit/identity/avatar), [badges](https://docs.base.org/builderkits/onchainkit/identity/badge), and [addresses](https://docs.base.org/builderkits/onchainkit/identity/address). - [**`Wallet`**](https://docs.base.org/builderkits/onchainkit/wallet/wallet)\- Create or connect wallets with [Connect Wallet](https://docs.base.org/builderkits/onchainkit/wallet/wallet). - [**`Transaction`**](https://docs.base.org/builderkits/onchainkit/transaction/transaction)\- Handle [transactions](https://docs.base.org/builderkits/onchainkit/transaction/transaction) using EOAs or Smart Wallets. - [**`Checkout`**](https://docs.base.org/builderkits/onchainkit/checkout/checkout)\- Integrate USDC [checkout](https://docs.base.org/builderkits/onchainkit/checkout/checkout) flows with ease. - [**`Fund`**](https://docs.base.org/builderkits/onchainkit/fund/fund-button)\- Create a [funding](https://docs.base.org/builderkits/onchainkit/fund/fund-button) flow to onboard users. - [**`Tokens`**](https://docs.base.org/builderkits/onchainkit/token/token-chip)\- Search and display [tokens](https://docs.base.org/builderkits/onchainkit/token/token-chip) with various components. - [**`Swap`**](https://docs.base.org/builderkits/onchainkit/swap/swap)\- Enable [token swaps](https://docs.base.org/builderkits/onchainkit/swap/swap) in your app. - [**`Mint`**](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card)- [View](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) and [Mint](https://docs.base.org/builderkits/onchainkit/mint/nft-mint-card) NFTs in your app.