<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: metadevdigital</title>
    <description>The latest articles on DEV Community by metadevdigital (@metadevdigital).</description>
    <link>https://dev.to/metadevdigital</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3815467%2F084f52a2-4d8c-4a5a-bb6e-06ee876450cb.png</url>
      <title>DEV Community: metadevdigital</title>
      <link>https://dev.to/metadevdigital</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/metadevdigital"/>
    <language>en</language>
    <item>
      <title>Why SatuChain’s APOS (Adaptive Proof of Stake) Could Be a Practical Model for the Next Generation of EVM Networks</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Sun, 05 Apr 2026 11:23:13 +0000</pubDate>
      <link>https://dev.to/metadevdigital/why-satuchains-apos-adaptive-proof-of-stake-could-be-a-practical-model-for-the-next-generation-1dk8</link>
      <guid>https://dev.to/metadevdigital/why-satuchains-apos-adaptive-proof-of-stake-could-be-a-practical-model-for-the-next-generation-1dk8</guid>
      <description>&lt;p&gt;Why SatuChain’s APOS (Adaptive Proof of Stake) Could Be a Practical Model for the Next Generation of EVM Networks&lt;/p&gt;

&lt;p&gt;In blockchain, the real challenge is no longer just launching a chain. The harder part is building a network that feels fast, affordable, reliable, and practical enough for real users and real applications.&lt;/p&gt;

&lt;p&gt;That is where SatuChain tries to position itself.&lt;/p&gt;

&lt;p&gt;SatuChain is presented as a Layer-1, EVM-compatible blockchain built for speed, predictable costs, and production-ready developer adoption. Instead of forcing builders to learn a new stack from scratch, it stays close to the familiar Ethereum ecosystem while introducing its own validator design through APOS — Adaptive Proof of Stake.&lt;/p&gt;

&lt;p&gt;What is APOS?&lt;/p&gt;

&lt;p&gt;APOS stands for Adaptive Proof of Stake, SatuChain’s consensus architecture designed around a hybrid validator model. Rather than relying on only one validator class, APOS combines genesis core validators with community-driven public validators and delegators. According to SatuChain’s technical documentation, the goal is to preserve early network stability while opening a path toward broader decentralization over time.&lt;/p&gt;

&lt;p&gt;This is an important design choice.&lt;/p&gt;

&lt;p&gt;Many networks face a familiar tradeoff:&lt;/p&gt;

&lt;p&gt;if validator participation is too open too early, network coordination can become fragile&lt;br&gt;
if the validator model is too closed, decentralization becomes mostly symbolic&lt;/p&gt;

&lt;p&gt;APOS appears to aim for a middle path.&lt;/p&gt;

&lt;p&gt;How SatuChain APOS Works&lt;/p&gt;

&lt;p&gt;Based on SatuChain’s published architecture, APOS uses a dual-tier validator system. The network starts with 5 core validators embedded from genesis to provide baseline block production and network stability. On top of that, the protocol allows up to 16 public validators to join the active set through staking weight, bringing the maximum active validator count to 21.&lt;/p&gt;

&lt;p&gt;The broader participation layer comes from delegators. Token holders do not need to run infrastructure themselves. Instead, they can delegate STU to validators, with SatuChain stating a minimum delegation of 100 STU and an approximately 80% reward share to delegators, while the remaining portion functions as validator commission.&lt;/p&gt;

&lt;p&gt;In simple terms, the APOS flow looks like this:&lt;/p&gt;

&lt;p&gt;Users stake or delegate STU&lt;br&gt;
Validators accumulate staking weight&lt;br&gt;
The active validator set participates in block production&lt;br&gt;
Blocks are finalized on a deterministic rotation model&lt;br&gt;
Rewards are distributed between validators and delegators&lt;br&gt;
Why the “Adaptive” Part Matters&lt;/p&gt;

&lt;p&gt;The word adaptive is doing real work here.&lt;/p&gt;

&lt;p&gt;SatuChain is not describing APOS as just another plain staking system. The model is built around the idea that networks evolve in phases:&lt;/p&gt;

&lt;p&gt;Phase 1: strong bootstrap security through core validators&lt;br&gt;
Phase 2: gradual validator expansion through public participation&lt;br&gt;
Phase 3: stronger economic decentralization through delegation&lt;/p&gt;

&lt;p&gt;That makes APOS interesting because it treats decentralization as something that should be structured, not only advertised.&lt;/p&gt;

&lt;p&gt;For early-stage ecosystems, this can be more realistic than pretending every chain starts fully decentralized on day one. It acknowledges that infrastructure reliability, validator quality, and security controls matter during the bootstrap period.&lt;/p&gt;

&lt;p&gt;Built for Practical Performance&lt;/p&gt;

&lt;p&gt;Consensus architecture only matters if the user experience improves.&lt;/p&gt;

&lt;p&gt;SatuChain’s APOS documentation claims the network is designed for:&lt;/p&gt;

&lt;p&gt;3-second block time&lt;br&gt;
fast finality&lt;br&gt;
low and predictable fees&lt;br&gt;
EVM-native compatibility&lt;br&gt;
public RPC, WebSocket, explorer, and verified contract tooling&lt;/p&gt;

&lt;p&gt;That combination is especially relevant for applications where inconsistency hurts adoption:&lt;/p&gt;

&lt;p&gt;DEX trading&lt;br&gt;
payment flows&lt;br&gt;
staking dashboards&lt;br&gt;
NFT interactions&lt;br&gt;
gaming transactions&lt;br&gt;
high-frequency consumer dApps&lt;/p&gt;

&lt;p&gt;The promise here is not just raw TPS marketing. The stronger message is operational predictability. Developers need infrastructure that behaves consistently under normal conditions, and users need confirmation times that feel stable rather than random.&lt;/p&gt;

&lt;p&gt;Security Through Structure, Not Just Marketing&lt;/p&gt;

&lt;p&gt;One of the stronger parts of the SatuChain documentation is that it frames security as both validator security and operational integrity.&lt;/p&gt;

&lt;p&gt;The network materials highlight features such as:&lt;/p&gt;

&lt;p&gt;staking-backed validator incentives&lt;br&gt;
slashing protection&lt;br&gt;
auto-jailing for validators missing too many blocks&lt;br&gt;
anti-abuse protections for public infrastructure&lt;br&gt;
redundancy planning for RPC availability&lt;br&gt;
an emphasis on finality and reorganization resistance in typical network conditions&lt;/p&gt;

&lt;p&gt;This is a practical way to think about blockchain security.&lt;/p&gt;

&lt;p&gt;In production, users do not only experience “consensus security.” They experience wallet connectivity, RPC reliability, explorer transparency, indexing quality, and whether transactions confirm when they should. If those layers are weak, even a technically sound chain can feel broken.&lt;/p&gt;

&lt;p&gt;APOS seems designed to support that broader view of reliability.&lt;/p&gt;

&lt;p&gt;Why APOS Fits the EVM World&lt;/p&gt;

&lt;p&gt;One major advantage of SatuChain is that it does not ask developers to abandon existing workflows. Its documentation emphasizes compatibility with Solidity, MetaMask, Hardhat, and Remix, which lowers migration friction for builders already working in the Ethereum ecosystem.&lt;/p&gt;

&lt;p&gt;That matters because adoption is often blocked by one simple issue:&lt;/p&gt;

&lt;p&gt;developers do not want to relearn everything just to test a new chain.&lt;/p&gt;

&lt;p&gt;An EVM-native network with a more structured staking model can be appealing if it offers:&lt;/p&gt;

&lt;p&gt;familiar tooling&lt;br&gt;
lower costs&lt;br&gt;
faster confirmations&lt;br&gt;
community staking participation&lt;br&gt;
enough architectural clarity for serious deployment&lt;/p&gt;

&lt;p&gt;This is where APOS may help SatuChain stand out. It is not trying to replace the EVM mindset. It is trying to make it more operationally usable.&lt;/p&gt;

&lt;p&gt;The Validator and Delegator Opportunity&lt;/p&gt;

&lt;p&gt;Another notable point is the network’s economic participation model.&lt;/p&gt;

&lt;p&gt;SatuChain documents a minimum 500,000 STU stake for public validators, while delegators can participate from 100 STU. That creates two different entry levels:&lt;/p&gt;

&lt;p&gt;infrastructure operators who want to run validator nodes&lt;br&gt;
community participants who want to support the network and earn staking rewards without managing servers&lt;/p&gt;

&lt;p&gt;This split is healthy for ecosystem growth.&lt;/p&gt;

&lt;p&gt;A chain becomes stronger when it offers meaningful roles to multiple participant types, not just full-node operators. Delegation broadens economic involvement, while validator requirements preserve performance and accountability.&lt;/p&gt;

&lt;p&gt;A More Realistic Layer-1 Narrative&lt;/p&gt;

&lt;p&gt;What I find most interesting about SatuChain’s APOS design is that it feels more grounded than the usual “fastest blockchain ever” messaging.&lt;/p&gt;

&lt;p&gt;The project narrative is centered on a few practical priorities:&lt;/p&gt;

&lt;p&gt;real-world dApp usability&lt;br&gt;
predictable execution costs&lt;br&gt;
stable validator participation&lt;br&gt;
builder-friendly EVM deployment&lt;br&gt;
a credible path from bootstrap security to broader decentralization&lt;/p&gt;

&lt;p&gt;That is a more mature story than simply chasing hype around TPS numbers.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;APOS on SatuChain looks like an attempt to solve a real blockchain problem: how to balance speed, usability, validator quality, and decentralization without sacrificing developer familiarity.&lt;/p&gt;

&lt;p&gt;If the network continues to execute on its documented goals, APOS could become one of the more practical consensus approaches for emerging EVM ecosystems, especially those targeting consumer apps, DeFi products, and community staking participation.&lt;/p&gt;

&lt;p&gt;In a market full of chains competing for attention, the ones that may last are not always the loudest. They are the ones that make on-chain systems feel dependable.&lt;/p&gt;

&lt;p&gt;And that is exactly the kind of problem APOS appears to be trying to solve.&lt;/p&gt;

