# Attribution Tags Source: https://docs.celo.org/build-on-celo/attribution-tags Attribution tags let you mark transactions as coming from your app — so on-chain activity can be credited back to you for programs like [Proof of Ship](/build-on-celo/fund-your-project), MiniPay leaderboards, and hackathon tracking. Celo's implementation follows [ERC-8021](https://oxlib.sh/ercs/erc8021/Attribution). ## How It Works ERC-8021 appends a small suffix to a transaction's calldata. The suffix is invisible to the contract being called — the EVM discards trailing bytes — so adding it never changes execution semantics. It just makes the transaction identifiable as having come through your app to anyone reading calldata off-chain. Tagging a transaction is open to everyone. Whether a code gets *credited* on a leaderboard or rewards program is resolved at the registry/indexer layer, not at the tagging step. ## Install ```bash theme={null} npm install @celo/attribution-tags viem ``` `viem` is an optional peer dependency — only required if you call `verifyTx` to decode a tag from a transaction hash. The SDK exports four functions: ```ts theme={null} toDataSuffix(code | [codes]) // → encoded suffix (Hex) codeFromHostname(hostname) // → "celo_" + 12 hex chars, derived from a hostname fromDataSuffix(data) // → { codes, schemaId } | null verifyTx({ client, hash }) // → { codes, schemaId } | null ``` ## Quickstart If you've been issued a code (`celo_xxxxxxxx`) — for example through Proof of Ship onboarding or a hackathon registration — pass it directly: ```ts theme={null} import { toDataSuffix } from "@celo/attribution-tags"; const tag = toDataSuffix("celo_b7k3p9da"); // issued code, or any custom string await wallet.sendTransaction({ to, value, data: tag }); ``` Any string matching `[a-z0-9_]` (1–32 characters) is a valid code. If a program assigned you a code, it must be present in the suffix — leaderboards and reward programs only credit the assigned code, not one you derive yourself with `codeFromHostname`. You can include both: ```ts theme={null} const tag = toDataSuffix(["your_own_code", "celo_assigned1234"]); ``` ## Tagging a Contract Call Concatenate your encoded calldata with the suffix: ```ts theme={null} import { encodeFunctionData, concat } from "viem"; const callData = encodeFunctionData({ abi, functionName: "transfer", args }); const taggedData = concat([callData, tag]); await wallet.sendTransaction({ to: tokenAddress, data: taggedData }); ``` With [wagmi](/tooling/dev-environments/thirdweb/overview), pass `dataSuffix` directly and wagmi handles the concatenation: ```ts theme={null} const { writeContract } = useWriteContract(); writeContract({ address, abi, functionName: "transfer", args, dataSuffix: tag, }); ``` ## The Layering Rule ERC-8021 suffixes can carry multiple codes, but **each code should only be added by the entity it represents**: * **Your app code** — added by your app, as shown above. * **A platform code** like `minipay` — added by the platform itself (the wallet or cohort layer), never by your app. Adding a platform code from your own app would falsely claim every transaction ran inside that platform, polluting attribution data. ## Verifying It Worked ```ts theme={null} import { verifyTx } from "@celo/attribution-tags"; import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; const client = createPublicClient({ chain: celo, transport: http() }); const result = await verifyTx({ client, hash: "0x..." }); console.log(result); // { codes: ["celo_b7k3p9da"], schemaId: 0 } ``` `verifyTx` returns `null` (never throws) if no tag is found. For offline decoding without an RPC call, use `fromDataSuffix(rawCalldata)` instead. Some smart-account / bundler flows (ERC-4337 bundlers, meta-tx relayers) rewrite calldata and can strip trailing bytes. Verify on-chain with `verifyTx` before relying on tags in production. ## Resources | Resource | Link | | ------------------ | ------------------------------------------------------------------------------------ | | Source & full docs | [github.com/celo-org/attribution-tags](https://github.com/celo-org/attribution-tags) | | npm package | [@celo/attribution-tags](https://www.npmjs.com/package/@celo/attribution-tags) | | ERC-8021 standard | [oxlib.sh/ercs/erc8021](https://oxlib.sh/ercs/erc8021/Attribution) | ## Related * [x402: Agent Payments](/build-on-celo/build-with-ai/x402) * [Fund your Project](/build-on-celo/fund-your-project) — Proof of Ship progress tracking uses attribution tags * [Launch Checklist](/build-on-celo/launch-checklist) # MiniPay Code Library Source: https://docs.celo.org/build-on-celo/build-on-minipay/code-library Snippets of code that can be used to implement flows inside MiniPay Make sure you are using Typescript v5 or above and Viem v2 or above. ## Get the connected user's address without any Library ```js theme={null} // The code must run in a browser environment and not in node environment if (window && window.ethereum) { // User has a injected wallet if (window.ethereum.isMiniPay) { // User is using Minipay // Requesting account addresses let accounts = await window.ethereum.request({ method: "eth_requestAccounts", params: [], }); // Injected wallets inject all available addresses, // to comply with API Minipay injects one address but in the form of array console.log(accounts[0]); } // User is not using MiniPay } // User does not have a injected wallet ``` To use the code snippets below, install the following packages: ```bash yarn theme={null} yarn add @celo/abis @celo/identity viem@2 ``` ```bash npm theme={null} npm install @celo/abis @celo/identity viem@2 ``` ## Check USDm Balance of an address ```js theme={null} import { getContract, formatEther, createPublicClient, http } from "viem"; import { celo } from "viem/chains"; import { stableTokenABI } from "@celo/abis"; // USDm address on Celo mainnet const STABLE_TOKEN_ADDRESS = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; async function checkUSDmBalance(publicClient, address) { const StableTokenContract = getContract({ abi: stableTokenABI, address: STABLE_TOKEN_ADDRESS, client: publicClient, }); const balanceInBigNumber = await StableTokenContract.read.balanceOf([ address, ]); const balanceInWei = balanceInBigNumber.toString(); const balanceInEthers = formatEther(balanceInWei); return balanceInEthers; } const publicClient = createPublicClient({ chain: celo, transport: http(), }); // Mainnet const balance = await checkUSDmBalance(publicClient, address); // In Ether unit ``` ## Check If a transaction succeeded ```js theme={null} import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; async function checkIfTransactionSucceeded(publicClient, transactionHash) { const receipt = await publicClient.getTransactionReceipt({ hash: transactionHash, }); return receipt.status === "success"; } const publicClient = createPublicClient({ chain: celo, transport: http(), }); // Mainnet const transactionStatus = await checkIfTransactionSucceeded( publicClient, transactionHash ); ``` ## Estimate Gas for a transaction (in Celo) ```js theme={null} import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; async function estimateGas(publicClient, transaction, feeCurrency = "") { return await publicClient.estimateGas({ ...transaction, feeCurrency: feeCurrency ? feeCurrency : "", }); } const publicClient = createPublicClient({ chain: celo, transport: http(), }); const gasLimit = await estimateGas(publicClient, { account: "0x8eb02597d85abc268bc4769e06a0d4cc603ab05f", to: "0x4f93fa058b03953c851efaa2e4fc5c34afdfab84", value: "0x1", data: "0x", }); ``` ## Estimate Gas for a transaction (in USDm) ```js theme={null} import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; async function estimateGas(publicClient, transaction, feeCurrency = "") { return await publicClient.estimateGas({ ...transaction, feeCurrency: feeCurrency ? feeCurrency : "", }); } const publicClient = createPublicClient({ chain: celo, transport: http(), }); const STABLE_TOKEN_ADDRESS = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; const gasLimit = await estimateGas( publicClient, { account: "0x8eb02597d85abc268bc4769e06a0d4cc603ab05f", to: "0x4f93fa058b03953c851efaa2e4fc5c34afdfab84", value: "0x1", data: "0x", }, STABLE_TOKEN_ADDRESS ); ``` ## Estimate Gas Price for a transaction (in Celo) ```js theme={null} import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; async function estimateGasPrice(publicClient, feeCurrency = "") { return await publicClient.request({ method: "eth_gasPrice", params: feeCurrency ? [feeCurrency] : [], }); } const publicClient = createPublicClient({ chain: celo, transport: http(), }); const gasPrice = await estimateGasPrice(publicClient); ``` ## Estimate Gas Price for a transaction (in USDm) ```js theme={null} import { createPublicClient, http } from "viem"; import { celo } from "viem/chains"; async function estimateGasPrice(publicClient, feeCurrency = "") { return await publicClient.request({ method: "eth_gasPrice", params: feeCurrency ? [feeCurrency] : [], }); } const publicClient = createPublicClient({ chain: celo, transport: http(), }); const STABLE_TOKEN_ADDRESS = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; const gasPrice = await estimateGasPrice(publicClient, STABLE_TOKEN_ADDRESS); ``` ## Calculate USDm to be spent for transaction fees ```js theme={null} import { createPublicClient, http, formatEther, fromHex } from "viem"; import { celo } from "viem/chains"; const publicClient = createPublicClient({ chain: celo, transport: http(), }); const STABLE_TOKEN_ADDRESS = "0x765DE816845861e75A25fCA122bb6898B8B1282a"; // `estimateGas` implemented above const gasLimit = await estimateGas( publicClient, { account: "0x8eb02597d85abc268bc4769e06a0d4cc603ab05f", to: "0x4f93fa058b03953c851efaa2e4fc5c34afdfab84", value: "0x1", data: "0x", }, STABLE_TOKEN_ADDRESS ); // `estimateGasPrice` implemented above const gasPrice = await estimateGasPrice(publicClient, STABLE_TOKEN_ADDRESS); // Convert hex gas price to BigInt and calculate fees const gasPriceBigInt = fromHex(gasPrice, "bigint"); const transactionFeesInUSDm = formatEther(gasLimit * gasPriceBigInt); ``` ## Resolve Minipay phone numbers to Addresses Install the `@celo/identity` package: ```bash theme={null} npm install @celo/identity ``` ### Step 1: Set up your issuer The issuer is the account registering attestations. When a user requests attestation registration, verify they own the identifier (e.g., SMS verification for phone numbers). ```js theme={null} import { createWalletClient, http } from "viem"; import { celoSepolia } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; // The issuer is the account that is registering the attestation const ISSUER_PRIVATE_KEY = "YOUR_ISSUER_PRIVATE_KEY"; // Create Celo Sepolia viem client with the issuer private key const viemClient = createWalletClient({ account: privateKeyToAccount(ISSUER_PRIVATE_KEY), transport: http(), chain: celoSepolia, }); // Information provided by user, issuer should confirm they own the identifier const userPlaintextIdentifier = "+12345678910"; const userAccountAddress = "0x000000000000000000000000000000000000user"; // Time at which issuer verified the user owns their identifier const attestationVerifiedTime = Date.now(); ``` ### Step 2: Check and top up ODIS quota ```js theme={null} import { OdisUtils } from "@celo/identity"; import { AuthSigner } from "@celo/identity/lib/odis/query"; import { OdisContextName } from "@celo/identity/lib/odis/query"; // authSigner provides information needed to authenticate with ODIS const authSigner: AuthSigner = { authenticationMethod: OdisUtils.Query.AuthenticationMethod.WALLET_KEY, sign191: ({ message, account }) => viemClient.signMessage({ message, account }), }; // serviceContext provides the ODIS endpoint and public key const serviceContext = OdisUtils.Query.getServiceContext( OdisContextName.CELO_SEPOLIA ); // Check existing quota on issuer account const issuerAddress = viemClient.account.address; const { remainingQuota } = await OdisUtils.Quota.getPnpQuotaStatus( issuerAddress, authSigner, serviceContext ); // If needed, approve and send payment to OdisPayments to get quota for ODIS // Note: This example uses viem. For contract interactions, use getContract from viem if (remainingQuota < 1) { // Use viem's getContract to interact with stable token and ODIS payments contracts // Implementation depends on your specific contract setup } ``` ### Step 3: Derive the obfuscated identifier Get the obfuscated identifier from the plaintext identifier by querying ODIS: ```js theme={null} const { obfuscatedIdentifier } = await OdisUtils.Identifier.getObfuscatedIdentifier( userPlaintextIdentifier, OdisUtils.Identifier.IdentifierPrefix.PHONE_NUMBER, issuerAddress, authSigner, serviceContext ); ``` ### Step 4: Look up account addresses Query the FederatedAttestations contract to look up account addresses owned by an identifier: ```js theme={null} const attestations = await federatedAttestationsContract.lookupAttestations( obfuscatedIdentifier, [issuerAddress] // Trusted issuers ); console.log(attestations.accounts); ``` ## Request an ERC20 token transfer USDT and USDC on Celo use **6 decimals**, not 18. Pass `tokenDecimals` as `6` when transferring either token. Using `18` will send 1,000,000,000,000× more than intended. USDm uses 18 decimals. ```js theme={null} import { createWalletClient, createPublicClient, custom, http, encodeFunctionData, parseUnits } from "viem"; import { celo, celoSepolia } from "viem/chains"; import { stableTokenABI } from "@celo/abis"; const walletClient = createWalletClient({ chain: celoSepolia, // For testnet // chain: celo, // For mainnet transport: custom(window.ethereum!), }); const publicClient = createPublicClient({ chain: celoSepolia, // For testnet // chain: celo, // For mainnet transport: http(), }); async function requestTransfer(tokenAddress, transferValue, tokenDecimals, receiverAddress) { const hash = await walletClient.sendTransaction({ to: tokenAddress, // Mainnet token addresses and their decimals: // USDm: '0x765DE816845861e75A25fCA122bb6898B8B1282a' (18 decimals) // USDC: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C' (6 decimals) // USDT: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e' (6 decimals) data: encodeFunctionData({ abi: stableTokenABI, // Token ABI from @celo/abis functionName: "transfer", args: [ receiverAddress, // USDm uses 18 decimals; USDC and USDT use 6 decimals parseUnits(`${Number(transferValue)}`, tokenDecimals), ], }), }); const transaction = await publicClient.waitForTransactionReceipt({ hash, // Transaction hash that can be used to search transaction on the explorer. }); if (transaction.status === "success") { // Do something after transaction is successful. } else { // Do something after transaction has failed. } } ``` # MiniPay Deeplinks Source: https://docs.celo.org/build-on-celo/build-on-minipay/deeplinks Deeplinks let your Mini App interact with MiniPay's native features without manual navigation. They use the host `link.minipay.xyz` and can be triggered from external apps or from within MiniPay itself. The user must have MiniPay installed and be logged in. Users without the app are shown an install prompt. ## Available deeplinks | Action | Deeplink | Description | | ------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Add cash | `https://link.minipay.xyz/add_cash` | Launches the add cash flow. Optionally scope the tokens with `?tokens=USDM,USDT` (supported: `USDM`, `USDT`, `USDC`). | | Open Mini App | `https://link.minipay.xyz/browse?url=xxx` | Opens an approved Mini App at the given URL. | | Discover tab | `https://link.minipay.xyz/discover` | Opens the Mini Apps discovery page. | | Transaction receipt | `https://link.minipay.xyz/receipt?tx=xxx` | Shows the receipt for a transaction hash. Append `&celebrate` for a celebration animation. | | QR code | `https://link.minipay.xyz/qr` | Shows the user's QR code. | | Invite friends | `https://link.minipay.xyz/invite_friends` | Opens the invite friends screen. | | Pockets | `https://link.minipay.xyz/balance` | Opens the balance (pockets) view. | ## Trigger the add cash screen To trigger or redirect a MiniPay user to the add cash screen inside MiniPay, use the following link: [https://link.minipay.xyz/add\_cash](https://link.minipay.xyz/add_cash) To pre-select which tokens the user can add, pass the `tokens` query parameter, for example [https://link.minipay.xyz/add\_cash?tokens=USDM,USDT](https://link.minipay.xyz/add_cash?tokens=USDM,USDT). add cash minipay deeplink # Build on MiniPay Source: https://docs.celo.org/build-on-celo/build-on-minipay/overview ## Create a Mini App for the MiniPay Stablecoin Wallet *** [MiniPay](https://www.opera.com/products/minipay) is a stablecoin wallet with a built-in Mini App discovery page, integrated directly within the popular Opera Mini Android browser and also available as a standalone application on Android and iOS. Since launching, MiniPay is the fastest growing non-custodial wallet in the Global South with more than 10M+ activations. Install the new MiniPay standalone app for [Android](https://play.google.com/store/apps/details?id=com.opera.minipay) or [iOS](https://apps.apple.com/de/app/minipay-easy-global-wallet/id6504087257?l=en-GB) now! 🎉 📥 ## Why Build on MiniPay? * **Useful Applications:** MiniPay focuses on practical uses in everyday life, especially in emerging markets, where most of their users are located. * **Integrated App Discovery:** MiniPay includes a built-in app discovery page, allowing users to interact with selected Mini Apps directly within their wallet, without needing to switch to other platforms. * **Access to Opera’s Large User Base** Developers can tap into MiniPay’s growing user base (10 Million activated addresses) and Opera browser distribution. ## Key Features of MiniPay * **Phone Number mapping:** Uses mobile phone numbers as wallet addresses. * **Fast, Low-Cost Transactions:** Offers fast P2P stablecoin transactions with sub-cent fees. * **Lightweight Design:** At just 2MB, users can use the wallet with limited data. ## Opportunities for MiniPay Builders * **Raising Funding?** Reach out to [team@verda.ventures](mailto:team@verda.ventures) with a deck and/or product demo. * **Still Building?** Register your project for [Build With Celo: Proof-of-Ship](https://www.celopg.eco/programs/proof-of-ship-s1) for monthly rewards. # Ngrok Setup Source: https://docs.celo.org/build-on-celo/build-on-minipay/prerequisites/ngrok-setup When builidng dApps for MiniPay locally, you want to test the dApp inside MiniPay wallet on your phone. But since the dApp is running locally, you cannot simply visit localhost on your phone to open the dApp on your phone. To solve this, we use `ngrok`. `ngrok` allows us to share our localhost by providing us with a temporary web url that can be used on any device! ## Installing Ngrok 1. Visit [ngrok.com](https://ngrok.com) ngrok.com 2. Sign up sign up ngrok 3. The dashboard will have instructions based on your OS on how to install and use ngrok! dashboard 4. Once installed you can use the following command to share your localhost port. ```bash theme={null} > ngrok http [PORT] ``` The output looks something like this. ngrok output You can use the highlighted url to launch the localhost dApp on the [MiniPay's Site Tester](/build-on-celo/build-on-minipay/quickstart#test-your-mini-app-inside-minipay). # Get Started Building on MiniPay Source: https://docs.celo.org/build-on-celo/build-on-minipay/quickstart A step-by-step guide to setting up, building, and testing your MiniPay Mini App. *** ## 1. Installing MiniPay MiniPay is designed for mainstream adoption, making digital payments simple and easy to use. #### Key Features: * **Currency Display**: Balances appear in your local currency. * **Stablecoin Support**: Only stablecoins (USDm, USDC, and USDT) are supported. * **Simple Swaps**: The pocket swap feature allows for easy swaps between stablecoins by dragging one pocket into another. MiniPay is only available on Celo and Celo Sepolia Testnet. Other blockchain networks are not supported. #### How to Access MiniPay: * [**Opera Mini Browser**](https://www.opera.com/pl/products/minipay) (Android) * [**Standalone App Android**](https://play.google.com/store/apps/details?id=com.opera.minipay) * [**Standalone App iOS**](https://apps.apple.com/de/app/minipay-easy-global-wallet/id6504087257?l=en-GB) #### Set Up MiniPay: * **Install the MiniPay Standalone App:** Download for [Android](https://play.google.com/store/apps/details?id=com.opera.minipay) and [iOS](https://apps.apple.com/de/app/minipay-easy-global-wallet/id6504087257?l=en-GB) * **Create an Account:** Sign up using your Google account and phone number. ## 2. Build Your MiniPay Mini App #### For creating a new app: * Use the [Celo Composer MiniPay Template](https://github.com/celo-org/minipay-template) to start building. ```bash theme={null} npx @celo/celo-composer@latest create -t minipay ``` * Follow the [Quickstart Guide](/build-on-celo/quickstart) for a step-by-step tutorial. #### For integrating an existing app: * Follow the [Helpful Tips Guide](#helpful-tips-to-make-your-mini-app-minipay-compatible) to ensure your app is MiniPay compatible. ## 3. Get Testnet Tokens Request CELO testnet tokens from the Celo [faucet](https://faucet.celo.org/celo-sepolia/) to test your Mini App. After you got the CELO tokens, you can exchange them for stablecoins like USDm, USDT and USDC in the [mento app](https://app.mento.org/). ## 4. Test your Mini App inside MiniPay You cannot test MiniPay using the Android Studio Emulator. Use an Android or iOS mobile device. ### Enable Developer Mode: 1. Open the MiniPay app on your phone and navigate to settings. Open MiniPay dApp store 2. In the **About** section, tap the **Version** number repeatedly until the confirmation message appears. Open MiniPay dApp test page 3. Return to **Settings**, then select **Developer Settings**. MiniPay dApp testing 4. Enable **Developer Mode** and toggle **Use Testnet** to connect to Sepolia L2 testnet. MiniPay dApp testing ### Load Your Mini App: 1. In **Developer Settings,** tap **Load Test Page.** 2. Enter your **Mini App URL.** * If testing a local deployment, use [ngrok](#testing-local-development-with-minipay) to expose your localhost. MiniPay dApp testing 6. Click **Go** to launch and test your Mini App. MiniPay dApp testing *** ## Helpful Tips to Make Your Mini App MiniPay Compatible MiniPay uses Custom [Fee Abstraction](/build-on-celo/fee-abstraction/overview) based transactions. We recommend using viem or wagmi as they provide native support for fee currency. #### 1. Using Viem ```js theme={null} import { createWalletClient, custom } from "viem"; import { celo, celoSepolia } from "viem/chains"; const client = createWalletClient({ chain: celo, // chain: celoSepolia, // For Celo Sepolia Testnet transport: custom(window.ethereum), }); const [address] = await client.getAddresses(); ``` #### 2. Using Wagmi These snippets use **wagmi v2** (the current major version). In v2, connectors are functions (e.g. `injected()`) rather than the classes used in v1 (`new InjectedConnector()`), `WagmiConfig` is now `WagmiProvider`, and the config is built with `createConfig`. First, create your wagmi config and wrap your app in `WagmiProvider` (wagmi v2 also requires a TanStack Query provider): ```tsx theme={null} // providers.tsx "use client"; import { WagmiProvider, createConfig, http } from "wagmi"; import { celo } from "wagmi/chains"; import { injected } from "wagmi/connectors"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; export const config = createConfig({ chains: [celo], connectors: [injected({ target: "metaMask" })], transports: { [celo.id]: http(), }, }); const queryClient = new QueryClient(); export function Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` Then auto-connect on load using the connector from your config: ```tsx theme={null} import { useEffect } from "react"; import { useConnect } from "wagmi"; const { connect, connectors } = useConnect(); useEffect(() => { // `connectors[0]` is the `injected()` connector registered in `createConfig` connect({ connector: connectors[0] }); }, [connect, connectors]); ``` This sets up the `injected` connector in `createConfig` and then uses the `connect` method from the `useConnect` hook. The `useEffect` ensures that the connection is established when the page loads. In the Viem example, we're creating a wallet client that specifies the chain and a custom transport using `window.ethereum`. The `getAddresses` method then retrieves the connected addresses. ### Important Notes Ensure the "Connect Wallet" button is hidden when your DApp is loaded inside the MiniPay app, as the wallet connection is implicit. *Code Example to hide Connect Wallet button if the user is using MiniPay wallet* ```tsx theme={null} import { useEffect, useState } from "react"; import { useConnect } from "wagmi"; import { injected } from "wagmi/connectors"; export default function Header() { // State variable that determines whether to hide the button or not. const [hideConnectBtn, setHideConnectBtn] = useState(false); const { connect } = useConnect(); useEffect(() => { if (window.ethereum && window.ethereum.isMiniPay) { // User is using MiniPay so hide connect wallet button. setHideConnectBtn(true); connect({ connector: injected({ target: "metaMask" }) }); } }, [connect]); return (
{/* Conditional rendering of Connect Wallet button */} {!hideConnectBtn && ( )}
); } ``` * Always verify the existence of `window.provider` before initializing your web3 library to ensure seamless compatibility with the MiniPay wallet. * When using `ngrok`, remember that the tunneling URL is temporary. You'll get a new URL every time you restart ngrok. * Be cautious about exposing sensitive information or functionality when using public tunneling services like ngrok. Always use them in a controlled environment. * MiniPay manages gas fees for you. You can set the `feeCurrency` property when running `eth_sendTransaction`, but MiniPay may ignore it and pay gas in the stablecoin the user holds the most of. Supported gas tokens include `USDT`, `USDC`, and `USDm` (as well as other Mento stablecoins). * Use viem or wagmi to build and send transactions, as they provide native support for Celo's fee-currency transactions. ## Testing Local Development with MiniPay If you're developing your MiniApp locally (e.g., on `localhost:3000`), use `ngrok` to tunnel traffic over HTTP, for real-time testing. #### Set Up ngrok * **Install ngrok:** If you haven't already, install ngrok. You can find instructions on their [official website](https://ngrok.com/download). * **Start Your Local Server:** Ensure your local development server is running. For instance, if you're using Next.js, you might run `npm run dev` to start your server at `localhost:3000`. * **Tunnel Traffic with ngrok:** In your terminal, run the following command to start an ngrok tunnel: ```bash theme={null} ngrok http 3000 ``` This will provide you with a public URL that tunnels to your localhost. For a more in depth guide, check out the official [ngrok setup](/build-on-celo/build-on-minipay/prerequisites/ngrok-setup). * **Test in MiniPay:** Copy the provided ngrok URL and use it inside the MiniPay app to test your DApp. # ERC-8004: Agent Trust Protocol Source: https://docs.celo.org/build-on-celo/build-with-ai/8004 [ERC-8004](https://github.com/erc-8004/erc-8004-contracts/tree/master) is an Ethereum standard that establishes trust infrastructure for autonomous AI agents. It enables agents to discover, identify, and evaluate other agents across organizational boundaries without pre-existing trust relationships. ## Key Features * **Identity Registry**: Portable agent identifiers based on ERC-721 NFTs * **Reputation Registry**: Standardized feedback and rating system for agents * **Validation Registry**: Independent verification hooks where third-party validators can attest to agent outputs—supporting stake-secured re-execution, zkML proofs, or TEE attestations for high-stakes operations * **Cross-Chain Support**: Works on any EVM-compatible chain including Celo ## Why ERC-8004? When AI agents interact across organizational boundaries, three critical questions arise: * **Discovery**: How do agents find each other? The Identity Registry provides searchable metadata—agents query the registry to discover other agents by capabilities, endpoints, or domain. * **Identity**: How do agents verify who they're dealing with? Each agent is an ERC-721 NFT with a cryptographically linked wallet, enabling verification that you're communicating with the authentic agent owner. * **Trust**: How do agents evaluate reliability? The Reputation Registry stores feedback from every interaction, creating a portable track record that travels with the agent across platforms. ### Protocol stack ERC-8004 fits into the broader agent infrastructure stack: ```mermaid theme={null} flowchart TB subgraph APP["APPLICATION LAYER"] A1["Agent Apps, Platforms, Marketplaces"] end subgraph TRUST["TRUST LAYER"] T1["ERC-8004"] T2["Identity, Reputation, Validation"] end subgraph PAY["PAYMENT LAYER"] P1["x402"] P2["HTTP 402 + Stablecoin Payments"] end subgraph COMM["COMMUNICATION LAYER"] C1["A2A (Google) + MCP (Anthropic)"] end APP --> TRUST TRUST --> PAY PAY --> COMM ``` ## The Three Registries ### 1. Identity Registry Makes agents discoverable via portable NFT identifiers. **Key capabilities:** * Every agent **identity** is represented as an ERC-721 NFT—the agent itself runs off-chain, but its on-chain identity is an NFT that's browsable in wallets, transferable between owners, and queryable by smart contracts * `agentURI` points to registration file with endpoints * Supports multiple endpoint types (A2A, MCP, wallet, ENS, DIDs) * Domain verification for endpoint ownership **Agent registration file structure:** ```json theme={null} { "type": "Agent", "name": "My AI Agent", "description": "Description of capabilities", "image": "ipfs://...", "endpoints": [ { "type": "a2a", "url": "https://example.com/.well-known/agent.json" }, { "type": "mcp", "url": "https://example.com/mcp" }, { "type": "wallet", "address": "0x...", "chainId": 42220 } ], "supportedTrust": ["reputation", "validation", "tee"] } ``` ### 2. Reputation Registry Stores feedback and attestations about agent performance. Feedback is submitted on-chain by any address that has interacted with the agent—this includes users who hired the agent, other agents that collaborated with it, or monitoring services that track uptime and responsiveness. The contract prevents agents from rating themselves (owner and operator addresses are blocked from submitting feedback on their own agent). **Common feedback tags:** | Tag | Measures | Example | | -------------- | ---------------------- | ---------- | | `starred` | Quality rating (0-100) | 87/100 | | `uptime` | Endpoint uptime % | 99.77% | | `successRate` | Task success rate % | 89% | | `responseTime` | Response time (ms) | 560ms | | `reachable` | Endpoint reachable | true/false | **Key functions:** * `giveFeedback()` - Submit feedback with score and tags * `revokeFeedback()` - Remove previous feedback * `readAllFeedback()` - Get all feedback for an agent * `getSummary()` - Get aggregated reputation summary ### 3. Validation Registry Independent verification hooks for high-stakes operations. **Supported validation approaches:** | Model | Mechanism | Best For | | -------------------- | ------------------------------------------ | --------------------------------- | | **Reputation-based** | Client feedback with scores | Low-stake, frequent interactions | | **Crypto-economic** | Stake-secured validation with slashing | Medium-stake financial operations | | **zkML** | Zero-knowledge proofs of correct execution | Privacy-preserving verification | | **TEE Attestation** | Hardware-isolated execution proofs | High-assurance requirements | Check out the [repository](https://github.com/erc-8004/erc-8004-contracts/tree/master) of the ERC-8004 protocol for agent discovery and trust through reputation and validation. ## Contract Deployments ### Celo Mainnet | Contract | Address | | ------------------- | ------------------------------------------ | | Identity Registry | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 | | Reputation Registry | 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 | ### Celo Sepolia (Testnet) | Contract | Address | | ------------------- | ------------------------------------------ | | Identity Registry | 0x8004A818BFB912233c491871b3d84c89A494BD9e | | Reputation Registry | 0x8004B663056A597Dffe9eCcC1965A193B7388713 | ## Quick Start ### Install SDK The ERC-8004 SDK provides TypeScript/JavaScript and Python interfaces to interact with the on-chain registries. Install the SDK for your preferred language: ```bash theme={null} # JavaScript/TypeScript npm install @chaoschain/sdk # Python pip install chaoschain-sdk ``` ### Register an Agent Registration mints a new ERC-721 NFT that represents your agent's on-chain identity. You'll need to: 1. Create a registration file (JSON) describing your agent's name, capabilities, and endpoints 2. Upload it to IPFS or host it at a public URL 3. Call the registry to mint your agent NFT with the URI pointing to that file ```javascript theme={null} import { IdentityRegistry } from '@chaoschain/sdk'; const registry = new IdentityRegistry(provider); // Upload registration file to IPFS first const agentURI = 'ipfs://QmYourRegistrationFile'; // Register and get agent ID const tx = await registry.register(agentURI); const agentId = tx.events.Transfer.returnValues.tokenId; console.log('Agent registered with ID:', agentId); ``` ### Give Feedback After interacting with an agent, submit feedback to the Reputation Registry. Each feedback entry includes a score, category tag (like "starred" for quality or "uptime" for availability), and an optional link to detailed off-chain feedback data: ```javascript theme={null} import { ReputationRegistry } from '@chaoschain/sdk'; const reputation = new ReputationRegistry(provider); await reputation.giveFeedback( agentId, 85, // score (0-100) 0, // decimals 'starred', // tag1: category '', // tag2: optional 'https://agent.example.com', // endpoint used 'ipfs://QmDetailedFeedback', // detailed feedback URI feedbackHash // keccak256 of feedback content ); ``` ### Query Agent Reputation Before delegating tasks to an agent, check its reputation. You can retrieve all individual feedback entries or get aggregated statistics: ```javascript theme={null} // Get all feedback const feedback = await reputation.readAllFeedback(agentId); // Get summary statistics const summary = await reputation.getSummary(agentId); console.log('Average rating:', summary.averageScore); console.log('Total reviews:', summary.totalFeedback); ``` ## Use Cases ### DeFi Trading Agents This diagram shows a typical agent-to-agent interaction flow. A portfolio management agent needs to execute a trade, so it: 1. Queries the Identity Registry to discover available strategy agents 2. Filters candidates using the Reputation Registry (checking track records, success rates) 3. Selects an agent and requests a trade 4. Pays for the service via x402 (HTTP-native payments) 5. After the trade completes, submits feedback to build the strategy agent's reputation ```mermaid theme={null} sequenceDiagram participant PA as Portfolio Agent participant IR as Identity Registry participant RR as Reputation Registry participant SA as Strategy Agent participant x402 as x402 Payment PA->>IR: Discover Strategy Agents IR-->>PA: List of registered agents PA->>RR: Check reputation scores RR-->>PA: Filtered by track record PA->>SA: Execute trade request SA->>x402: Payment required PA->>x402: Pay for service x402-->>SA: Payment confirmed SA-->>PA: Trade executed PA->>RR: Submit feedback ``` ### Multi-Agent Workflows AI agents collaborating across organizations can: * Discover each other via Identity Registry * Verify credentials before delegation * Track performance with Reputation Registry * Use Validation Registry for high-stakes decisions ## Integration with Celo ERC-8004 works seamlessly with Celo's ecosystem: * **Fee abstraction**: Register agents and give feedback paying gas in stablecoins * **x402 payments**: Combine trust verification with instant payments * **MCP servers**: Agents can expose capabilities via Celo MCP Server ## Resources | Resource | Link | | ----------------- | ---------------------------------------------------------------------------------------- | | EIP Specification | [eips.ethereum.org/EIPS/eip-8004](https://eips.ethereum.org/EIPS/eip-8004) | | Official Website | [8004.org](https://www.8004.org) | | Learning Portal | [8004.org/learn](https://www.8004.org/learn) | | Contracts Repo | [github.com/erc-8004/erc-8004-contracts](https://github.com/erc-8004/erc-8004-contracts) | | Telegram | [t.me/ERC8004](https://t.me/ERC8004) | | Builder Program | [bit.ly/8004builderprogram](http://bit.ly/8004builderprogram) | ## Related Protocols * [x402](/build-on-celo/build-with-ai/x402) - Payment layer for AI agents * [MPP](/build-on-celo/build-with-ai/mpp) - Machine Payments Protocol: charge USDC per request over HTTP * [Celopedia](/build-on-celo/build-with-ai/celopedia) - Celo ecosystem knowledge for coding assistants * [MCP Servers](/build-on-celo/build-with-ai/mcp/index) - Connect agents to data and tools # Celopedia Source: https://docs.celo.org/build-on-celo/build-with-ai/celopedia **Your AI coding assistant, now fluent in Celo.** Celopedia is a knowledge skill that plugs verified Celo intelligence — contract addresses, protocols, MiniPay, grants, and agent infrastructure — straight into the tools you already build with. Go from "what should I build?" to a live dApp without tab-hopping through docs. Search live ecosystem data to spot the gaps and opportunities worth building. Compare verticals, pick the right protocols, and scope an architecture that fits Celo. Pressure-test as you go — how saturated is this market, how does my approach compare? Grab contract addresses, MiniPay and fee-abstraction patterns, and deploy — all in your editor. ## Install Celopedia Add it to your coding assistant with one command: ```bash theme={null} npx skills add celo-org/celopedia-skills ``` Restart your coding assistant afterward if it doesn't discover new skills mid-session. Celopedia works with file-based skill environments including Codex, Claude Code, and OpenClaw — see the [GitHub repository](https://github.com/celo-org/celopedia-skills) for tool-specific install notes. ## Try it Once installed, ask your assistant things like: ```text theme={null} What lending protocols exist on Celo, and which vertical is least saturated? Give me the Uniswap V4 contract addresses on Celo mainnet. Scaffold a payments Mini App with the recommended architecture. Set up a Foundry project for Celo with fee abstraction. ``` ## What's inside | Area | What you get | | ---------------------- | ---------------------------------------------------------------------------------- | | Network & contracts | Chain IDs, RPCs, explorers, fee currencies, and verified contract addresses | | Ecosystem intelligence | Product discovery, competitor scans, and vertical analysis | | Builder setup | Foundry, Hardhat, Viem, Wagmi, fee abstraction, and deploy & verify patterns | | DeFi | References for Uniswap, Aave, Morpho, Mento, Velodrome, Curve, Ubeswap, and stCELO | | MiniPay | Wallet detection, stablecoin payments, ODIS, templates, and listing guidance | | AI agents | ERC-8004, x402, the Celo MCP Server, and agent skill references | | Grants | Funding programs and grant matchmaking | Celopedia is curated from official Celo documentation, protocol references, and live public data sources including Celo Docs, The Grid, DefiLlama, and Celoscan. ## Resources * [Celopedia](https://celopedia.celo.org/) * [Celopedia GitHub repository](https://github.com/celo-org/celopedia-skills) # Celo MCP Server Source: https://docs.celo.org/build-on-celo/build-with-ai/mcp/celo-mcp The **Celo MCP Server** is a Model Context Protocol (MCP) server that provides comprehensive access to the Celo blockchain. This powerful tool enables AI assistants and development environments to interact directly with Celo blockchain data, execute token operations, manage NFTs, handle smart contract interactions, process transactions, and participate in governance operations. ## Key Features * 🔗 **Blockchain Data Access**: Real-time access to blocks, transactions, and account information * 💰 **Token Operations**: Complete ERC20 and Mento stable token support (USDm, EURm, BRLm) * 🖼️ **NFT Management**: Support for ERC721 and ERC1155 standards with metadata fetching * 📄 **Smart Contract Interactions**: Call functions, estimate gas, and manage ABIs * 📊 **Transaction Handling**: Gas estimation, EIP-1559 support, and transaction simulation * 🏛️ **Governance Operations**: Access to Celo governance proposals and voting data ## Prerequisites * Python 3.11 or higher * Git (v2.38 or higher) * An IDE that supports MCP (Cursor or Claude Desktop) ## Installation ### Method 1: Direct Installation Clone the repository and install dependencies: ```bash theme={null} git clone https://github.com/celo-org/celo-mcp cd celo-mcp pip install -e . ``` ### Method 2: Using pipx (Recommended) ```bash theme={null} pip install pipx pipx install celo-mcp ``` ## Configuration Set up optional environment variables for custom RPC endpoints: ```bash theme={null} export CELO_RPC_URL="https://forno.celo.org" # Default: Celo mainnet export CELO_TESTNET_RPC_URL="https://forno.celo-sepolia.celo-testnet.org/" # Celo Sepolia testnet ``` ## MCP Client Integration MCP is supported by a wide range of IDEs and development tools. Below are setup instructions for popular options: ### VS Code Setup VS Code has native MCP support. Add the following configuration to your MCP settings: **macOS/Linux**: `~/.vscode/mcp.json` or via VS Code settings **Windows**: `%APPDATA%\Code\User\mcp.json` ```json theme={null} { "mcpServers": { "celo-mcp": { "command": "uvx", "args": ["--refresh", "celo-mcp"] } } } ``` ### Cursor IDE Setup Add the following configuration to your MCP settings file (`~/.cursor/mcp.json`): ```json theme={null} { "mcpServers": { "celo-mcp": { "command": "uvx", "args": ["--refresh", "celo-mcp"] } } } ``` The `--refresh` flag ensures the latest code is always loaded when the MCP server starts. ### JetBrains IDEs Setup For IntelliJ IDEA, WebStorm, PyCharm, and other JetBrains IDEs, configure MCP through the IDE settings or via the JetBrains MCP Server plugin. ### Windsurf Setup Windsurf has built-in MCP support. Configure MCP servers through the Windsurf settings interface. ### Claude Desktop Setup For Claude Desktop, add this configuration to your MCP settings file: * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` ```json theme={null} { "mcpServers": { "celo-mcp": { "command": "uvx", "args": ["--refresh", "celo-mcp"] } } } ``` ## Available Tools ### Blockchain Data Operations #### Network and Block Information * **`get_network_status`**: Get current network status and connection information * **`get_block`**: Fetch block information by number, hash, or "latest" * **`get_latest_blocks`**: Get information about recent blocks (up to 100) #### Account and Transaction Data * **`get_account`**: Get account information including balance and nonce * **`get_transaction`**: Get detailed transaction information by hash ### Token Operations #### Token Information and Balances * **`get_token_info`**: Get detailed token information (name, symbol, decimals, supply) * **`get_token_balance`**: Get token balance for a specific address * **`get_celo_balances`**: Get CELO and stable token balances for an address ### NFT Operations #### NFT Management * **`get_nft_info`**: Get NFT information including metadata and collection details * **`get_nft_balance`**: Get NFT balance for an address (supports ERC721 and ERC1155) ### Smart Contract Operations #### Contract Interactions * **`call_contract_function`**: Call read-only contract functions * **`estimate_contract_gas`**: Estimate gas for contract function calls ### Transaction Operations #### Transaction Management * **`estimate_transaction`**: Estimate gas and cost for transactions * **`get_gas_fee_data`**: Get current gas fee data including EIP-1559 fees ### Governance Operations #### Celo Governance * **`get_governance_proposals`**: Get Celo governance proposals with pagination * **`get_proposal_details`**: Get detailed information about specific governance proposals ## Development ### Running Tests ```bash theme={null} # Install development dependencies pip install -e ".[dev]" # Run tests pytest # Run with coverage pytest --cov=celo_mcp ``` ### Code Quality ```bash theme={null} # Format code black src/ isort src/ # Lint code flake8 src/ mypy src/ ``` ## Running the Server Start the MCP server directly: ```bash theme={null} # Run the MCP server python -m celo_mcp.server ``` # Model Context Protocol (MCP) Source: https://docs.celo.org/build-on-celo/build-with-ai/mcp/index [The Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol that standardizes how applications provide context to Large Language Models (LLMs). It was developed by Anthropic, the AI company behind Claude, to solve the challenge of consistently and efficiently connecting AI models with various data sources and tools. MCP has become the industry standard for integrating AI tools and IDEs, with widespread adoption across major development environments including VS Code, Cursor, JetBrains IDEs, Windsurf, Zed, and many others. OpenAI has also adopted MCP across their Agents SDK and ChatGPT desktop app, ensuring broad compatibility across major AI platforms. ## Celo specific MCPs: * [Celo MPC Server](/build/build-with-ai/mcp/celo-mcp) * Chain Info * Governance Proposals