<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Paul Imoke's Blog]]></title><description><![CDATA[Paul Imoke's Blog]]></description><link>https://blog.paulimoke.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 03:40:51 GMT</lastBuildDate><atom:link href="https://blog.paulimoke.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Gating a Web3 UI Based on On-Chain Attestations: A React Tutorial]]></title><description><![CDATA[As a Web3 frontend developer, you often need to restrict access to premium content, DAO dashboards, or specific application features based on a user's verified qualifications. Rather than building a c]]></description><link>https://blog.paulimoke.com/gating-a-web3-ui-based-on-on-chain-attestations-a-react-tutorial</link><guid isPermaLink="true">https://blog.paulimoke.com/gating-a-web3-ui-based-on-on-chain-attestations-a-react-tutorial</guid><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Paul Imoke]]></dc:creator><pubDate>Wed, 04 Mar 2026 08:21:07 GMT</pubDate><content:encoded><![CDATA[<p>As a Web3 frontend developer, you often need to restrict access to premium content, DAO dashboards, or specific application features based on a user's verified qualifications. Rather than building a centralized backend database to track who has completed KYC, joined a community, or attended an event, you can use the <strong>Attest Protocol SDK</strong> to verify on-chain attestations directly in your React frontend.</p>
<p>This technical guide walks you through the process of querying a decentralized attestation and using it to conditionally render a React component. We will be using the unified <code>@attestprotocol/sdk</code>, an open-source library that works seamlessly across supported blockchain networks (Stellar Soroban, Solana, Cairo).</p>
<p><strong>Prerequisites for Web3 Verification</strong></p>
<ul>
<li><p>You have the <code>@attestprotocol/sdk</code> installed in your project via npm, yarn, or pnpm.</p>
</li>
<li><p>You know the unique <code>schemaUID</code> representing the on-chain data structure you want to check (e.g., a "Verified Human" or "Accredited Investor" Schema).</p>
</li>
<li><p>You have access to the connected user's wallet address (e.g., via a standard Web3 wallet adapter).</p>
</li>
</ul>
<ol>
<li><strong>Initialize the Universal Client</strong></li>
</ol>
<p>First, initialize the Attestation Client. Because the SDK is chain-agnostic, you simply declare the chain your app is operating on. You do not need a signer (keypair) if you are only verifying (reading) data from the network.</p>
<pre><code class="language-typescript">import { AttestProtocol } from '@attestprotocol/sdk';

// Initialize the universal read-only client
// No secret key is required for verification queries
const sdk = await AttestProtocol.initializeStellar({
  url: 'https://soroban-testnet.stellar.org',
});
</code></pre>
<ol>
<li><strong>Querying the Attestation</strong></li>
</ol>
<p>We need to check if the connected user has an active, valid attestation for our specific <code>schemaUID</code>.</p>
<pre><code class="language-typescript">async function checkUserVerification(userAddress: string, schemaUID: string) {
  try {
    // Query the protocol for attestations matching the subject and schema
    const result = await sdk.fetchAttestation({
      subject: userAddress,
      schemaUID: schemaUID,
    });

    // Check if attestation exists and is not revoked
    if (result.data &amp;&amp; !result.data.revoked) {
      // You can additionally parse the value string if your schema holds specific data
      // e.g. "verified:true,level:enhanced"
      return true;
    }

    return false;
  } catch (error) {
    console.error("Failed to fetch attestations:", error.message);
    return false;
  }
}
</code></pre>
<ol>
<li><strong>Implementing the React Component</strong></li>
</ol>
<p>Now, let's tie this asynchronous verification logic into a React component using standard hooks. When the user connects their wallet, we check their attestation status and unlock the premium UI content.</p>
<pre><code class="language-typescript">import React, { useState, useEffect } from 'react';
import { checkUserVerification } from './attestUtils'; // Assuming the function above is exported

const VERIFIED_HUMAN_SCHEMA = "kyc-basic-v1";