&lt;p&gt;Official Website: &lt;a href="https://satuchain.com" rel="noopener noreferrer"&gt;https://satuchain.com&lt;/a&gt;&lt;br&gt;
Documentation: &lt;a href="https://docs.satuchain.com" rel="noopener noreferrer"&gt;https://docs.satuchain.com&lt;/a&gt;&lt;br&gt;
Mainnet Explorer: &lt;a href="https://stuscan.com" rel="noopener noreferrer"&gt;https://stuscan.com&lt;/a&gt;&lt;br&gt;
Testnet Explorer: &lt;a href="https://testnet.satuchain.com" rel="noopener noreferrer"&gt;https://testnet.satuchain.com&lt;/a&gt;&lt;br&gt;
Faucet: &lt;a href="https://faucet.satuchain.com" rel="noopener noreferrer"&gt;https://faucet.satuchain.com&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Solana Frontend Development: Building Functional Web3 UIs from Scratch</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Fri, 03 Apr 2026 16:26:16 +0000</pubDate>
      <link>https://dev.to/metadevdigital/solana-frontend-development-building-functional-web3-uis-from-scratch-4kfo</link>
      <guid>https://dev.to/metadevdigital/solana-frontend-development-building-functional-web3-uis-from-scratch-4kfo</guid>
      <description>&lt;h1&gt;
  
  
  Solana Frontend Development: Building Functional Web3 UIs from Scratch
&lt;/h1&gt;

&lt;p&gt;I've spent the last year shipping Solana dApps, and I'm gonna be real with you—the frontend side is where most developers struggle. Not because Solana's hard, but because the ecosystem moves fast and most tutorials are either outdated or don't show you how to actually build something people want to use.&lt;/p&gt;

&lt;p&gt;This guide covers the practical stuff: setting up a Solana wallet integration, reading on-chain data, and handling transactions on the frontend. No fluff, just what you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Solana Frontend Development is Different
&lt;/h2&gt;

&lt;p&gt;When you're building on Solana, you're not just throwing data on a blockchain and hoping it sticks. You need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle keypair signing locally (not with MetaMask magic)&lt;/li&gt;
&lt;li&gt;Interact with the Solana JSON RPC directly for most operations&lt;/li&gt;
&lt;li&gt;Deal with transaction finality that's actually fast enough to matter&lt;/li&gt;
&lt;li&gt;Build UIs that don't make users wait 30 seconds for confirmation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news? Once you get the patterns down, it's cleaner than traditional web3 development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Your Dev Environment Set Up
&lt;/h2&gt;

&lt;p&gt;First things first. Install the essentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @solana/web3.js @solana/wallet-adapter-react @solana/wallet-adapter-wallets @solana/wallet-adapter-base
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're starting fresh, I recommend using the Solana CLI too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; https://release.solana.com/stable/install&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
solana-cli 1.18.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify your setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;solana &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building Your First Wallet Connection
&lt;/h2&gt;

&lt;p&gt;This is the foundation. You need users to connect their wallets before anything meaningful happens.&lt;/p&gt;

&lt;p&gt;Here's a working example with React and the Wallet Adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConnectionProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WalletProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WalletModalProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WalletMultiButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PhantomWalletAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-wallets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clusterApiUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clusterApiUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PhantomWalletAdapter&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ConnectionProvider&lt;/span&gt; &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WalletProvider&lt;/span&gt; &lt;span class="na"&gt;wallets&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;wallets&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;autoConnect&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WalletModalProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Solana Frontend Starter&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WalletMultiButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;WalletModalProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;WalletProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ConnectionProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This handles the entire wallet connection flow. Users click the button, choose their wallet, and boom—you have access to their public key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading On-Chain Data
&lt;/h2&gt;

&lt;p&gt;Once you've got wallet connection, the next natural step is fetching data from the blockchain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useWallet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BalanceChecker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useWallet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;lamports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lamports&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Convert to SOL&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Connect wallet first&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Balance: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; SOL&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is straightforward, but notice the pattern: we depend on &lt;code&gt;publicKey&lt;/code&gt; from the wallet context, and we fetch data when it changes. Clean dependency management keeps your data in sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Transactions
&lt;/h2&gt;

&lt;p&gt;This is where things get interesting. Here's how to actually send a transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useWallet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/wallet-adapter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SystemProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TransferSOL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signTransaction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useWallet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendTransfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipientAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signTransaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wallet not connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;SystemProgram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;fromPubkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;toPubkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipientAddress&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;lamports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Convert SOL to lamports&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Get recent blockhash&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blockhash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLatestBlockhash&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recentBlockhash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blockhash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;feePayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Sign and send&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signedTx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;signTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendRawTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signedTx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

      &lt;span class="c1"&gt;// Wait for confirmation&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirmTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction sent! Signature: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer failed: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sendTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourRecipientAddressHere&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sending...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Send 0.1 SOL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key takeaways here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You always need a recent blockhash&lt;/li&gt;
&lt;li&gt;Sign with the wallet adapter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sendRawTransaction&lt;/code&gt; sends the serialized transaction&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;confirmTransaction&lt;/code&gt; waits for actual confirmation (not just acceptance)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Handling Errors Like a Professional
&lt;/h2&gt;

&lt;p&gt;Real apps fail gracefully. Here's what you should actually handle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleTransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your transaction code&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;insufficient funds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not enough SOL to cover transaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You rejected the transaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;32002&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network is busy, try again&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different errors need different messaging. Users shouldn't see raw RPC errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Gotchas I've Hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Blockhash expiration:&lt;/strong&gt; Don't cache blockhashes. Get a fresh one before every transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Wallet not signing:&lt;/strong&gt; Always check that &lt;code&gt;signTransaction&lt;/code&gt; exists before using it. Not all wallets support all operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Devnet SOL vs mainnet:&lt;/strong&gt; You're probably testing on devnet. Use the faucet, but know that devnet gets reset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. RPC rate limits:&lt;/strong&gt; If you're doing a lot of requests, consider using Helius or QuickNode instead of the free public RPC.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This covers the basics, but once you've got this down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn about SPL tokens (basically ERC20 but better)&lt;/li&gt;
&lt;li&gt;Explore program interactions (calling smart contract functions)&lt;/li&gt;
&lt;li&gt;Dive into NFT standards&lt;/li&gt;
&lt;li&gt;Build swap UIs using Orca or Jupiter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Solana ecosystem moves fast, so stay in the loop with the official docs and check out repos from projects you use.&lt;/p&gt;




</description>
      <category>solana</category>
      <category>frontend</category>
      <category>web3</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Web3 Marketing 101: Building Your Educational Foundation &amp; GTM Playbook</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Fri, 03 Apr 2026 16:25:46 +0000</pubDate>
      <link>https://dev.to/metadevdigital/web3-marketing-101-building-your-educational-foundation-gtm-playbook-pnn</link>
      <guid>https://dev.to/metadevdigital/web3-marketing-101-building-your-educational-foundation-gtm-playbook-pnn</guid>
      <description>&lt;h1&gt;
  
  
  Web3 Marketing 101: Building Your Educational Foundation &amp;amp; GTM Playbook
&lt;/h1&gt;

&lt;p&gt;Look, if you're building in Web3, you probably know that marketing here is... different. The old playbook doesn't work. You can't just drop a Facebook ad and expect 10k signups. The space moves fast, your community is sophisticated, and trust is everything. So let's build a real educational foundation and a go-to-market strategy that actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: The Web3 Marketing Fundamentals Module
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What Makes Web3 Marketing Different?
&lt;/h3&gt;

&lt;p&gt;Traditional marketing assumes passive consumers. Web3 marketing assumes active participants. Your users aren't just buying a product—they're potentially buying into a vision, a community, maybe even holding a token. That changes everything about how you communicate.&lt;/p&gt;

&lt;p&gt;The core differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transparency is non-negotiable.&lt;/strong&gt; Your community will call out BS instantly. Roadmaps, financials, even team members—be real about where you stand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community is your moat.&lt;/strong&gt; In Web3, a loyal 1,000-person community beats 100k passive followers. These people evangelize for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Narrative matters.&lt;/strong&gt; Bitcoin's "sound money" narrative, Ethereum's "world computer," Solana's "fast, cheap, scalable"—these stories move markets and drive adoption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-chain signals are real.&lt;/strong&gt; Actions on-chain (token transfers, smart contract interactions, governance votes) matter more than what someone says on Twitter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Core Distribution Channels (And Why They Work)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Twitter/X&lt;/strong&gt;&lt;br&gt;
The epicenter of Web3 discourse. Technical updates, community hot takes, and market sentiment all live here. Your strategy: Be helpful, share learnings, engage genuinely. Threads work. Hot takes work. But obvious shilling dies fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discord&lt;/strong&gt;&lt;br&gt;
Where communities actually live. This is where your power users hang out. Discord isn't for broadcasting—it's for conversation. Build roles, create channels for different topics, enable peer-to-peer support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telegram&lt;/strong&gt;&lt;br&gt;
Announcement channel for time-sensitive news and quick updates. Keep it tight—low-friction way to reach people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Blog/Mirror&lt;/strong&gt;&lt;br&gt;
Long-form content. Educational posts. Technical deep dives. This is where you own the narrative and build authority. Medium or Mirror work, but hosting on your own domain is better for SEO and brand control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-Chain Activity&lt;/strong&gt;&lt;br&gt;
This one's underrated. A token launch with careful vesting, a DAO vote, rewards for community members—these create real incentives and tangible proof of what you're building.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Three Pillars of Web3 Marketing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Education First&lt;/strong&gt;&lt;br&gt;
Your audience is learning. Help them. Write explainers. Make tutorials. Create content that teaches people why your solution matters, not just that it exists. Educational content builds trust faster than any marketing copy ever will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Community Building&lt;/strong&gt;&lt;br&gt;
You need real people invested in your success. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regular AMAs (ask me anything sessions)&lt;/li&gt;
&lt;li&gt;Transparent communication about progress and setbacks&lt;/li&gt;
&lt;li&gt;Rewarding community members who help (early supporters, evangelists, bug finders)&lt;/li&gt;
&lt;li&gt;Creating spaces for discussion, not just announcements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Product-Led Growth&lt;/strong&gt;&lt;br&gt;
Your product is your best marketing tool. Make it easy to try. Make it feel good to use. Create network effects where using it naturally leads to sharing it. In Web3, a smooth user experience with clear value beats hype every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Your GTM Strategy Toolkit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pre-Launch: Foundation Phase (4-8 weeks)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Week 1-2: Define Your Narrative&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What problem do you solve? (Be specific. "Make crypto easier" isn't specific.)&lt;/li&gt;
&lt;li&gt;Who's your first customer? (Not "everyone." Name them. Describe them. Know their pain.)&lt;/li&gt;
&lt;li&gt;What's your unique angle? (What would make someone choose you over alternatives?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write these down. One paragraph each. This becomes your north star.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3-4: Build Your Community Foundation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up Discord with basic structure (announcements, general, support, dev discussion)&lt;/li&gt;
&lt;li&gt;Create a Twitter account and start sharing learnings&lt;/li&gt;
&lt;li&gt;Set up your blog infrastructure (Ghost, Substack, Mirror—whatever)&lt;/li&gt;
&lt;li&gt;Recruit 20-50 early believers. These become your alpha users and evangelists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Week 5-8: Content &amp;amp; Education&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write 4-8 educational posts about the problem you're solving&lt;/li&gt;
&lt;li&gt;Create 1-2 explainer videos or visual guides&lt;/li&gt;
&lt;li&gt;Document your journey (transparency builds trust)&lt;/li&gt;
&lt;li&gt;Start hosting weekly AMAs or office hours&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Launch Phase (Launch week + 2 weeks after)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pre-Launch Week&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email your community. Tell them what's coming.&lt;/li&gt;
&lt;li&gt;Create launch-day assets (graphic, 30-second video, announcement thread)&lt;/li&gt;
&lt;li&gt;Plan your launch day: What's happening on-chain? Any token distributions? Contests?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Launch Day&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post everywhere at the same time (but don't spam)&lt;/li&gt;
&lt;li&gt;Jump into community Discord—be present, answer questions&lt;/li&gt;
&lt;li&gt;Track early feedback obsessively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Week After Launch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share launch-day metrics (transparently)&lt;/li&gt;
&lt;li&gt;Respond to feedback, deploy quick fixes&lt;/li&gt;
&lt;li&gt;Start interviews with early users (what worked, what didn't)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Post-Launch: Growth Phase (Weeks 3+)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Retention &amp;gt; Acquisition&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track who's using you regularly&lt;/li&gt;
&lt;li&gt;Create advanced content for power users&lt;/li&gt;
&lt;li&gt;Implement referral mechanics (rewards for bringing friends)&lt;/li&gt;
&lt;li&gt;Regular updates on progress and roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Content Rhythm&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2-3 tweets per week (mix of updates, educational, personality)&lt;/li&gt;
&lt;li&gt;1 substantial blog post per week&lt;/li&gt;
&lt;li&gt;1 community call per month (Discord spaces, Twitter spaces, whatever format fits)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analytics That Matter&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Daily active users and repeat usage rate (are people coming back?)&lt;/li&gt;
&lt;li&gt;Community growth (followers, Discord members—but quality matters more than size)&lt;/li&gt;
&lt;li&gt;Sentiment tracking (are people saying good things or complaining?)&lt;/li&gt;
&lt;li&gt;On-chain metrics (if applicable): transaction volume, new addresses, token holders&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real GTM Checklist
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRE-LAUNCH
☐ Narrative defined and documented
☐ Discord server created and moderated
☐ Twitter account with thoughtful early posts
☐ Blog set up with 3+ educational pieces
☐ 25+ early community members recruited
☐ Launch day timeline and assets prepared
☐ Team briefed on communication strategy

LAUNCH WEEK
☐ Launch announcement across all channels
☐ Community support team active in Discord
☐ Daily progress updates shared
☐ Early feedback documented
☐ Basic metrics dashboard created

FIRST 30 DAYS
☐ Post-launch retrospective written
☐ Product improvements shipped based on feedback
☐ Community member interviews conducted (at least 5)
☐ Educational content for early users created
☐ Referral mechanism (if applicable) launched
☐ Second content series published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Mindset Shift
&lt;/h2&gt;

&lt;p&gt;Here's what separates good Web3 marketing from great Web3 marketing: You're not trying to convince people. You're building something worth talking about, and inviting people to participate.&lt;/p&gt;

&lt;p&gt;Focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Being genuinely helpful&lt;/li&gt;
&lt;li&gt;Building in public&lt;/li&gt;
&lt;li&gt;Treating early community members like partners&lt;/li&gt;
&lt;li&gt;Measuring success by engagement and retention, not just follower count&lt;/li&gt;
&lt;li&gt;Being honest about what you don't know yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. It's not more complicated than that, but it is more &lt;em&gt;authentic&lt;/em&gt; than traditional marketing.&lt;/p&gt;

&lt;p&gt;Build something real. Tell the truth about it. Let your community grow organically from people who actually care.&lt;/p&gt;




</description>
      <category>web3marketing</category>
      <category>gotomarketstrategy</category>
      <category>communitybuilding</category>
      <category>blockchaineducation</category>
    </item>
    <item>
      <title>El Colosseum de Solana y su Taller: Todo lo que necesitas saber</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Fri, 03 Apr 2026 14:05:45 +0000</pubDate>
      <link>https://dev.to/metadevdigital/el-colosseum-de-solana-y-su-taller-todo-lo-que-necesitas-saber-3451</link>
      <guid>https://dev.to/metadevdigital/el-colosseum-de-solana-y-su-taller-todo-lo-que-necesitas-saber-3451</guid>
      <description>&lt;h1&gt;
  
  
  El Colosseum de Solana y su Taller: Todo lo que necesitas saber
&lt;/h1&gt;

&lt;p&gt;Hey, aquí va un hilo que te va a cambiar cómo ves la educación en Web3. No es el típico contenido de cripto, así que dale una chance.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧵 Hilo: Colosseum y el Taller - La revolución educativa que faltaba
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1/&lt;/strong&gt; Okay, empecemos por lo obvio: si estás en Solana y quieres aprender a buildear, pero no sabes por dónde empezar, probablemente te has sentido perdido. Hay tutoriales viejos, comunidades fragmentadas y mucho ruido. Colosseum llega a romper ese esquema completamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2/&lt;/strong&gt; ¿Qué es Colosseum? En serio, no es solo otra plataforma de cursos. Es un arena (sí, literalmente un "colosseum") donde los developers se reúnen para resolver problemas reales y aprender mientras lo hacen. Es como si Stack Overflow tuviera un bebé con una bootcamp de Web3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3/&lt;/strong&gt; La diferencia clave está en el Taller. Mientras otros platafomas te dan videos aburridos, el Taller es donde la magia ocurre. Aquí no estás viendo a alguien programar en una pantalla. Estás resolviendo desafíos reales, trabajando con código que importa, y siendo guiado por gente que sabe qué onda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4/&lt;/strong&gt; Mira, en el desarrollo tradicional, aprendes con "hello world". En el Taller de Colosseum, aprendes construyendo cosas que la gente realmente usa. ¿Necesitas entender smart contracts? No hay mejor forma que escribir uno de verdad. ¿SPL tokens? Crealos. ¿Integración con Anchor? Úsalo en un proyecto que vale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5/&lt;/strong&gt; Lo que me fascina es que el Taller no es competitivo de una manera tóxica. Es cooperativo. Ves a otros developers resolviendo problemas, puedes colaborar, pedir feedback, y más importante aún: ves exactamente dónde estás en tu journey de aprendizaje.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6/&lt;/strong&gt; Los recursos que encuentras en el Taller son updated. No son documentación de 2021 que nadie mantiene. Es contenido vivo, porque está siendo usado constantemente por la comunidad. Si algo cambió en Rust o en la versión de Anchor, el Taller lo refleja.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7/&lt;/strong&gt; Y aquí viene lo mejor: hay incentivos reales. No es solo por aprenderlo o por hacerlo. En Colosseum, tu trabajo vale. Completa desafíos, gana rewards, construye reputación. Es como freelancing, pero para aprender. Ganas mientras evolucionas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8/&lt;/strong&gt; El Taller también es genial porque te conecta con mentores que realmente quieren ayudarte. No son bots dando respuestas genéricas. Son developers que han estado donde tú estás, que saben los pain points, que entienden por qué ciertos conceptos de Solana son confusos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9/&lt;/strong&gt; Hablemos de la curva de aprendizaje. Si eres totalmente nuevo en Web3 pero tienes experiencia de programación, el Taller tiene paths para ti. Si ya estás en Solana pero quieres specializar te en DeFi, hay desafíos específicos. El contenido se adapta a dónde estés.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10/&lt;/strong&gt; La comunidad detrás de Colosseum es otro level. No es just transactional. La gente está genuinamente interesada en que los demás crezcan. Ves threads en Twitter, discussions en Discord, code reviews, colaboraciones. Es un ecosistema de verdad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11/&lt;/strong&gt; Tecnicamente, el Taller usa la blockchain para certificar tu progreso. Tu achievement no vive en un certificado que nadie verifica. Vive on-chain. Los builders pueden ver exactamente qué desafíos completaste, cuánta experiencia acumulaste, en qué áreas eres fuerte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12/&lt;/strong&gt; Esto importa porque cuando eres un junior developer buscando oportunidad, las companies pueden ver tu historial real. No es un CV que dice "tengo experiencia en Rust". Es: "completé 15 desafíos de Rust, colaboré en 3 proyectos, recibí feedback positivo de 20+ mentores".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13/&lt;/strong&gt; El Taller también entiende que no todo el mundo learns igual. Algunos prefieren documentación escrita. Otros necesitan ver código ejecutándose. Otros aprenden mejor con problemas. Colosseum tiene todo mezclado estratégicamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14/&lt;/strong&gt; Y no es elitista. No necesitas $10k para una bootcamp. No necesitas vivir en SF o Nueva York. Es global, es accesible, y está diseñado específicamente para que la barrera de entrada sea baja pero el ceiling sea infinito.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15/&lt;/strong&gt; El futuro del learning en Web3 no es certifications random que nadie valida. Es demostración real de habilidad a través de trabajo real. Colosseum lo entiende. El Taller lo ejecuta. Por eso está resonando tanto en la comunidad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16/&lt;/strong&gt; Si estás pensando si deberías unirte: ¿quieres buildear en Solana? ¿Quieres aprender de verdad? ¿Quieres ganar mientras aprendes? No es una pregunta difícil. Colosseum + El Taller es donde tiene que estar tu atención ahora.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;17/&lt;/strong&gt; Last thing: la evolución de Colosseum va a ser interesante de ver. No me sorprendería que en 6 meses sea la place donde los mejores junior devs de Solana están construyendo. Y va a ser porque el modelo funciona. Porque el Taller enseña lo real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;18/&lt;/strong&gt; Así que mañana, chequea Colosseum. Entra al Taller. Completa el primer desafío. Date cuenta de que finalmente alguien entendió cómo debería ser aprender en Web3. Nos vemos en el arena 🏛️&lt;/p&gt;




</description>
      <category>solana</category>
      <category>colosseum</category>
      <category>tallerdeaprendizaje</category>
      <category>desarrolloweb3</category>
    </item>
    <item>
      <title>How to Build a Solana Spending App with Xpend: The Developer's Guide</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Mon, 30 Mar 2026 14:05:44 +0000</pubDate>
      <link>https://dev.to/metadevdigital/how-to-build-a-solana-spending-app-with-xpend-the-developers-guide-4fk4</link>
      <guid>https://dev.to/metadevdigital/how-to-build-a-solana-spending-app-with-xpend-the-developers-guide-4fk4</guid>
      <description>&lt;h1&gt;
  
  
  How to Build a Solana Spending App with Xpend: The Developer's Guide
&lt;/h1&gt;

&lt;p&gt;Alright, let's be real—managing expenses on-chain is still a pain point for most developers building on Solana. You've got your wallet, you've got your tokens, but tracking where your SOL is actually going? That's where things get messy. Enter Xpend, a spending analytics platform built for the Solana ecosystem that makes it dead simple to monitor, categorize, and optimize your on-chain transactions.&lt;/p&gt;

&lt;p&gt;In this guide, I'm walking you through how to integrate Xpend into your Solana application and why it matters for your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Should Care About Spending Analytics on Solana
&lt;/h2&gt;

&lt;p&gt;Before we dive into the technical stuff, let's talk about why this matters. Most blockchain applications focus on transaction volume or TVL, but they ignore a critical user pain point: &lt;strong&gt;financial clarity&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Users want to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where is their money actually going?&lt;/li&gt;
&lt;li&gt;What are their spending patterns across different dApps?&lt;/li&gt;
&lt;li&gt;How much are they losing to slippage and fees?&lt;/li&gt;
&lt;li&gt;Can they set spending limits or get alerts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Xpend solves this. And when you integrate it into your app, you're not just building features—you're building trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js (v16+) installed&lt;/li&gt;
&lt;li&gt;A Solana wallet with some SOL (testnet is fine)&lt;/li&gt;
&lt;li&gt;Basic understanding of Solana program interactions&lt;/li&gt;
&lt;li&gt;The Solana CLI installed&lt;/li&gt;
&lt;li&gt;Familiarity with JavaScript/TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Xpend in Your Project
&lt;/h2&gt;

&lt;p&gt;First, install the necessary packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @xpend/sdk @solana/web3.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you're using yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @xpend/sdk @solana/web3.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Initialize the Xpend Client
&lt;/h2&gt;

&lt;p&gt;Create a new file called &lt;code&gt;xpend-client.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;XpendClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xpend/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;XpendClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.xpend.io&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;XPEND_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Get this from Xpend dashboard&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, you'll need an API key. Head over to the Xpend dashboard, sign up, and grab your credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Fetch User Spending Data
&lt;/h2&gt;

&lt;p&gt;Now let's pull actual spending data for a wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./xpend-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserSpending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spendingData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSpending&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timeframe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Last 30 days&lt;/span&gt;
      &lt;span class="na"&gt;includeMetadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;spendingData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to fetch spending data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUserSpending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_WALLET_ADDRESS_HERE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalSpent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;125.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SOL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeframe"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"30d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"categories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trading"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;75.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"staking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;30.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nft_purchases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fees"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.00&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transactions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tx123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trading"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dapp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Orca"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1699564800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create Spending Categories and Alerts
&lt;/h2&gt;

&lt;p&gt;Here's where it gets useful. Let's set up custom spending categories and alerts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupSpendingAlerts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Create custom categories&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCategory&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Trading Experiments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FF6B6B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Orca&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Raydium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jupiter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Auto-categorize these dApps&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Set up alerts&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createAlert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;threshold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Alert if trading exceeds 100 SOL&lt;/span&gt;
    &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;7d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Per week&lt;/span&gt;
    &lt;span class="na"&gt;webhookUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-app.com/webhooks/spending-alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alerts configured successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Display Spending Dashboard in Your UI
&lt;/h2&gt;

&lt;p&gt;Now let's build a React component to display the spending data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./xpend-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SpendingDashboard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;walletAddress&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSpending&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;xpendClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSpending&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;timeframe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nf"&gt;setSpending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to load spending:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="nx"&gt;spending&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;available&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spending-dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nc"&gt;Spending &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Last&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="nx"&gt;Days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;total-spent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalSpent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;SOL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;categories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category-card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;SOL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
                &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-fill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalSpent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}}&lt;/span&gt;
              &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recent-transactions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Recent&lt;/span&gt; &lt;span class="nx"&gt;Transactions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;spending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tx-row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dapp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;SOL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Handle Webhooks for Real-Time Updates