export const PremiumDashboard = ({ userWalletAddress }) =&gt; {
  const [isVerified, setIsVerified] = useState&lt;boolean | null&gt;(null);

  useEffect(() =&gt; {
    if (!userWalletAddress) return;

    const verify = async () =&gt; {
      const status = await checkUserVerification(
        userWalletAddress, 
        VERIFIED_HUMAN_SCHEMA
      );
      setIsVerified(status);
    };

    verify();
  }, [userWalletAddress]);

  if (isVerified === null) {
    return &lt;div&gt;Checking credentials on-chain...&lt;/div&gt;;
  }

  if (!isVerified) {
    return (
      &lt;div className="locked-state"&gt;
        &lt;h2&gt;Access Denied: Verification Required&lt;/h2&gt;
        &lt;p&gt;You must hold a valid "Verified Human" on-chain attestation to view this Web3 dashboard.&lt;/p&gt;
        &lt;button onClick={() =&gt; alert("Redirect to KYC provider")}&gt;Start Verification Process&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  return (
    &lt;div className="unlocked-state"&gt;
      &lt;h2&gt;Welcome to the Premium Web3 Dashboard&lt;/h2&gt;
      &lt;p&gt;Your on-chain credentials have been verified successfully via the Attest Protocol!&lt;/p&gt;
      {/* Premium DAO Content or RWA Data Renders Here */}
    &lt;/div&gt;
  );
};
</code></pre>
<p><strong>Summary: Decentralized Access Control</strong></p>
<p>By leveraging the Attest Protocol SDK, gating a Web3 user interface becomes a purely frontend operation. Your React application reads verifiable data natively from the blockchain, eliminating the need to maintain an insecure centralized backend database of user permissions or API keys.</p>
<p>Because the SDK exposes a unified API, this exact same React component logic applies whether the underlying attestation was anchored on the Stellar network, Solana, or any other supported execution environment. This approach significantly enhances your application's decentralization, security, and developer experience (DX).</p>
]]></content:encoded></item><item><title><![CDATA[Step-by-Step Guide to Designing a Cinema Ticketing App with Google Sheets, Flutter, and Fincra API]]></title><description><![CDATA[Prerequisites:
This app will be built with the flutter framework, using google sheets for storing the data and the Fincra API for receiving payments. For this you'll need:

Flutter version 3.3.3

A Google Account with Google Cloud Console

A Fincra M...]]></description><link>https://blog.paulimoke.com/step-by-step-guide-to-designing-a-cinema-ticketing-app-with-google-sheets-flutter-and-fincra-api</link><guid isPermaLink="true">https://blog.paulimoke.com/step-by-step-guide-to-designing-a-cinema-ticketing-app-with-google-sheets-flutter-and-fincra-api</guid><category><![CDATA[fincra]]></category><category><![CDATA[Flutter]]></category><category><![CDATA[google sheets]]></category><category><![CDATA[React Native]]></category><dc:creator><![CDATA[Paul Imoke]]></dc:creator><pubDate>Tue, 13 Dec 2022 15:26:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/23LET4Hxj_U/upload/c208725fd3eddb56df6311879257d237.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-prerequisites">Prerequisites:</h2>
<p>This app will be built with the flutter framework, using google sheets for storing the data and the Fincra API for receiving payments. For this you'll need:</p>
<ul>
<li><p>Flutter version 3.3.3</p>
</li>
<li><p>A Google Account with Google Cloud Console</p>
</li>
<li><p>A Fincra Merchant account</p>
</li>
</ul>
<h3 id="heading-goal">Goal:</h3>
<p>At the end of this guide, you will have built a mobile app that connects to a Google spreadsheet to pull listed movie data, let users buy movie tickets, and automatically update the spreadsheet with new information whenever a purchase is made.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/paul-portfolio-6aec1.appspot.com/o/ezgif.com-gif-maker%20(1)%20(1).gif?alt=media&amp;token=5e8935b9-1275-4735-9fde-d66d0d8b7cbf" alt class="image--center mx-auto" /></p>
<h3 id="heading-outline">Outline:</h3>
<ul>
<li><p>Step 1: Set up Google Sheets Credentials</p>
</li>
<li><p>Step 2: Set up Google Spreadsheet Document</p>
</li>
<li><p>Step 3: Set up your Fincra Account</p>
</li>
<li><p>Step 4: Set up Flutter Local Code</p>
</li>
</ul>
<h4 id="heading-step-1-set-up-google-sheets-credentials">Step 1: Set up Google Sheets Credentials</h4>
<p>To get started, you'll need to get credentials from your Google console by following the process below to let your app access the spreadsheet.</p>
<ul>
<li><p>Go to <a target="_blank" href="https://console.developers.google.com">https://console.developers.google.com</a></p>
</li>
<li><p>Create a new project and name it "<strong>movie-app"</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922223629/JbrGqiWUJ.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922303383/55OYPuoyP.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Click the menu and go to <strong>"Enable API &amp; Services"</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922376991/hsABIW_YR.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Enable <strong>Google Drive API</strong> and <strong>Google Sheets API</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922434726/H2U8TTEtY.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922440683/VSkqhcMZS.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Next, you'll need to create a service account credentials, click the Menu button, and under <strong>API &amp; Services,</strong> click <strong>Credentials,</strong> then click <strong>Create Credentials</strong> and create a <strong>Service Account</strong>.</p>
<p><em>A service account is a robot account that can access your documents (spreadsheet) and perform actions on your behalf.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922500944/x3eFcWzJR.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Fill in the service account details</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922584289/l1mYWYgKa.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922590958/nvwB77odQ.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Once the service account is created, click <strong>Keys</strong> and create a new JSON key, and it should automatically download the JSON file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670885917677/sNDfqdWlk.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670922964588/4iBLektQ5.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h4 id="heading-step-2-set-up-google-spreadsheet-document">Step 2: Set up Google Spreadsheet Document</h4>
<ul>
<li><p>Create a new Google Spreadsheet document, or make a copy of this one<br />https://docs.google.com/spreadsheets/d/1gzCSczMfb1s8sXy81unXs3vR3JMBwFVTdJxDxk19ScI</p>
</li>
<li><p>Invite your service account to have edit access to the spreadsheet</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670923151667/c3dLXtIOh.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Make sure you have two sheets named <strong>Movies</strong> and <strong>Payments</strong> respectively</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670923234280/uzBvIyn3W.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670886688419/vKkJVEwFD.png" alt class="image--center mx-auto" /></p>
<p><em>Movies Table</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670886722910/Wfzd52QYT.png" alt class="image--center mx-auto" /></p>
<p><em>Payments Table</em></p>
<h4 id="heading-step-3-set-up-your-fincra-account">Step 3: Set up your Fincra Account</h4>
<ul>
<li><p>Go to <a target="_blank" href="https://app.fincra.com/auth/signup">https://app.fincra.com/auth/signup</a> to open an account</p>
</li>
<li><p>After signing up you should have access to a test account like the one below, don't worry the test account is fine for this guide</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670924140188/j3PdvHNfw.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h4 id="heading-step-4-set-up-flutter-local-code">Step 4: Set up Flutter Local Code</h4>
<ul>
<li><p>To get started quickly, I've already implemented the UI of the movie app, all you'll need to do is clone the flutter app repo</p>
<p>Here: <a target="_blank" href="https://github.com/pauleke65/movie_app">https://github.com/pauleke65/movie_app</a></p>
<p>Next, you'll need to configure the Google sheets service to let the app use the service account you previously created and access the spreadsheet.</p>
</li>
<li><p>Open the <code>google_sheet.dart</code> file and update the credentials with the ones in the previously downloaded JSON file.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670886993344/ynMCFJdbU.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670887175852/ZAkkmSq5b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Make sure to add your spreadsheet id in the <code>_spreadsheetId</code> variable</p>
<p><strong>Sample:</strong> <code>https://docs.google.com/spreadsheets/d/1gzCSczMfb1s8sXy81unXs3vR3JMBwFVTdJxDxk19ScI</code> where <strong>1gzCSczMfb1s8sXy81unXs3vR3JMBwFVTdJxDxk19ScI</strong> is the spreadsheet id.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670925478810/yvOyCc4lV.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Next, open the <code>payments.dart</code> file and update it with your Fincra API Credentials</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670887352866/jj64eJEMo.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Open your Fincra dashboard and go to <strong>Settings</strong>, then copy your <strong>Business Id</strong> and paste it in <code>businessId</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670925110398/SH2tlPMtX.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Next Click <strong>API Key &amp; Webhook</strong></p>
</li>
<li><p>Paste your <strong>Secret Key</strong> in <code>apiKey</code> and your <strong>Public Key</strong> in <code>publicKey</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670887485157/RUHMMOCGe.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>In the <code>Payment</code> class, you will find two main functions <code>getCheckoutLink()</code> which uses the <strong>Checkout &gt; Create Checkout</strong> endpoint to generate a checkout link that the user can use for payments.</p>
<p>More info <a target="_blank" href="https://docs.fincra.com/reference/create-checkout">here</a></p>
</li>
<li><p>And the <code>verifyPayment()</code> method, which uses the <strong>Checkout &gt; Verify Payment</strong> endpoint to verify the status of the payment if it was <em>successful</em> or it's still <em>pending</em>.</p>
<p>More info <a target="_blank" href="https://docs.fincra.com/reference/verify-payment">here</a></p>
</li>
<li><p>Now, in your terminal run <code>flutter pub get</code> to download the dependencies, then <code>flutter run</code> to get your app up and running.</p>
</li>
</ul>
<p>Congratulations🎉, you just created a cross-platform app with Flutter that uses Google Sheets as its database and the Fincra API to receive payments😃</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>So what exactly just happened?</p>
<p>Well, let me explain.</p>
<p>First, we set up our Google console service account and credentials so that we could let our app access our spreadsheet in order to retrieve the list of movies, and record payment history whenever a payment is made.</p>
<p>Next, we created our google spreadsheet, opened a Fincra account and set up our Flutter app that pulls the list of movies from the Google sheets and lets the user pay for a movie ticket with Fincra while recording the transactions history on the Google sheets table.</p>
<p>Voila✨</p>
]]></content:encoded></item></channel></rss>