&lt;/h2&gt;

&lt;p&gt;If you're setting up alerts, here's how to handle incoming webhooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhooks/spending-alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Alert for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Send notification to user, update UI, etc.&lt;/span&gt;
  &lt;span class="c1"&gt;// Example: send to database, trigger Telegram bot, etc.&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Webhook server running&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Rate Limiting&lt;/strong&gt;: Xpend has rate limits. Cache spending data for at least 5 minutes before re-fetching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Error Handling&lt;/strong&gt;: Always wrap API calls in try-catch blocks. Network issues happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Security&lt;/strong&gt;: Never expose your &lt;code&gt;XPEND_API_KEY&lt;/code&gt; in client-side code. Keep it server-side only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. User Consent&lt;/strong&gt;: Always ask users for permission before tracking their spending. Transparency builds trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Integrating Xpend into your Solana app gives your users something most crypto platforms don't offer: financial clarity. It's not flashy, but it's incredibly valuable.&lt;/p&gt;

&lt;p&gt;The beauty of this integration is that it's straightforward. You get spending analytics, custom alerts, and category management without building all of it from scratch. Your users get better visibility into their on-chain activity. Everyone wins.&lt;/p&gt;

&lt;p&gt;Start with the basic integration, gather feedback from your users, and expand from there. That's how you build products people actually want to use.&lt;/p&gt;




</description>
      <category>solana</category>
      <category>web3</category>
      <category>xpend</category>
      <category>spendinganalytics</category>
    </item>
    <item>
      <title>Understanding Cross-Chain Bridges: A Developer's Guide to Moving Assets Between Blockchains</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Fri, 27 Mar 2026 15:15:40 +0000</pubDate>
      <link>https://dev.to/metadevdigital/understanding-cross-chain-bridges-a-developers-guide-to-moving-assets-between-blockchains-1fja</link>
      <guid>https://dev.to/metadevdigital/understanding-cross-chain-bridges-a-developers-guide-to-moving-assets-between-blockchains-1fja</guid>
      <description>&lt;h1&gt;
  
  
  Understanding Cross-Chain Bridges: A Developer's Guide to Moving Assets Between Blockchains
&lt;/h1&gt;

&lt;p&gt;Cross-chain bridges have become one of the most important infrastructure pieces in Web3, yet they're also one of the most misunderstood. If you're building on multiple chains or just trying to move your assets around, you've probably wondered how these things actually work under the hood. Let me break it down in a way that actually makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Need Bridges (The Problem)
&lt;/h2&gt;

&lt;p&gt;Here's the thing: blockchains don't naturally talk to each other. Bitcoin doesn't know what's happening on Ethereum. Solana doesn't care about Polygon. They're isolated ecosystems with their own validators, consensus mechanisms, and security models.&lt;/p&gt;

&lt;p&gt;But users want to use the best application on each chain. Someone might want to trade on Uniswap (Ethereum), use Magic Eden (Solana), and interact with Phantom (Polygon) all in the same day. They need a way to move their assets between these worlds without going through centralized exchanges.&lt;/p&gt;

&lt;p&gt;That's where bridges come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Cross-Chain Bridges Actually Work
&lt;/h2&gt;

&lt;p&gt;There are a few different approaches, and understanding them will help you decide which bridge to use (and which ones to be careful with).&lt;/p&gt;

&lt;h3&gt;
  
  
  Liquidity Pools (The Most Common Approach)
&lt;/h3&gt;

&lt;p&gt;The simplest and most used method relies on liquidity pools on both sides of the bridge. Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You deposit your tokens on Chain A (let's say Ethereum)&lt;/li&gt;
&lt;li&gt;The bridge locks your tokens in a smart contract&lt;/li&gt;
&lt;li&gt;Equivalent tokens are minted on Chain B (let's say Polygon)&lt;/li&gt;
&lt;li&gt;You can now use those wrapped tokens on Polygon&lt;/li&gt;
&lt;li&gt;When you want to go back, you burn the Polygon tokens, and your original tokens unlock on Ethereum&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Services like Uniswap's bridge or Stargate Finance use variations of this model. It's straightforward but requires liquidity providers to actually have capital sitting on both sides. The bridge operators take fees to incentivize this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validator-Based Bridges
&lt;/h3&gt;

&lt;p&gt;Some bridges use their own network of validators to confirm transactions. Wormhole, for example, uses a guardian network. Here's the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You initiate a transaction on the source chain&lt;/li&gt;
&lt;li&gt;Validators observe and confirm the transaction&lt;/li&gt;
&lt;li&gt;They sign off that yes, this transaction definitely happened&lt;/li&gt;
&lt;li&gt;Once enough validators agree (typically 2/3+), they trigger the corresponding action on the destination chain&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This works well but introduces new trust assumptions. You're now trusting the bridge's validators in addition to the blockchain's validators. This is why bridge security breaches have been so dramatic—there's an additional point of failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimistic Bridges
&lt;/h3&gt;

&lt;p&gt;These are newer and more experimental. They assume transactions are valid unless proven otherwise. Someone posts a claim ("the user locked 10 ETH"), and unless someone challenges it within a time window, it's accepted. If challenged, there's a verification game to determine who was right.&lt;/p&gt;

&lt;p&gt;It's similar to optimistic rollups in concept. You get fast finality most of the time, but with a built-in dispute resolution mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Risks You Need to Know
&lt;/h2&gt;

&lt;p&gt;Look, I'm going to be straight with you: bridges are complex. And complexity in crypto usually means risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Liquidity risks&lt;/strong&gt;: If a bridge doesn't have enough liquidity on the destination chain, you might get slipped worse than a Uniswap trade with 0.01% liquidity. Or worse, you might not be able to move your assets back when you want to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validator risks&lt;/strong&gt;: If the bridge validator set is small or dominated by a few large players, you're back to trusting institutions. That defeats the purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart contract risks&lt;/strong&gt;: Bridges are smart contracts. They can have bugs. History is full of bridge hacks—from Nomad to Poly Network to Ronin. When code is handling billions in liquidity, even small vulnerabilities are catastrophic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Economic risks&lt;/strong&gt;: Some bridges require you to hold governance tokens to use them. If that token crashes, your bridge utility crashes with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing a Bridge: What Actually Matters
&lt;/h2&gt;

&lt;p&gt;So you need to move assets. Here's what I actually look at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Track record&lt;/strong&gt;: Has this bridge been live for years without getting hacked? Boring is good here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total value locked&lt;/strong&gt;: More TVL usually means more liquidity and less slippage. But it also means bigger target on their back for hackers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fee structure&lt;/strong&gt;: Some bridges take 0.1%, others take 1%. Over repeated transactions, this adds up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed&lt;/strong&gt;: Do you need your assets in seconds or is 10 minutes fine? Liquidity-based bridges are usually faster. Validator-based bridges depend on finality time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chain support&lt;/strong&gt;: Does it support the specific chains you need? If you're primarily on Solana and want Polygon, make sure the bridge actually connects those two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Community sentiment&lt;/strong&gt;: Check Discord and Twitter. If the community is losing confidence, that's a signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Bridges Worth Paying Attention To
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stargate&lt;/strong&gt;: Liquidity-based, supports major chains, good UI. Owned by the LayerZero protocol team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wormhole&lt;/strong&gt;: Validator-based, massive TVL, supports like 15+ chains. Got hacked once, but recovered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hop Protocol&lt;/strong&gt;: Great for rollups, solid tech, smaller but trustworthy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native bridges&lt;/strong&gt;: Some chains like Polygon have their own bridges. These are usually safest because they leverage the chain's own validators.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future: Intent-Based Bridges
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. New protocols like Intents are emerging where instead of worrying about which bridge to use, you just declare your intent: "I want 10 USDC on Polygon." The system figures out the optimal path, which bridge to use, and how much slippage to expect. That's pretty cool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Bridges aren't magic—they're either locking your assets and minting new ones, or they're using trusted intermediaries to confirm your transaction. Both approaches have tradeoffs. The key is understanding which tradeoffs you're making and whether you trust the mechanism.&lt;/p&gt;

&lt;p&gt;If you're moving large amounts, split across multiple bridges. If you're moving small amounts, native bridges are almost always safest. And always, always test with small amounts first. No bridge is worth losing your entire position over a weird edge case.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>crosschain</category>
      <category>bridges</category>
      <category>web3infrastructure</category>
    </item>
    <item>
      <title>How Reentrancy Attacks Work in Solidity — and How to Prevent Them</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Tue, 24 Mar 2026 17:48:38 +0000</pubDate>
      <link>https://dev.to/metadevdigital/how-reentrancy-attacks-work-in-solidity-and-how-to-prevent-them-4j4j</link>
      <guid>https://dev.to/metadevdigital/how-reentrancy-attacks-work-in-solidity-and-how-to-prevent-them-4j4j</guid>
      <description>&lt;h1&gt;
  
  
  How Reentrancy Attacks Work in Solidity — and How to Prevent Them
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1451187580459-43490279c0fa%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1451187580459-43490279c0fa%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" alt="cover" width="1200" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your contract is probably vulnerable right now, and you don't even know it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part Nobody Tells You
&lt;/h2&gt;

&lt;p&gt;Reentrancy isn't some exotic attack that only happens to bad code. It's baked into Solidity's execution model. When you call an external contract, you're handing over control of execution. The called contract can do literally anything before returning to you. Including calling you back.&lt;/p&gt;

&lt;p&gt;The Ronin bridge hack (2022) cost $625 million. Wormhole lost $325 million. Both involved reentrancy vectors. But the vulnerability has been known since 2016. The DAO attack literally created reentrancy as a category. And people &lt;em&gt;still&lt;/em&gt; get it wrong.&lt;/p&gt;

&lt;p&gt;Let me show you why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here's Where It Gets Weird
&lt;/h2&gt;

&lt;p&gt;Look at this contract. Totally normal withdrawal function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

contract VulnerableBank {
    mapping(address =&amp;gt; uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] &amp;gt;= amount);

        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);

        balances[msg.sender] -= amount;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dead simple. Check balance, send money, update balance. What could go wrong? Everything.&lt;/p&gt;

&lt;p&gt;When you call &lt;code&gt;msg.sender.call{value: amount}("")&lt;/code&gt;, you're giving control to whatever contract &lt;code&gt;msg.sender&lt;/code&gt; is. If it's a contract, its fallback function runs &lt;em&gt;immediately&lt;/em&gt;. Before the balance gets updated. So an attacker contract can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Attacker {
    VulnerableBank target;

    constructor(address _target) {
        target = VulnerableBank(_target);
    }

    function attack() public payable {
        target.deposit{value: 1 ether}();
        target.withdraw(1 ether);
    }

    fallback() external payable {
        // We're in the middle of withdraw()
        // balance hasn't been updated yet
        if (address(target).balance &amp;gt;= 1 ether) {
            target.withdraw(1 ether);
        }
    }

    receive() external payable {
        // Same thing
        if (address(target).balance &amp;gt;= 1 ether) {
            target.withdraw(1 ether);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution flow: &lt;code&gt;withdraw()&lt;/code&gt; checks balance[attacker] = 1 ether ✓. Call sends 1 ether, attacker's fallback runs. Attacker calls &lt;code&gt;withdraw()&lt;/code&gt; again. Checks balance&lt;a href="https://dev.tostill%201%20ether!"&gt;attacker&lt;/a&gt; ✓. Sends another ether, fallback runs again. Repeat until bank is drained. &lt;em&gt;Then&lt;/em&gt; the first balance update finally happens. You just lost everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lesson I Learned The Hard Way
&lt;/h2&gt;

&lt;p&gt;I audited a lending protocol in 2022 (won't name it, NDAs exist). They had flash loan logic. I found a reentrancy path through the redemption function and told the team. Their response? "Oh, it's fine, we check balances before and after." That doesn't work. The attacker can call another protocol in their callback that sends them tokens, completely bypassing your checks. That contract got rugged two months later — different exploit, but the reentrancy was sitting there waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Checks-Effects-Interactions (CEI):&lt;/strong&gt; Update state &lt;em&gt;before&lt;/em&gt; you call external code. Put the balance update before the call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract SecureBank {
    mapping(address =&amp;gt; uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] &amp;gt;= amount);

        balances[msg.sender] -= amount;  // EFFECT FIRST

        (bool success, ) = msg.sender.call{value: amount}("");  // INTERACTION LAST
        require(success);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when the attacker's fallback runs, &lt;code&gt;balances[msg.sender]&lt;/code&gt; is already zero. Second call fails the require. Done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reentrancy Guard (Mutex):&lt;/strong&gt; Sometimes you can't reorganize code cleanly. Use a lock instead. Set a flag to 2 before executing, back to 1 after. Any reentrancy attempt reads locked as 2 and reverts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() {
        require(locked == 1, "No reentrancy");
        locked = 2;
        _;
        locked = 1;
    }
}

contract SafeBank is ReentrancyGuard {
    mapping(address =&amp;gt; uint256) public balances;

    function withdraw(uint256 amount) public nonReentrant {
        require(balances[msg.sender] &amp;gt;= amount);

        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);

        balances[msg.sender] -= amount;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use established patterns:&lt;/strong&gt; Prefer pull over push. Use safe transfer functions from battle-tested libraries. Minimize the surface area where reentrancy can happen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Better: use safeTransfer from OpenZeppelin
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract BetterBank {
    using SafeERC20 for IERC20;

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] &amp;gt;= amount);
        balances[msg.sender] -= amount;
        IERC20(token).safeTransfer(msg.sender, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Reentrancy is dead simple to prevent. Checks-Effects-Interactions. Reentrancy guards. Safe transfer patterns. Pick one, or use two to be paranoid. The real problem is developers don't think about it until someone exploits them. Don't be that developer. Think about your callstack. Think about who controls execution when. Think about what state is true when. That's 90% of security right there.&lt;/p&gt;




</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>solidity</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Token Locks: Why Projects Are Using Them (And Why You Should Care)</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Tue, 24 Mar 2026 17:48:18 +0000</pubDate>
      <link>https://dev.to/metadevdigital/token-locks-why-projects-are-using-them-and-why-you-should-care-9nm</link>
      <guid>https://dev.to/metadevdigital/token-locks-why-projects-are-using-them-and-why-you-should-care-9nm</guid>
      <description>&lt;h1&gt;
  
  
  Token Locks: Why Projects Are Using Them (And Why You Should Care)
&lt;/h1&gt;

&lt;p&gt;If you've spent any time in crypto, you've probably heard the term "token lock" thrown around. Maybe you've seen it on a project's roadmap, or noticed it mentioned in a whitepaper as some kind of security feature. But what actually &lt;em&gt;is&lt;/em&gt; a token lock, and why are developers and projects obsessed with them?&lt;/p&gt;

&lt;p&gt;Let me break it down in a way that actually makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Founder Rug Pulls and Trust Issues
&lt;/h2&gt;

&lt;p&gt;Here's the reality—crypto has a trust problem. For good reason. We've all seen the headlines: founder disappears with millions, unlocks all their tokens at once and dumps them on the market, killing the project overnight. It's called a "rug pull," and it's one of the most common ways retail investors lose money in this space.&lt;/p&gt;

&lt;p&gt;This is where token locks come in.&lt;/p&gt;

&lt;p&gt;A token lock is essentially a smart contract that prevents certain tokens (usually founder allocations, team tokens, or investor tokens) from being transferred or sold until a specific date or condition is met. Think of it like locking your crypto in a vault and throwing away the key until a predetermined time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Token Locks Work (The Technical Side)
&lt;/h2&gt;

&lt;p&gt;At their core, token locks are fairly straightforward smart contracts. Here's the basic concept:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract TokenLock {
    IERC20 public token;
    address public beneficiary;
    uint256 public unlockTime;
    uint256 public lockedAmount;

    constructor(
        address _token,
        address _beneficiary,
        uint256 _unlockTime,
        uint256 _amount
    ) {
        token = IERC20(_token);
        beneficiary = _beneficiary;
        unlockTime = _unlockTime;
        lockedAmount = _amount;
    }

    function unlock() external {
        require(block.timestamp &amp;gt;= unlockTime, "Tokens still locked");
        require(msg.sender == beneficiary, "Only beneficiary can unlock");

        uint256 balance = token.balanceOf(address(this));
        require(balance &amp;gt; 0, "No tokens to unlock");

        token.transfer(beneficiary, balance);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, right? You deposit tokens into the contract, set a beneficiary address, specify when they unlock, and then nobody—not even the original deployer—can touch those tokens until the time is up. The smart contract doesn't care who you are or what your excuses are. It's pure, algorithmic enforcement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Actually Matters for Projects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Building Investor Confidence&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a new project goes public, early investors are basically betting their money on the team not abandoning ship. A token lock proves that the founders are committed long-term. If the team's tokens are locked for 2-3 years, suddenly they have incentive to actually build something valuable instead of cashing out immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Preventing Dumps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without a token lock, here's what can happen: Token launches, price pumps on hype, founder dumps their entire allocation at once, price crashes 90%. Token lock smooths this out by forcing a vesting schedule. Tokens unlock gradually over time, which means selling pressure is distributed and more predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Getting Listed on Exchanges&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most serious exchanges require token lock documentation before they'll list a project. They don't want to list a token that's about to get rugged. When you can show them a verified smart contract that cryptographically proves the founder's tokens are locked for 18 months, suddenly you look a lot more legitimate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Types of Token Locks
&lt;/h2&gt;

&lt;p&gt;Not all token locks are created equal. Here are the common variations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-based locks:&lt;/strong&gt; The simplest kind. Tokens become available after a specific date. No conditions, no flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vesting locks:&lt;/strong&gt; More sophisticated. Instead of all tokens unlocking at once, they unlock gradually over time. A founder might have 10 million tokens, but only 100,000 unlock per month for 100 months. This prevents massive dumps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-signature locks:&lt;/strong&gt; Requires multiple signers to unlock. Even if a founder's private key is compromised, the attacker can't touch the locked tokens without the other signatories approving it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditional locks:&lt;/strong&gt; Unlock based on specific conditions being met. For example, tokens might only unlock once the protocol reaches certain metrics or milestones. This aligns incentives with actual project development.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Catch: Not All Locks Are Equal
&lt;/h2&gt;

&lt;p&gt;Here's where you need to be careful. Some projects use "soft locks"—tokens locked in a wallet that the team controls, with a public promise not to move them. This is basically trust, just with extra steps. &lt;/p&gt;

&lt;p&gt;The &lt;em&gt;real&lt;/em&gt; security comes from &lt;strong&gt;hard locks&lt;/strong&gt;—smart contracts where the code is law. Even the founders can't move the tokens early, no matter what. You can verify this on a blockchain explorer by looking at the smart contract code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red flags to watch for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No publicly verifiable lock contract&lt;/li&gt;
&lt;li&gt;Suspiciously short lock periods (6 months is pretty short)&lt;/li&gt;
&lt;li&gt;Founder tokens that vest all at once instead of gradually&lt;/li&gt;
&lt;li&gt;Multiple "emergency unlock" functions in the code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Means for You
&lt;/h2&gt;

&lt;p&gt;If you're evaluating a new token project, ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are the founder tokens locked? Until when?&lt;/li&gt;
&lt;li&gt;Where's the lock contract address? Can you verify it on Etherscan?&lt;/li&gt;
&lt;li&gt;What's the vesting schedule?&lt;/li&gt;
&lt;li&gt;Are there multi-sig requirements?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions separate projects that are serious about building from ones that might not be. A transparent token lock won't guarantee a project succeeds, but it's a pretty good signal that the team isn't planning to exit scam.&lt;/p&gt;

&lt;p&gt;Token locks aren't revolutionary technology. They're just smart contracts doing simple math. But in an ecosystem rife with bad actors, sometimes the most powerful tool is one that says: "I literally cannot access these tokens before this date, no matter how hard I try."&lt;/p&gt;

&lt;p&gt;And in crypto, that's worth a lot.&lt;/p&gt;

</description>
      <category>tokenlocks</category>
      <category>smartcontracts</category>
      <category>blockchainsecurity</category>
      <category>web3development</category>
    </item>
    <item>
      <title>Kazakhstan's Growing Solana Ecosystem: Projects You Should Know About</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Tue, 24 Mar 2026 13:48:19 +0000</pubDate>
      <link>https://dev.to/metadevdigital/kazakhstans-growing-solana-ecosystem-projects-you-should-know-about-3ai7</link>
      <guid>https://dev.to/metadevdigital/kazakhstans-growing-solana-ecosystem-projects-you-should-know-about-3ai7</guid>
      <description>&lt;h1&gt;
  
  
  Kazakhstan's Growing Solana Ecosystem: Projects You Should Know About
&lt;/h1&gt;

&lt;p&gt;Kazakhstan isn't usually the first place that comes to mind when you think about Solana development hubs, but that's changing fast. The country has quietly built an impressive collection of blockchain projects, many of them native to Solana. Whether you're a developer looking to connect with the community or someone curious about what's happening in Central Asia's crypto scene, there's actually a lot worth paying attention to here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Kazakhstan Matters for Solana
&lt;/h2&gt;

&lt;p&gt;First, let's get the context straight. Kazakhstan has positioned itself as a crypto-friendly nation with clear regulatory frameworks. This isn't just talk—it's backed up by actual infrastructure and government support. The country has special economic zones dedicated to blockchain development, competitive electricity costs (which matter for validators), and a growing developer talent pool who are increasingly building on Solana instead of staying confined to traditional tech companies.&lt;/p&gt;

&lt;p&gt;The real advantage? Lower operational costs combined with serious technical talent. When you combine those factors with Solana's speed and low fees, you get developers who can iterate fast and build for global audiences without bleeding through a bootstrap budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Projects Shaping the Scene
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Aqbe Finance
&lt;/h3&gt;

&lt;p&gt;Aqbe Finance is one of the more interesting projects emerging from Kazakhstan's Solana ecosystem. They're building infrastructure for decentralized finance with a specific focus on cross-chain bridging and liquidity solutions. What makes them notable is their approach to solving real problems that developers actually face—fragmented liquidity across chains and expensive bridging fees.&lt;/p&gt;

&lt;p&gt;Their protocol lets users move assets between Solana and other chains with minimal slippage, which matters if you're running an app that needs to tap into liquidity pools across multiple networks. The team is small but technically solid, and they've been shipping updates consistently rather than doing the typical crypto thing of disappearing after a launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  MarginFi
&lt;/h3&gt;

&lt;p&gt;While not exclusively Kazakhstani, MarginFi has significant development happening in Kazakhstan. They're building margin trading infrastructure for Solana, which is frankly something the ecosystem needed. Their approach focuses on capital efficiency and risk management—solving the problem of how retail traders can access leverage without getting liquidated in a flash crash.&lt;/p&gt;

&lt;p&gt;The interesting part is how they've structured their liquidation mechanisms and collateral management. It's the kind of nitty-gritty infrastructure work that doesn't get attention but makes the whole ecosystem more functional. Developers in Kazakhstan have been instrumental in shipping several protocol upgrades here.&lt;/p&gt;

&lt;h3&gt;
  
  
  CapyDAO
&lt;/h3&gt;

&lt;p&gt;This is a more recent project that's building community-driven infrastructure for Solana. The DAO structure means actual token holders have governance rights, but more importantly, it shows how Kazakhstan developers are thinking about long-term sustainability and community ownership rather than just extracting value.&lt;/p&gt;

&lt;p&gt;They're focusing on education and developer tooling, which is slightly unglamorous compared to flashy trading platforms, but absolutely critical for ecosystem health. They've published some genuinely useful documentation and SDKs that make it easier to build on Solana.&lt;/p&gt;

&lt;h3&gt;
  
  
  LocalSolana
&lt;/h3&gt;

&lt;p&gt;LocalSolana is a grassroots project that deserves mention because it represents the community aspect of Kazakhstan's ecosystem. It's essentially a decentralized exchange with a focus on peer-to-peer trading and local community building. Nothing revolutionary from a technical standpoint, but the execution is solid and it's actually being used by people in the region.&lt;/p&gt;

&lt;p&gt;What's worth noting: they're building for specific regional needs—stablecoin adoption patterns differ across countries, payment preferences vary, and the regulatory environment matters. LocalSolana isn't trying to be another Uniswap clone; it's optimizing for actual usage in its region.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Different About This Ecosystem
&lt;/h2&gt;

&lt;p&gt;Three things stand out when you look at Kazakhstan's Solana projects compared to crypto projects elsewhere:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pragmatism Over Hype&lt;/strong&gt;&lt;br&gt;
You won't find 10-minute Telegram videos promising 100x returns. The projects here are shipping actual code and solving real problems. There's less marketing theater and more technical focus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Long-term Thinking&lt;/strong&gt;&lt;br&gt;
Many of these projects are building infrastructure instead of yet another token. That's harder to sell to retail investors, but it creates lasting value. The developers seem to be thinking in years, not the 90-day crypto cycles we see elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Community Integration&lt;/strong&gt;&lt;br&gt;
There's genuine effort to build actual communities rather than just pump-and-dump token holder groups. Projects regularly contribute to local education initiatives and developer grants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Involved
&lt;/h2&gt;

&lt;p&gt;If you're interested in the Kazakhstan Solana ecosystem, here's what you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Follow builders&lt;/strong&gt;: Most active developers maintain Twitter/X accounts and are genuinely responsive to questions. It's not the massive ecosystem of Ethereum where you get lost in thousands of projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join local communities&lt;/strong&gt;: Telegram groups and Discord servers for Kazakhstan crypto communities are active and helpful. People actually respond to questions here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contribute&lt;/strong&gt;: Several projects are actively looking for developers. If you have Rust or TypeScript skills and want to work on meaningful infrastructure, there are real opportunities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the products&lt;/strong&gt;: The best feedback is actually using these applications. LocalSolana, Aqbe, and others benefit from real transaction data and user feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Future
&lt;/h2&gt;

&lt;p&gt;Kazakhstan's Solana ecosystem is still in early stages, but the trajectory is compelling. You've got regulatory clarity, developer talent, economic incentives, and—critically—people who are building for the right reasons. It's not the sexiest part of the Solana ecosystem, but it's where actual infrastructure gets built.&lt;/p&gt;

&lt;p&gt;The developers here aren't trying to flip a token in three months. They're building the pipes and foundations that other projects will depend on. That's less exciting than a viral launch, but it's how ecosystems actually become resilient and useful.&lt;/p&gt;

&lt;p&gt;If you're seriously interested in Solana's future, worth keeping an eye on what's building in Kazakhstan.&lt;/p&gt;




</description>
      <category>solana</category>
      <category>kazakhstan</category>
      <category>web3</category>
      <category>blockchainprojects</category>
    </item>
    <item>
      <title>Merkle Trees in Blockchain: From Bitcoin to Airdrops</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Sun, 22 Mar 2026 17:48:49 +0000</pubDate>
      <link>https://dev.to/metadevdigital/merkle-trees-in-blockchain-from-bitcoin-to-airdrops-3dop</link>
      <guid>https://dev.to/metadevdigital/merkle-trees-in-blockchain-from-bitcoin-to-airdrops-3dop</guid>
      <description>&lt;h1&gt;
  
  
  Merkle Trees in Blockchain: From Bitcoin to Airdrops
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1639762681057-7375639deef3%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1639762681057-7375639deef3%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" alt="cover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've ever debugged a database query, you've felt the pain of verifying data at scale. You run a SELECT query, get back 10,000 rows, and think: "How do I know this is complete and unchanged?" In traditional systems, you trust the database server to give you the right answer. Merkle trees solve this problem without a trusted middleman.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Web2 Analogy: Hash-Based Verification
&lt;/h2&gt;

&lt;p&gt;Imagine you're building an API that serves file checksums to millions of clients. You could hash each file individually, but that's inefficient—with 1 million files, you're computing 1 million hashes per request. Instead, you build a tree structure where you hash pairs of files together, then hash those results together, until you get a single root hash. Now you only need to return one hash to represent all 1 million files. This is the Merkle tree: a binary tree where every leaf is a data hash, and every parent node is the hash of its two children.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters in Blockchain
&lt;/h2&gt;

&lt;p&gt;Bitcoin's block structure relies entirely on Merkle trees. Each block contains ~2,000 transactions, and instead of storing 2,000 transaction hashes, Bitcoin only stores one: the Merkle root. This was genius for 2009 when storage was precious, and it's still foundational for SPV (Simplified Payment Verification) wallets—lightweight clients that verify transactions without downloading the entire blockchain. The key insight: &lt;strong&gt;you can prove a specific transaction exists in a block with only ~12 hashes&lt;/strong&gt;, not the entire block.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Let's say you have 8 transactions: Tx1, Tx2, Tx3, Tx4, Tx5, Tx6, Tx7, Tx8.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Root
          /    \
        H(AB)  H(CD)
       /  \    /   \
     H1  H2  H3    H4
    / \ / \  / \   / \
   T1 T2 T3 T4 T5 T6 T7 T8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To prove Tx1 exists in this tree, you need the hash of Tx1 itself, H2 (hash of Tx3+Tx4), and H(CD) (hash of all transactions 5-8). That's 3 hashes to prove 1 transaction among 8. With 2,048 transactions (a realistic block), it's ~11 hashes. This is the &lt;strong&gt;Merkle proof&lt;/strong&gt; or &lt;strong&gt;Merkle path&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web2 Equivalent: Merkle Proofs vs. Digital Signatures
&lt;/h2&gt;

&lt;p&gt;In Web2, you might verify data integrity using HMAC-SHA256—the server computes an HMAC and sends it alongside the data, then the client recomputes it to verify nothing changed. The problem: the client still has to process all the data. With Merkle proofs, the client processes &lt;em&gt;only the leaf it cares about&lt;/em&gt;, plus the path to the root. It's like asking a database: "Prove this customer exists in the customer table" without requiring the customer to download all customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World: Uniswap's Airdrop
&lt;/h2&gt;

&lt;p&gt;Uniswap distributed 400 million UNI tokens in September 2020. They couldn't store 250,000 claims on-chain—that would cost millions in gas. So they used a Merkle tree instead. Uniswap computed a Merkle tree of all eligible addresses and amounts, posted the root on-chain (32 bytes), and claimers submitted their address + amount + Merkle proof. The contract verified the proof against the root. This cost roughly 200k gas per claim—affordable and scalable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solidity Implementation
&lt;/h2&gt;

&lt;p&gt;Here's a real Merkle claim contract, simplified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract MerkleAirdrop {
    bytes32 public merkleRoot;
    mapping(address =&amp;gt; bool) public claimed;

    event Claimed(address indexed claimer, uint256 amount);

    constructor(bytes32 _merkleRoot) {
        merkleRoot = _merkleRoot;
    }

    function claim(uint256 amount, bytes32[] calldata proof) external {
        require(!claimed[msg.sender], "Already claimed");

        // Compute the leaf hash
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));

        // Verify the proof
        require(
            MerkleProof.verify(proof, merkleRoot, leaf),
            "Invalid proof"
        );

        claimed[msg.sender] = true;
        // Transfer tokens...
        emit Claimed(msg.sender, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;MerkleProof.verify()&lt;/code&gt; function does the heavy lifting: it hashes pairs up the tree until it reaches the root, then checks if it matches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Computing the Merkle Root (Off-Chain)
&lt;/h2&gt;

&lt;p&gt;You don't compute the Merkle root in Solidity. That happens off-chain in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MerkleTree&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;merkletreejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keccak256&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keccak256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addresses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x123...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x456...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x789...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Create leaves&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;solidityPack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uint256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Build tree&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MerkleTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaves&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sortPairs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRoot&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Generate proof for first address&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That root gets deployed in the contract. Proofs get distributed to users (usually via API or frontend). Make sure your sorting is consistent between off-chain and on-chain or proofs will fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Web2 Developer's Concern
&lt;/h2&gt;

&lt;p&gt;I'll be honest: the first time I saw a Merkle tree in crypto, I thought, "Why not just use a database?" The answer is you &lt;em&gt;can't&lt;/em&gt; trust the database anymore when you don't control the server. But Merkle trees are genuinely clever—they're deterministic, cryptographically secure, and scale logarithmically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Merkle Trees Can't Do
&lt;/h2&gt;

&lt;p&gt;Merkle proofs only prove inclusion. They don't prove &lt;em&gt;exclusion&lt;/em&gt;—if you want to prove someone is &lt;em&gt;not&lt;/em&gt; in the airdrop list, that's harder (you need a range proof or accumulator, different tools). Also, once you post a Merkle root on-chain, changing it requires a new transaction. The Uniswap airdrop merkle root is still there, immutable, forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Step: Build It Today
&lt;/h2&gt;

&lt;p&gt;Clone the &lt;a href="https://github.com/miguelmota/merkletreejs" rel="noopener noreferrer"&gt;merkletreejs repo&lt;/a&gt; and run the example with Hardhat. Create a simple airdrop for 10 test addresses, deploy it to Goerli testnet, and claim it yourself. You'll understand more in 30 minutes of hands-on work than reading another article.&lt;/p&gt;




</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>solidity</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>On-Chain Governance: The Voting Mechanisms That Actually Move Billions (And Fail Spectacularly)</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Sat, 21 Mar 2026 17:48:43 +0000</pubDate>
      <link>https://dev.to/metadevdigital/on-chain-governance-the-voting-mechanisms-that-actually-move-billions-and-fail-spectacularly-3f7e</link>
      <guid>https://dev.to/metadevdigital/on-chain-governance-the-voting-mechanisms-that-actually-move-billions-and-fail-spectacularly-3f7e</guid>
      <description>&lt;h1&gt;
  
  
  On-Chain Governance: The Voting Mechanisms That Actually Move Billions (And Fail Spectacularly)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1518546305927-5a555bb7020d%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1518546305927-5a555bb7020d%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" alt="cover" width="1200" height="802"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most governance tokens are security theater that lets retail holders &lt;em&gt;feel&lt;/em&gt; like they matter while whales decide everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part Nobody Tells You
&lt;/h2&gt;

&lt;p&gt;Governance isn't about democracy. It's about &lt;em&gt;economic incentives&lt;/em&gt;. Whoever owns the most tokens controls the votes—shocker, I know. Most DAOs have participation rates under 5%, which means you're literally fighting people who won't show up. Meanwhile whales are delegating to themselves and running off with treasury funds. Compound's governance model became the template for 200+ copycat protocols using simple token-weighted voting—one token, one vote. Sounds fair until a single address owns 2% and effectively runs everything because nobody else participates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here's Where It Gets Weird
&lt;/h2&gt;

&lt;p&gt;On-chain governance lives on an &lt;strong&gt;immutable ledger&lt;/strong&gt;. Vote for a bad proposal and it's there forever. Get rugged by a governance attack and it's &lt;em&gt;your fault for voting&lt;/em&gt;. Ronin Bridge blew up because validators had governance power and got compromised—the entire sidechain got drained and it's all transparently visible.&lt;/p&gt;

&lt;p&gt;Here's basic token voting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

interface IGovernanceToken {
    function balanceOf(address account) external view returns (uint256);
}

contract SimpleGovernance {
    IGovernanceToken public token;

    struct Proposal {
        uint256 id;
        string description;
        uint256 forVotes;
        uint256 againstVotes;
        uint256 deadline;
        bool executed;
        mapping(address =&amp;gt; bool) hasVoted;
    }

    mapping(uint256 =&amp;gt; Proposal) public proposals;
    uint256 public proposalCount;

    constructor(address _token) {
        token = IGovernanceToken(_token);
    }

    function createProposal(string memory description) external {
        proposals[proposalCount].id = proposalCount;
        proposals[proposalCount].description = description;
        proposals[proposalCount].deadline = block.timestamp + 3 days;
        proposalCount++;
    }

    function vote(uint256 proposalId, bool support) external {
        require(!proposals[proposalId].hasVoted[msg.sender], "Already voted");
        require(block.timestamp &amp;lt; proposals[proposalId].deadline, "Voting ended");

        uint256 votes = token.balanceOf(msg.sender);
        require(votes &amp;gt; 0, "No voting power");

        proposals[proposalId].hasVoted[msg.sender] = true;

        if (support) {
            proposals[proposalId].forVotes += votes;
        } else {
            proposals[proposalId].againstVotes += votes;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is garbage. &lt;strong&gt;Flash loan attack&lt;/strong&gt;—someone borrows 100 million tokens, votes with them, returns them in the same transaction. MakerDAO patched this with vote delegation snapshots at block height. The first 50 protocols got destroyed by variants of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delegation: Where Laziness Meets Oligarchy
&lt;/h2&gt;

&lt;p&gt;Most governance tokens support delegation so hodlers can hand off voting power to addresses they trust. The problem: once you delegate, you forget about it. You move tokens around, sell half your bag, and you're still voting through an address that might not even exist anymore. Curve governance got hit hard because voter apathy plus delegation to random addresses equals centralized control by whoever stays awake and actually votes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract DelegationExample {
    mapping(address =&amp;gt; address) public delegates;
    mapping(address =&amp;gt; uint256) public delegateVotes;

    IGovernanceToken token;

    function delegate(address to) external {
        address oldDelegate = delegates[msg.sender];
        uint256 balance = token.balanceOf(msg.sender);

        if (oldDelegate != address(0)) {
            delegateVotes[oldDelegate] -= balance;
        }

        delegates[msg.sender] = to;
        delegateVotes[to] += balance;
    }

    function getVotes(address account) external view returns (uint256) {
        return delegateVotes[account];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple. Broken in practice. Nobody tracks when large delegations happen. Whales keep positions secret until voting starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timelock and Execution: The Speed Bump That Doesn't Stop Anything
&lt;/h2&gt;

&lt;p&gt;Most protocols add a timelock between voting and execution—usually 1-2 days—so theoretically people have time to exit if a proposal tanks the protocol. In reality? If a whale pushes through something malicious, you have maybe 48 hours to notice, evaluate, and get your tokens off an exchange. Good luck with that.&lt;/p&gt;

&lt;p&gt;Euler Finance got destroyed by a governance exploit because their timelock was too short and their voting threshold was too low. Someone accumulated just enough governance tokens and pushed a bad proposal through. The attack chain was visible on-chain the whole time. Nobody noticed until it was too late.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VOTING_PERIOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 3 days&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TIMELOCK_DELAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 2 days&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TOTAL_SAFETY_WINDOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;VOTING_PERIOD&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;TIMELOCK_DELAY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 5 days&lt;/span&gt;

&lt;span class="c1"&gt;// If you're not monitoring governance constantly? You're exposed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quorum: The Empty Room Problem
&lt;/h2&gt;

&lt;p&gt;Most protocols require minimum participation—quorum. If only 2% of token holders vote, does the proposal pass? Different protocols answer differently. Aave requires 320,000 tokens voting, which sounds substantial until you realize it's 0.5% of their governance supply. With delegation issues? You're really at 0.2% of &lt;em&gt;actual&lt;/em&gt; engaged voters. The dirty secret: if you're a whale in a low-quorum protocol, you basically have unilateral control if you can be bothered to vote.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Talk
&lt;/h2&gt;

&lt;p&gt;On-chain governance is &lt;em&gt;transparent&lt;/em&gt; but not &lt;em&gt;fair&lt;/em&gt;. It's &lt;em&gt;permissionless&lt;/em&gt; but not &lt;em&gt;accessible&lt;/em&gt;. Most token holders can't parse proposals. Most voters don't understand the implications.&lt;/p&gt;

&lt;p&gt;If you're building a DAO, assume it will eventually be controlled by whoever cares most—i.e., whoever makes money from controlling it. Design your timelock long enough to actually matter. Set quorum high enough to require real consensus. Make voting &lt;em&gt;costly&lt;/em&gt; so people think before they vote: time cost, gas cost, delegation risk. Otherwise you're just running a whaleocracy with extra steps and a blockchain to prove it.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>solidity</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Flash Loans: How Aave Turned Instant Liquidity Into a $25M Problem</title>
      <dc:creator>metadevdigital</dc:creator>
      <pubDate>Fri, 20 Mar 2026 17:48:51 +0000</pubDate>
      <link>https://dev.to/metadevdigital/flash-loans-how-aave-turned-instant-liquidity-into-a-25m-problem-57pg</link>
      <guid>https://dev.to/metadevdigital/flash-loans-how-aave-turned-instant-liquidity-into-a-25m-problem-57pg</guid>
      <description>&lt;h1&gt;
  
  
  Flash Loans: How Aave Turned Instant Liquidity Into a $25M Problem
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1558494949-ef010cbdcc31%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1558494949-ef010cbdcc31%3Fw%3D1200%26q%3D80%26auto%3Dformat%26fit%3Dcrop" alt="cover" width="1200" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;February 2020. bZx protocol got torn apart by a $55,000 flash loan attack—pocket change now, but it was the first time anyone weaponized atomic arbitrage on mainnet.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Three years later, Euler Finance ate a $196 million loss using the same playbook.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; So yeah, flash loans are elegant as hell, but they'll also burn your protocol to the ground if you're not paranoid enough.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Aave's flash loans are uncollateralized loans that must be repaid (plus 0.05% fee) within the same transaction. They're powerful for arbitrage, liquidations, and MEV, but catastrophically dangerous if you assume prices remain stable or rely on external oracles without reentrancy guards. Always validate state changes mid-transaction; never trust balances or prices before the loan is repaid.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Would Anyone Give You Money They Can Take Back Mid-Transaction?
&lt;/h2&gt;

&lt;p&gt;Ethereum transactions are atomic. Either they all succeed or they all fail—there's no halfway state on the blockchain.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; Aave figured out that this atomicity meant they could lend money with zero risk. If you can't repay within the same transaction, the whole thing reverts like it never happened.&lt;/p&gt;

&lt;p&gt;The implementation is almost stupid in its simplicity. You call &lt;code&gt;flashLoan()&lt;/code&gt;, Aave sends you tokens, invokes your callback function, checks that the tokens (plus a 0.05% fee) got returned, and if not—transaction gets nuked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface IFlashLoanReceiver {
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external returns (bytes32);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the actual flow: you call &lt;code&gt;flashLoan()&lt;/code&gt; with an asset and amount. Aave transfers tokens to your contract, calls your &lt;code&gt;executeOperation()&lt;/code&gt; callback, then verifies the tokens plus fee made it back into their vault.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Simplified Aave flash loan logic
function flashLoan(
    address receiver,
    address token,
    uint256 amount,
    bytes calldata params
) external {
    uint256 balanceBefore = IERC20(token).balanceOf(address(this));
    uint256 amountOwed = amount + (amount * flashLoanPremium / 10000);

    IERC20(token).transfer(receiver, amount);

    IFlashLoanReceiver(receiver).executeOperation(
        token,
        amount,
        amountOwed - amount,
        msg.sender,
        params
    );

    // This is the critical check: if it fails, entire tx reverts
    require(
        IERC20(token).balanceOf(address(this)) &amp;gt;= amountOwed,
        "Flash loan not repaid"
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The legitimate uses are actually pretty cool: DEX arbitrage, liquidations without needing capital upfront, swapping collateral on the fly.&lt;sup id="fnref4"&gt;4&lt;/sup&gt; Problems start when someone builds a liquidator and forgets that their callback runs mid-transaction, not after everything settles.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Oracle Manipulation Trap: A Case Study in Assumptions
&lt;/h2&gt;

&lt;p&gt;What happens when you ask "what's the price of this asset" after you receive a flash loan but before you repay it? (hint: you're about to get wrecked)&lt;/p&gt;

&lt;p&gt;Here's the vulnerable pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ❌ DO NOT DO THIS
contract VulnerableLiquidator is IFlashLoanReceiver {
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external override returns (bytes32) {
        // Receive flash loan of WETH
        // Check price on Uniswap V2
        uint256 ethPrice = getUniswapV2Price(WETH, USDC);

        // Problem: attacker could have manipulated Uniswap V2 in the same tx
        // Flash loan is fungible—they could have flash loaned the same assets
        // and created artificial price movement before your callback even runs

        // Liquidate a borrower based on this price
        liquidateBorrower(ethPrice);

        // Repay loan
        IERC20(asset).approve(address(lender), amount + premium);
        // ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Euler Finance got destroyed exactly this way. An attacker flash loaned tokens, used those tokens to tank the price of another asset on Euler's internal oracle, triggered liquidations of healthy accounts, and walked off with millions—all one atomic transaction.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The fix is boring and unsexy but it actually works: use Chainlink or other battle-hardened external price feeds that can't be manipulated mid-transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ CORRECT: Use an oracle that doesn't suck
contract SafeLiquidator is IFlashLoanReceiver {
    IChainlinkOracle public oracle;

    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external override returns (bytes32) {
        // Chainlink prices are tamper-resistant because they:
        // 1) Update only between transactions (not mid-block)
        // 2) Derive from multiple independent sources
        // 3) Include time-delay mechanisms

        uint256 ethPrice = oracle.latestAnswer(WETH);

        // Liquidation proceeds with confidence
        liquidateBorrower(ethPrice);

        // Repay
        uint256 amountOwed = amount + premium;
        IERC20(asset).approve(address(lender), amountOwed);

        return keccak256("ERC3156FlashBorrower.onFlashLoan");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reentrancy: The Thing Everyone Forgets About
&lt;/h2&gt;

&lt;p&gt;Flash loans stack badly with reentrancy attacks because callbacks execute mid-transaction. Curve's withdrawal vulnerability happened because flash loans could manipulate liquidity and re-enter the withdrawal function before state got updated.&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Use checks-effects-interactions. Update your internal state before you make external calls. Don't even trust Aave with this rule.&lt;/p&gt;




&lt;p&gt;Flash loans were legitimately cool—they democratized liquidations and arbitrage for anyone without a seven-figure balance. But they also exposed something uncomfortable: developers were treating "happened in the same block" as "happened safely." The $25M+ in attacks we've tracked down were mostly just people ignoring basic transaction-level constraints.&lt;/p&gt;

&lt;p&gt;Are they dangerous? Yeah. The danger's not in Aave's code though (which is locked down tight). It's in developers who think atomic transactions are magic and that their price oracle is somehow exempt from being manipulated.&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;bZx attack (February 2020): &lt;a href="https://peckshield.medium.com/bzx-hack-full-post-mortem-with-detailed-fund-flow-and-exchange-timestamps-e563bf2b23f0" rel="noopener noreferrer"&gt;https://peckshield.medium.com/bzx-hack-full-post-mortem-with-detailed-fund-flow-and-exchange-timestamps-e563bf2b23f0&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Euler Finance flash loan component of $196M exploit (March 2023): &lt;a href="https://www.euler.finance/blog/euler-incident-report" rel="noopener noreferrer"&gt;https://www.euler.finance/blog/euler-incident-report&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;EVM enforces this at the opcode level; &lt;code&gt;REVERT&lt;/code&gt; throws away all state changes back to the transaction entry point. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Flash loans enabled the "$1.3 billion in liquidations without capital" narrative in 2021-2022, though this metric is misleading since you still need enough collateral to cover the 0.05% fee. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Euler's oracle multiplier tracked internal borrow/supply ratios, which attackers could artificially move via flash loans. See audit post-mortem. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;Curve's August 2023 vulnerability involved a vyper compiler bug, but flash loans were a component of attack vectors in subsequent copycat exploits. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>blockchain</category>
      <category>solidity</category>
      <category>ethereum</category>
      <category>defi</category>
    </item>
  </channel>
</rss>
